[Libreoffice-commits] core.git: sd/qa svx/qa svx/source xmloff/source

Regina Henschel (via logerrit) logerrit at kemper.freedesktop.org
Wed Feb 26 11:04:48 UTC 2020


 sd/qa/unit/data/tdf98839_ShearVFlipH.odg   |binary
 sd/qa/unit/misc-tests.cxx                  |   31 ++++++++++++-
 svx/qa/unit/customshapes.cxx               |   40 +++++++++++++++++
 svx/qa/unit/data/tdf129532_MatrixFlipV.odg |binary
 svx/source/svdraw/svdoashp.cxx             |   65 ++++++++++++++++++++++------
 xmloff/source/draw/ximpshap.cxx            |   67 +++++++++++++++++------------
 6 files changed, 162 insertions(+), 41 deletions(-)

New commits:
commit b4a6977e05d87fe0a79b266ec30e4f403404f1b4
Author:     Regina Henschel <rb.henschel at t-online.de>
AuthorDate: Sat Dec 21 22:32:55 2019 +0100
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Wed Feb 26 12:04:11 2020 +0100

    tdf#129532 tdf#98839 fixes for mirror of custom shapes
    
    tdf#98839 In case a sheared custom shape was mirrored, the shear
    angle in draw:transform had a wrong sign in the saved file.
    tdf#129532 Mirroring given in draw:transform in file or via macro
    was wrongly applied. Errors:
    1)Mirroring from draw:transform attribute had overwritten already
    existing mirroring in the enhanced-geometry.
    2)Mirroring from draw:transform attribute was set in enhanced-
    geometry attributes but not really applied.
    
    Change-Id: Ifa52f3606b5a33e6492a02d6e19c883d28752da8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/85670
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/sd/qa/unit/data/tdf98839_ShearVFlipH.odg b/sd/qa/unit/data/tdf98839_ShearVFlipH.odg
new file mode 100644
index 000000000000..88763f8d3ccf
Binary files /dev/null and b/sd/qa/unit/data/tdf98839_ShearVFlipH.odg differ
diff --git a/sd/qa/unit/misc-tests.cxx b/sd/qa/unit/misc-tests.cxx
index 9bd6f8a64a55..852cdc03ece6 100644
--- a/sd/qa/unit/misc-tests.cxx
+++ b/sd/qa/unit/misc-tests.cxx
@@ -53,7 +53,8 @@
 #include <vcl/window.hxx>
 #include <vcl/event.hxx>
 #include <vcl/keycodes.hxx>
-
+#include <svx/svdoashp.hxx>
+#include <tools/gen.hxx>
 
 using namespace ::com::sun::star;
 
@@ -76,6 +77,7 @@ public:
     void testTdf67248();
     void testTdf119956();
     void testTdf120527();
+    void testTdf98839_ShearVFlipH();
 
     CPPUNIT_TEST_SUITE(SdMiscTest);
     CPPUNIT_TEST(testTdf96206);
@@ -93,6 +95,7 @@ public:
     CPPUNIT_TEST(testTdf67248);
     CPPUNIT_TEST(testTdf119956);
     CPPUNIT_TEST(testTdf120527);
+    CPPUNIT_TEST(testTdf98839_ShearVFlipH);
     CPPUNIT_TEST_SUITE_END();
 
 virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override
@@ -773,6 +776,32 @@ void SdMiscTest::testTdf119956()
     xDocShRef->DoClose();
 }
 
+void SdMiscTest::testTdf98839_ShearVFlipH()
+{
+    // Loads a document with a sheared shape and mirrors it
+    const OUString sURL = "sd/qa/unit/data/tdf98839_ShearVFlipH.odg";
+    sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc(sURL), ODG);
+    sd::GraphicViewShell* pViewShell = static_cast<sd::GraphicViewShell*>(xDocShRef->GetViewShell());
+    SdPage* pPage = pViewShell->GetActualPage();
+    SdrObjCustomShape* pShape = static_cast<SdrObjCustomShape*>(pPage->GetObj(0));
+    pShape->Mirror(Point(4000, 2000), Point(4000, 10000));
+
+    // Save and examine attribute draw:transform
+    utl::TempFile aTempFile;
+    aTempFile.EnableKillingFile();
+    save(xDocShRef.get(), getFormat(ODG), aTempFile);
+    xmlDocPtr pXmlDoc = parseExport(aTempFile, "content.xml");
+    CPPUNIT_ASSERT_MESSAGE("Failed to get 'content.xml'", pXmlDoc);
+    const OString sPathStart("/office:document-content/office:body/office:drawing/draw:page");
+    assertXPath(pXmlDoc, sPathStart);
+    const OUString sTransform = getXPath(pXmlDoc, sPathStart + "/draw:custom-shape","transform");
+
+    // Error was, that the shear angle had a wrong sign.
+    CPPUNIT_ASSERT_MESSAGE("expected: draw:transform='skewX (-0.64350...)", sTransform.startsWith("skewX (-"));
+
+    xDocShRef->DoClose();
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdMiscTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/svx/qa/unit/customshapes.cxx b/svx/qa/unit/customshapes.cxx
index 796fa4824809..a21652113ef8 100644
--- a/svx/qa/unit/customshapes.cxx
+++ b/svx/qa/unit/customshapes.cxx
@@ -631,6 +631,46 @@ CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf128413_tbrlOnOff)
     }
     CPPUNIT_ASSERT_EQUAL(OUString(), sError);
 }
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf129532_MatrixFlipV)
+{
+    // The document contains two rotated shapes with the same geometry. For one of them
+    // "matrix(1 0 0 -1 0cm 0cm)" was manually added to the value of the draw:transform
+    // attribute. That should result in mirroring on the x-axis. Error was, that the lines
+    // which are drawn on the shape rectangle were mirrored, but not the rectangle itself.
+    // The rectangle was only shifted.
+    const OUString sFileName("tdf129532_MatrixFlipV.odg");
+    OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName;
+    mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument");
+    CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is());
+    OUString sErrors; // sErrors collects the errors and should be empty in case all is OK.
+
+    uno::Reference<drawing::XShape> xShape0(getShape(0));
+    uno::Reference<beans::XPropertySet> xShape0Props(xShape0, uno::UNO_QUERY);
+    CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape0Props.is());
+    awt::Rectangle aBoundRect0;
+    xShape0Props->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect0;
+
+    uno::Reference<drawing::XShape> xShape1(getShape(1));
+    uno::Reference<beans::XPropertySet> xShape1Props(xShape1, uno::UNO_QUERY);
+    CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape1Props.is());
+    awt::Rectangle aBoundRect1;
+    xShape1Props->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect1;
+
+    // The size of the two BoundRect rectangles are the same in case of correct
+    // vertical mirroring.
+    if (aBoundRect0.Width != aBoundRect1.Width)
+    {
+        sErrors += "\n Width expected: " + OUString::number(aBoundRect1.Width)
+                   + " actual: " + OUString::number(aBoundRect0.Width);
+    }
+    if (aBoundRect0.Height != aBoundRect1.Height)
+    {
+        sErrors += "\n Height expected: " + OUString::number(aBoundRect1.Height)
+                   + " actual: " + OUString::number(aBoundRect0.Height);
+    }
+    CPPUNIT_ASSERT_EQUAL(OUString(), sErrors);
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/data/tdf129532_MatrixFlipV.odg b/svx/qa/unit/data/tdf129532_MatrixFlipV.odg
new file mode 100644
index 000000000000..eb0c10b3d417
Binary files /dev/null and b/svx/qa/unit/data/tdf129532_MatrixFlipV.odg differ
diff --git a/svx/source/svdraw/svdoashp.cxx b/svx/source/svdraw/svdoashp.cxx
index 367e6a3ac24f..2412213f2992 100644
--- a/svx/source/svdraw/svdoashp.cxx
+++ b/svx/source/svdraw/svdoashp.cxx
@@ -2987,21 +2987,29 @@ void SdrObjCustomShape::AdjustToMaxRect(const tools::Rectangle& rMaxRect, bool b
 
 void SdrObjCustomShape::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
 {
+    // The shape might have already flipping in its enhanced geometry. LibreOffice applies
+    // such after all transformations. We remove it, but remember it to apply them later.
+    bool bIsMirroredX = IsMirroredX();
+    bool bIsMirroredY = IsMirroredY();
+    if (bIsMirroredX || bIsMirroredY)
+    {
+        Point aCurrentCenter = GetSnapRect().Center();
+        if (bIsMirroredX) // mirror on the y-axis
+        {
+            Mirror(aCurrentCenter, Point(aCurrentCenter.X(), aCurrentCenter.Y() + 1000));
+        }
+        if (bIsMirroredY) // mirror on the x-axis
+        {
+            Mirror(aCurrentCenter, Point(aCurrentCenter.X() + 1000, aCurrentCenter.Y()));
+        }
+    }
+
     // break up matrix
     basegfx::B2DTuple aScale;
     basegfx::B2DTuple aTranslate;
     double fRotate, fShearX;
     rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
 
-    // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
-    // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
-    if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
-    {
-        aScale.setX(fabs(aScale.getX()));
-        aScale.setY(fabs(aScale.getY()));
-        fRotate = fmod(fRotate + F_PI, F_2PI);
-    }
-
     // reset object shear and rotations
     fObjectRotation = 0.0;
     aGeo.nRotationAngle = 0;
@@ -3018,14 +3026,19 @@ void SdrObjCustomShape::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix,
         }
     }
 
-    // build and set BaseRect (use scale)
-    Size aSize(FRound(aScale.getX()), FRound(aScale.getY()));
+    // scale
+    Size aSize(FRound(fabs(aScale.getX())), FRound(fabs(aScale.getY())));
     // fdo#47434 We need a valid rectangle here
     if( !aSize.Height() ) aSize.setHeight( 1 );
     if( !aSize.Width() ) aSize.setWidth( 1 );
-
     tools::Rectangle aBaseRect(Point(), aSize);
-    SetSnapRect(aBaseRect);
+    SetLogicRect(aBaseRect);
+
+    // Apply flipping from Matrix, which is a transformation relative to origin
+    if (basegfx::fTools::less(aScale.getX(), 0.0))
+        Mirror(Point(0, 0), Point(0, 1000)); // mirror on the y-axis
+    if (basegfx::fTools::less(aScale.getY(), 0.0))
+        Mirror(Point(0, 0), Point(1000, 0)); // mirror on the x-axis
 
     // shear?
     if(!basegfx::fTools::equalZero(fShearX))
@@ -3057,6 +3070,30 @@ void SdrObjCustomShape::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix,
     {
         Move(Size(FRound(aTranslate.getX()), FRound(aTranslate.getY())));
     }
+
+    // Apply flipping from enhanced geometry at center of the shape.
+    if (bIsMirroredX || bIsMirroredY)
+    {
+        // create mathematically matrix for the applied transformations
+        // aScale was in most cases built from a rectangle including edge
+        // and is therefore mathematically too large by 1
+        if (aScale.getX() > 2.0 && aScale.getY() > 2.0)
+            aScale -= basegfx::B2DTuple(1.0, 1.0);
+        basegfx::B2DHomMatrix aMathMat = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+                        aScale, -fShearX, basegfx::fTools::equalZero(fRotate) ? 0.0 : fRotate,
+                        aTranslate);
+        // Use matrix to get current center
+        basegfx::B2DPoint aCenter(0.5,0.5);
+        aCenter = aMathMat * aCenter;
+        double fCenterX = aCenter.getX();
+        double fCenterY = aCenter.getY();
+        if (bIsMirroredX) // vertical axis
+            Mirror(Point(FRound(fCenterX),FRound(fCenterY)),
+                Point(FRound(fCenterX), FRound(fCenterY + 1000.0)));
+        if (bIsMirroredY) // horizontal axis
+            Mirror(Point(FRound(fCenterX),FRound(fCenterY)),
+                Point(FRound(fCenterX + 1000.0), FRound(fCenterY)));
+    }
 }
 
 // taking fObjectRotation instead of aGeo.nAngle
@@ -3078,6 +3115,7 @@ bool SdrObjCustomShape::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegf
 
         if ( bMirroredX )
         {
+            fShearX = -fShearX;
             tools::Polygon aPol = Rect2Poly(maRect, aNewGeo);
             tools::Rectangle aBoundRect( aPol.GetBoundRect() );
 
@@ -3100,6 +3138,7 @@ bool SdrObjCustomShape::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegf
         }
         if ( bMirroredY )
         {
+            fShearX = -fShearX;
             tools::Polygon aPol( Rect2Poly( aRectangle, aNewGeo ) );
             tools::Rectangle aBoundRect( aPol.GetBoundRect() );
 
diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx
index 419c0174ae81..f0a8a169842a 100644
--- a/xmloff/source/draw/ximpshap.cxx
+++ b/xmloff/source/draw/ximpshap.cxx
@@ -3755,11 +3755,9 @@ void SdXMLCustomShapeContext::StartElement( const uno::Reference< xml::sax::XAtt
 
 void SdXMLCustomShapeContext::EndElement()
 {
-    // for backward compatibility, the above SetTransformation() may already have
-    // applied a call to SetMirroredX/SetMirroredY. This is not yet added to the
-    // beans::PropertyValues in maCustomShapeGeometry. When applying these now, this
-    // would be lost again.
-    // TTTT: Remove again after aw080
+    // Customshapes remember mirror state in its enhanced geometry.
+    // SetTransformation() in StartElement() may have applied mirroring, but that is not yet
+    // contained. Merge that information here before writing the property.
     if(!maUsedTransformation.isIdentity())
     {
         basegfx::B2DVector aScale, aTranslate;
@@ -3767,43 +3765,58 @@ void SdXMLCustomShapeContext::EndElement()
 
         maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
 
-        bool bFlippedX(aScale.getX() < 0.0);
-        bool bFlippedY(aScale.getY() < 0.0);
-
-        if(bFlippedX && bFlippedY)
+        if (aScale.getX() < 0.0)
         {
-            // when both are used it is the same as 180 degree rotation; reset
-            bFlippedX = bFlippedY = false;
+            const OUString sName("MirroredX");
+            //fdo#84043 Merge, if property exists, otherwise append it
+            auto aI = std::find_if(maCustomShapeGeometry.begin(), maCustomShapeGeometry.end(),
+                [&sName](beans::PropertyValue& rValue) { return rValue.Name == sName; });
+            if (aI != maCustomShapeGeometry.end())
+            {
+                beans::PropertyValue& rItem = *aI;
+                bool bMirroredX;
+                rItem.Value >>= bMirroredX;
+                rItem.Value <<= !bMirroredX;
+                rItem.Handle = -1;
+                rItem.State = beans::PropertyState_DIRECT_VALUE;
+            }
+            else
+            {
+                beans::PropertyValue* pItem;
+                maCustomShapeGeometry.emplace_back();
+                pItem = &maCustomShapeGeometry.back();
+                pItem->Name = sName;
+                pItem->Handle = -1;
+                pItem->Value <<= true;
+                pItem->State = beans::PropertyState_DIRECT_VALUE;
+            }
         }
 
-        if(bFlippedX || bFlippedY)
+        if (aScale.getY() < 0.0)
         {
-            OUString sName;
-
-            if(bFlippedX)
-                sName = "MirroredX";
-            else
-                sName = "MirroredY";
-
-            //fdo#84043 overwrite the property if it already exists, otherwise append it
-            beans::PropertyValue* pItem;
+            const OUString sName("MirroredY");
+            //fdo#84043 Merge, if property exists, otherwise append it
             auto aI = std::find_if(maCustomShapeGeometry.begin(), maCustomShapeGeometry.end(),
                 [&sName](beans::PropertyValue& rValue) { return rValue.Name == sName; });
             if (aI != maCustomShapeGeometry.end())
             {
                 beans::PropertyValue& rItem = *aI;
-                pItem = &rItem;
+                bool bMirroredY;
+                rItem.Value >>= bMirroredY;
+                rItem.Value <<= !bMirroredY;
+                rItem.Handle = -1;
+                rItem.State = beans::PropertyState_DIRECT_VALUE;
             }
             else
             {
+                beans::PropertyValue* pItem;
                 maCustomShapeGeometry.emplace_back();
                 pItem = &maCustomShapeGeometry.back();
+                pItem->Name = sName;
+                pItem->Handle = -1;
+                pItem->Value <<= true;
+                pItem->State = beans::PropertyState_DIRECT_VALUE;
             }
-
-            pItem->Name = sName;
-            pItem->Handle = -1;
-            pItem->Value <<= true;
-            pItem->State = beans::PropertyState_DIRECT_VALUE;
         }
     }
 


More information about the Libreoffice-commits mailing list