include/oox/export/drawingml.hxx         |    2 
 oox/qa/unit/data/tdf142605_CurveSize.odp |binary
 oox/qa/unit/drawingml.cxx                |   23 +++++++
 oox/source/export/drawingml.cxx          |   93 +++++++++++++++++++++++++++++++
 oox/source/export/shapes.cxx             |    4 -
 5 files changed, 120 insertions(+), 2 deletions(-)

New commits:
commit 925fa608d65a5970f966d45e33cccf04e2318060
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Thu Aug 12 19:19:19 2021 +0200
Commit:     Regina Henschel <rb.hensc...@t-online.de>
CommitDate: Sat Aug 14 17:15:28 2021 +0200

    tdf#142605 use frame size in oox export of BezierCurve
    
    The export had used the bound rectangle of PolyPolygonBezier. But that
    contains control points. Use API position and size instead.
    
    I have not incorporated the changes into existing WritePolyPolygon,
    but have made an own version for SdrPathObj, because I find it easier
    to read and maintain, than having a lot of case distinctions depending
    on the shape type.
    
    Change-Id: I2e646c4f5fa37174c4979855212ca72f2dfa447e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120407
    Tested-by: Jenkins
    Reviewed-by: Regina Henschel <rb.hensc...@t-online.de>

diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 77ff77174cc9..4af628a289f9 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -314,6 +314,8 @@ public:
         const SdrObjCustomShape& rSdrObjCustomShape);
     void WritePolyPolygon(const css::uno::Reference<css::drawing::XShape>& 
rXShape,
                           const tools::PolyPolygon& rPolyPolygon, const bool 
bClosed);
+    void WritePolyPolygon(const css::uno::Reference<css::drawing::XShape>& 
rXShape,
+                          const bool bClosed);
     void WriteFill( const css::uno::Reference< css::beans::XPropertySet >& 
xPropSet );
     void WriteShapeStyle( const css::uno::Reference< css::beans::XPropertySet 
>& rXPropSet );
     void WriteShapeEffects( const css::uno::Reference< 
css::beans::XPropertySet >& rXPropSet );
diff --git a/oox/qa/unit/data/tdf142605_CurveSize.odp 
b/oox/qa/unit/data/tdf142605_CurveSize.odp
new file mode 100644
index 000000000000..c797d378f1f3
Binary files /dev/null and b/oox/qa/unit/data/tdf142605_CurveSize.odp differ
diff --git a/oox/qa/unit/drawingml.cxx b/oox/qa/unit/drawingml.cxx
index c8dc0d9cc1fb..c7ba5ac61730 100644
--- a/oox/qa/unit/drawingml.cxx
+++ b/oox/qa/unit/drawingml.cxx
@@ -11,6 +11,7 @@
 #include <unotest/macros_test.hxx>
 
 #include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/container/XNamed.hpp>
 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
@@ -345,6 +346,28 @@ CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, 
testGroupShapeSmartArt)
     CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(0), xSmartArt->getCount());
 }
 
+CPPUNIT_TEST_FIXTURE(OoxDrawingmlTest, testTdf142605_CurveSize)
+{
+    // The document contains a Bezier curve, where the control points are 
outside the bounding
+    // rectangle of the shape. Error was, that the export uses a path size 
which included the
+    // control points.
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf142605_CurveSize.odp";
+    loadAndReload(aURL, "Impress Office Open XML");
+
+    uno::Reference<drawing::XDrawPagesSupplier> 
xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+    uno::Reference<drawing::XDrawPage> 
xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
+                                                 uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> 
xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+    css::awt::Rectangle aBoundRect;
+    xShapeProps->getPropertyValue("BoundRect") >>= aBoundRect;
+    // Without fix, size was 6262 x 3509, and position was 10037|6790.
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(8601), aBoundRect.Width, 1);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(4601), aBoundRect.Height, 1);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(7699), aBoundRect.X, 1);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(5699), aBoundRect.Y, 1);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index e45c5c52e8c5..91f4a779a984 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -3877,6 +3877,7 @@ sal_Int32 DrawingML::GetCustomGeometryPointValue(
     return nValue;
 }
 
+// version for SdrObjCustomShape
 void DrawingML::WritePolyPolygon(const 
css::uno::Reference<css::drawing::XShape>& rXShape,
                                  const tools::PolyPolygon& rPolyPolygon, const 
bool bClosed)
 {
@@ -3963,6 +3964,98 @@ void DrawingML::WritePolyPolygon(const 
css::uno::Reference<css::drawing::XShape>
     mpFS->endElementNS( XML_a, XML_custGeom );
 }
 
+// version for SdrPathObj
+void DrawingML::WritePolyPolygon(const 
css::uno::Reference<css::drawing::XShape>& rXShape,
+                                 const bool bClosed)
+{
+    tools::PolyPolygon aPolyPolygon = 
EscherPropertyContainer::GetPolyPolygon(rXShape);
+    // In case of Writer, the parent element is <wps:spPr>, and there the
+    // <a:custGeom> element is not optional.
+    if (aPolyPolygon.Count() < 1 && GetDocumentType() != DOCUMENT_DOCX)
+        return;
+
+    mpFS->startElementNS(XML_a, XML_custGeom);
+    mpFS->singleElementNS(XML_a, XML_avLst);
+    mpFS->singleElementNS(XML_a, XML_gdLst);
+    mpFS->singleElementNS(XML_a, XML_ahLst);
+    mpFS->singleElementNS(XML_a, XML_rect, XML_l, "0", XML_t, "0", XML_r, "r", 
XML_b, "b");
+
+    mpFS->startElementNS(XML_a, XML_pathLst);
+
+    awt::Size aSize = rXShape->getSize();
+    awt::Point aPos = rXShape->getPosition();
+    Reference<XPropertySet> xPropertySet(rXShape, UNO_QUERY);
+    uno::Reference<XPropertySetInfo> xPropertySetInfo = 
xPropertySet->getPropertySetInfo();
+    if (xPropertySetInfo->hasPropertyByName("AnchorPosition"))
+    {
+        awt::Point aAnchorPosition;
+        xPropertySet->getPropertyValue("AnchorPosition") >>= aAnchorPosition;
+        aPos.X += aAnchorPosition.X;
+        aPos.Y += aAnchorPosition.Y;
+    }
+
+    // Only closed SdrPathObj can be filled
+    std::optional<OString> sFill;
+    if (!bClosed)
+        sFill = "none"; // for possible values see ST_PathFillMode in OOXML 
standard
+
+    // Put all polygons of rPolyPolygon in the same path element
+    // to subtract the overlapped areas.
+    mpFS->startElementNS(XML_a, XML_path, XML_fill, sFill, XML_w, 
OString::number(aSize.Width),
+                         XML_h, OString::number(aSize.Height));
+
+    for (sal_uInt16 i = 0; i < aPolyPolygon.Count(); i++)
+    {
+        const tools::Polygon& aPoly = aPolyPolygon[i];
+
+        if (aPoly.GetSize() > 0)
+        {
+            mpFS->startElementNS(XML_a, XML_moveTo);
+
+            mpFS->singleElementNS(XML_a, XML_pt, XML_x, 
OString::number(aPoly[0].X() - aPos.X),
+                                  XML_y, OString::number(aPoly[0].Y() - 
aPos.Y));
+
+            mpFS->endElementNS(XML_a, XML_moveTo);
+        }
+
+        for (sal_uInt16 j = 1; j < aPoly.GetSize(); j++)
+        {
+            PolyFlags flags = aPoly.GetFlags(j);
+            if (flags == PolyFlags::Control)
+            {
+                // a:cubicBezTo can only contain 3 a:pt elements, so we need 
to make sure of this
+                if (j + 2 < aPoly.GetSize() && aPoly.GetFlags(j + 1) == 
PolyFlags::Control
+                    && aPoly.GetFlags(j + 2) != PolyFlags::Control)
+                {
+                    mpFS->startElementNS(XML_a, XML_cubicBezTo);
+                    for (sal_uInt8 k = 0; k <= 2; ++k)
+                    {
+                        mpFS->singleElementNS(XML_a, XML_pt, XML_x,
+                                              OString::number(aPoly[j + k].X() 
- aPos.X), XML_y,
+                                              OString::number(aPoly[j + k].Y() 
- aPos.Y));
+                    }
+                    mpFS->endElementNS(XML_a, XML_cubicBezTo);
+                    j += 2;
+                }
+            }
+            else if (flags == PolyFlags::Normal)
+            {
+                mpFS->startElementNS(XML_a, XML_lnTo);
+                mpFS->singleElementNS(XML_a, XML_pt, XML_x, 
OString::number(aPoly[j].X() - aPos.X),
+                                      XML_y, OString::number(aPoly[j].Y() - 
aPos.Y));
+                mpFS->endElementNS(XML_a, XML_lnTo);
+            }
+        }
+    }
+    if (bClosed)
+        mpFS->singleElementNS(XML_a, XML_close);
+    mpFS->endElementNS(XML_a, XML_path);
+
+    mpFS->endElementNS(XML_a, XML_pathLst);
+
+    mpFS->endElementNS(XML_a, XML_custGeom);
+}
+
 void DrawingML::WriteConnectorConnections( EscherConnectorListEntry& 
rConnectorEntry, sal_Int32 nStartID, sal_Int32 nEndID )
 {
     if( nStartID != -1 )
diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx
index d47acf217ac2..325387f4991d 100644
--- a/oox/source/export/shapes.cxx
+++ b/oox/source/export/shapes.cxx
@@ -400,7 +400,6 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const 
Reference< XShape >& xSha
     FSHelperPtr pFS = GetFS();
     pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? 
XML_sp : XML_wsp));
 
-    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())
@@ -413,6 +412,7 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const 
Reference< XShape >& xSha
     tools::Rectangle aRect(Point(aPos.X, aPos.Y), Size(aSize.Width, 
aSize.Height));
 
 #if OSL_DEBUG_LEVEL > 0
+    tools::PolyPolygon aPolyPolygon = 
EscherPropertyContainer::GetPolyPolygon(xShape);
     awt::Size size = MapSize( awt::Size( aRect.GetWidth(), aRect.GetHeight() ) 
);
     SAL_INFO("oox.shape", "poly count " << aPolyPolygon.Count());
     SAL_INFO("oox.shape", "size: " << size.Width << " x " << size.Height);
@@ -436,7 +436,7 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const 
Reference< XShape >& xSha
     // visual shape properties
     pFS->startElementNS(mnXmlNamespace, XML_spPr);
     WriteTransformation( xShape, aRect, XML_a );
-    WritePolyPolygon(xShape, aPolyPolygon, bClosed);
+    WritePolyPolygon(xShape, bClosed);
     Reference< XPropertySet > xProps( xShape, UNO_QUERY );
     if( xProps.is() ) {
         if( bClosed )

Reply via email to