oox/qa/unit/data/tdf141786_PolylineConnectorInGroup.odt |binary
 oox/qa/unit/data/tdf141786_RotatedShapeInGroup.odt      |binary
 oox/qa/unit/export.cxx                                  |   55 ++++++++++++++++
 oox/source/export/drawingml.cxx                         |   14 ++++
 oox/source/export/shapes.cxx                            |   17 ++++
 sw/qa/extras/ooxmlexport/ooxmlexport6.cxx               |   13 +--
 6 files changed, 91 insertions(+), 8 deletions(-)

New commits:
commit b33634a5c07c8f7032967d8e939100a50e0152ae
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Sun Jul 11 15:31:58 2021 +0200
Commit:     Regina Henschel <rb.hensc...@t-online.de>
CommitDate: Tue Jul 13 10:56:31 2021 +0200

    tdf#141786 correct position of child elements in group
    
    ...in export to docx.
    
    Rotated child elements need a correction to the position values,
    because LO uses left/top of snap rectangle as position, but Word uses
    left/top of unrotated shape. For the group itself it is done in
    DocxSdrExport::startDMLAnchorInline. But child elements' position
    is exported in DrawingML::WriteShapeTransformation. And there this
    correction was missing.
    
    Position is relative to anchor in Writer and relative to group in
    Word. The adaption is contained in WriteShapeTransformation. But
    PolyPolygon and Connector have no explicit rotation and therefore they
    do not use DrawingML::WriteShapeTransformation but call directly
    DrawingML::WriteTransformation. So they missed this adaption. I have
    added the adapation directly to these shapes.
    
    Unittest testDmlTextshapeB in sw-ooxmlexport6: I have adapted the
    values. The position of the connectors relative to the group is better
    now. You see this, if you compare it with a screenshot of the original
    file in Word. The handles of the connectors are still wrong and the
    whole group is still shifted.
    
    The patch does not fix the wrong position of rotated legacy ovals,
    because that error exists independent of groups.
    
    Change-Id: Iaf843dcf04bac596427dd35ccfa6cd20e3a4cdc8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118748
    Tested-by: Jenkins
    Reviewed-by: Regina Henschel <rb.hensc...@t-online.de>

diff --git a/oox/qa/unit/data/tdf141786_PolylineConnectorInGroup.odt 
b/oox/qa/unit/data/tdf141786_PolylineConnectorInGroup.odt
new file mode 100644
index 000000000000..d40dccac8c5e
Binary files /dev/null and 
b/oox/qa/unit/data/tdf141786_PolylineConnectorInGroup.odt differ
diff --git a/oox/qa/unit/data/tdf141786_RotatedShapeInGroup.odt 
b/oox/qa/unit/data/tdf141786_RotatedShapeInGroup.odt
new file mode 100644
index 000000000000..e932cf47b8dc
Binary files /dev/null and b/oox/qa/unit/data/tdf141786_RotatedShapeInGroup.odt 
differ
diff --git a/oox/qa/unit/export.cxx b/oox/qa/unit/export.cxx
index 20ae35c6b727..0e597adb2854 100644
--- a/oox/qa/unit/export.cxx
+++ b/oox/qa/unit/export.cxx
@@ -77,6 +77,61 @@ void Test::loadAndSave(const OUString& rURL, const OUString& 
rFilterName)
 
 constexpr OUStringLiteral DATA_DIRECTORY = u"/oox/qa/unit/data/";
 
+CPPUNIT_TEST_FIXTURE(Test, testPolylineConnectorPosition)
+{
+    // Given a document with a group shape and therein a polyline and a 
connector.
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf141786_PolylineConnectorInGroup.odt";
+    // When saving that to DOCX:
+    loadAndSave(aURL, "Office Open XML Text");
+
+    // Then make sure polyline and connector have the correct position.
+    uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+        = packages::zip::ZipFileAccess::createWithURL(mxComponentContext, 
getTempFile().GetURL());
+    uno::Reference<io::XInputStream> 
xInputStream(xNameAccess->getByName("word/document.xml"),
+                                                  uno::UNO_QUERY);
+    std::unique_ptr<SvStream> 
pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+
+    // For child elements of groups in Writer the position has to be adapted 
to be relative
+    // to group instead of being relative to anchor. That was missing for 
polyline and
+    // connector.
+    // Polyline: Without fix it would have failed with expected: 0, actual: 
1800360
+    assertXPath(pXmlDoc, "//wpg:wgp/wps:wsp[1]/wps:spPr/a:xfrm/a:off", "x", 
"0");
+    // ... failed with expected: 509400, actual: 1229400
+    assertXPath(pXmlDoc, "//wpg:wgp/wps:wsp[1]/wps:spPr/a:xfrm/a:off", "y", 
"509400");
+
+    // Connector: Without fix it would have failed with expected: 763200, 
actual: 2563560
+    assertXPath(pXmlDoc, "//wpg:wgp/wps:wsp[3]/wps:spPr/a:xfrm/a:off", "x", 
"763200");
+    // ... failed with expected: 0, actual: 720000
+    assertXPath(pXmlDoc, "//wpg:wgp/wps:wsp[3]/wps:spPr/a:xfrm/a:off", "y", 
"0");
+    // Polyline and connector were shifted 1800360EMU right, 720000EMU down.
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testRotatedShapePosition)
+{
+    // Given a document with a group shape and therein a rotated custom shape.
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf141786_RotatedShapeInGroup.odt";
+    // When saving that to DOCX:
+    loadAndSave(aURL, "Office Open XML Text");
+
+    // Then make sure the rotated child shape has the correct position.
+    uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+        = packages::zip::ZipFileAccess::createWithURL(mxComponentContext, 
getTempFile().GetURL());
+    uno::Reference<io::XInputStream> 
xInputStream(xNameAccess->getByName("word/document.xml"),
+                                                  uno::UNO_QUERY);
+    std::unique_ptr<SvStream> 
pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+
+    // For a group itself and for shapes outside of groups, the position 
calculation is done in
+    // DocxSdrExport. For child elements of groups it has to be done in
+    // DrawingML::WriteShapeTransformation(), but was missing.
+    // Without fix it would have failed with expected: 469440, actual: 92160
+    // The shape was about 1cm shifted up and partly outside its group.
+    assertXPath(pXmlDoc, "//wpg:wgp/wps:wsp[1]/wps:spPr/a:xfrm/a:off", "y", 
"469440");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testDmlGroupshapePolygon)
 {
     // Given a document with a group shape, containing a single polygon child 
shape:
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 140445a5ee0f..cc823858e337 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -39,6 +39,8 @@
 #include <tools/diagnose_ex.h>
 #include <comphelper/processfactory.hxx>
 #include <i18nlangtag/languagetag.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/range/b2drange.hxx>
 
 #include <numeric>
 #include <string_view>
@@ -104,6 +106,7 @@
 #include <comphelper/xmltools.hxx>
 #include <o3tl/any.hxx>
 #include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
 #include <tools/stream.hxx>
 #include <unotools/fontdefs.hxx>
 #include <vcl/cvtgrf.hxx>
@@ -1801,6 +1804,17 @@ void DrawingML::WriteShapeTransformation( const 
Reference< XShape >& rXShape, sa
             
aPos.X-=(1-faccos*cos(nRotation.get()*F_PI18000))*aSize.Width/2-facsin*sin(nRotation.get()*F_PI18000)*aSize.Height/2;
             
aPos.Y-=(1-faccos*cos(nRotation.get()*F_PI18000))*aSize.Height/2+facsin*sin(nRotation.get()*F_PI18000)*aSize.Width/2;
         }
+        else  if (m_xParent.is() && nRotation != 0_deg100)
+        {
+            // Position for rotated shapes inside group is not set by 
DocxSdrExport.
+            basegfx::B2DRange aRect(-aSize.Width / 2.0, -aSize.Height / 2.0, 
aSize.Width / 2.0,
+                                    aSize.Height / 2.0);
+            basegfx::B2DHomMatrix aRotateMatrix =
+                basegfx::utils::createRotateB2DHomMatrix(toRadians(nRotation));
+            aRect.transform(aRotateMatrix);
+            aPos.X += -aSize.Width / 2.0 - aRect.getMinX();
+            aPos.Y += -aSize.Height / 2.0 - aRect.getMinY();
+        }
 
         // The RotateAngle property's value is independent from any flipping, 
and that's exactly what we need here.
         uno::Reference<beans::XPropertySet> xPropertySet(rXShape, 
uno::UNO_QUERY);
diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx
index 795c864bc600..d47acf217ac2 100644
--- a/oox/source/export/shapes.cxx
+++ b/oox/source/export/shapes.cxx
@@ -402,6 +402,13 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const 
Reference< XShape >& xSha
 
     tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon( 
xShape );
     awt::Point aPos = xShape->getPosition();
+    // Position is relative to group for child elements in Word, but absolute 
in API.
+    if (GetDocumentType() == DOCUMENT_DOCX && m_xParent.is())
+    {
+        awt::Point aParentPos = m_xParent->getPosition();
+        aPos.X -= aParentPos.X;
+        aPos.Y -= aParentPos.Y;
+    }
     awt::Size aSize = xShape->getSize();
     tools::Rectangle aRect(Point(aPos.X, aPos.Y), Size(aSize.Width, 
aSize.Height));
 
@@ -1326,8 +1333,16 @@ ShapeExport& ShapeExport::WriteConnectorShape( const 
Reference< XShape >& xShape
         GET( rXShapeA, EdgeStartConnection );
         GET( rXShapeB, EdgeEndConnection );
     }
+    // Position is relative to group in Word, but relative to anchor of group 
in API.
+    if (GetDocumentType() == DOCUMENT_DOCX && m_xParent.is())
+    {
+        awt::Point aParentPos = m_xParent->getPosition();
+        aStartPoint.X -= aParentPos.X;
+        aStartPoint.Y -= aParentPos.Y;
+        aEndPoint.X -= aParentPos.X;
+        aEndPoint.Y -= aParentPos.Y;
+    }
     EscherConnectorListEntry aConnectorEntry( xShape, aStartPoint, rXShapeA, 
aEndPoint, rXShapeB );
-
     tools::Rectangle aRect( Point( aStartPoint.X, aStartPoint.Y ), Point( 
aEndPoint.X, aEndPoint.Y ) );
     if( aRect.getWidth() < 0 ) {
         bFlipH = true;
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
index 4e2f62b0dcbc..dc14b9540e81 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
@@ -124,16 +124,15 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testDmlTextshapeB, 
"dml-textshapeB.docx")
     uno::Reference<container::XIndexAccess> xGroup(getShape(1), 
uno::UNO_QUERY);
     uno::Reference<drawing::XShape> xShape(xGroup->getByIndex(3), 
uno::UNO_QUERY);
     // Connector was incorrectly shifted towards the top left corner, X was 
192, Y was -5743.
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(3776), xShape->getPosition().X);
-    // Values are as in LO7.2, the original problem is still fixed.
-    // FixMe: The shape is a VML group, not a DML. Export writes the connector 
shifted up, resulting
-    // in different routing. LO7.2 reads and writes the second connector 
wrongly. Whole group is
-    // still shifted.
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(-5061), xShape->getPosition().Y);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3896), xShape->getPosition().X);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-4775), xShape->getPosition().Y);
+    // Values are as in LO7.3, the original problem is still fixed.
+    // FixMe: The shape is a VML group, not a DML. Connector handles are still 
wrong and whole group
+    // is still shifted.
 
     xShape.set(xGroup->getByIndex(5), uno::UNO_QUERY);
     // This was incorrectly shifted towards the top of the page, Y was -5011.
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(-4710), xShape->getPosition().Y);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-4717), xShape->getPosition().Y);
 }
 
 DECLARE_OOXMLEXPORT_TEST(testDMLSolidfillAlpha, "dml-solidfill-alpha.docx")
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to