oox/qa/unit/data/FaultyPathStart.odp |binary
 oox/qa/unit/export.cxx               |   20 ++++++++++++++++++++
 oox/source/export/drawingml.cxx      |   25 +++++++++++++++++++------
 3 files changed, 39 insertions(+), 6 deletions(-)

New commits:
commit 3d7466b92a450d7ca4f45fef9a664143fbb3c386
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Sat Apr 23 21:52:29 2022 +0200
Commit:     Regina Henschel <rb.hensc...@t-online.de>
CommitDate: Sun Apr 24 13:37:54 2022 +0200

    Do not start a:path with lnTo in export to OOXML
    
    This is a follow up to commit 2029b2f6dd0109c5892e5ac5640022b31fe42fd2
    
    The commands A, W, T or L of a draw:enhanced-path draw a line from
    current point to start of the arc or end of line, respectivly. If
    there is no current point the path is faulty and behavior is not
    defined in ODF.
    
    LibreOffice is tolerant and makes a move to the start point of the
    arc or to the end point of the line. With this patch we do the same
    now in export to OOXML, so the user gets the same shape geometry as in
    LO. If a path starts with lnTo, MS Office will show nothing.
    
    I wouldn't care about user-created faulty paths, but LO produces such
    faulty path when an EllipseRibbon shape from binary MS Office is
    imported. Even when that will be fixed, we need the fix here, because
    the faulty path had been written to document markup and will be used
    when such document is opened.
    
    Change-Id: Ic52ec3bc78231b26efb592ddadee2e3042fdc065
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133349
    Tested-by: Jenkins
    Reviewed-by: Regina Henschel <rb.hensc...@t-online.de>

diff --git a/oox/qa/unit/data/FaultyPathStart.odp 
b/oox/qa/unit/data/FaultyPathStart.odp
new file mode 100644
index 000000000000..219795ffa58b
Binary files /dev/null and b/oox/qa/unit/data/FaultyPathStart.odp differ
diff --git a/oox/qa/unit/export.cxx b/oox/qa/unit/export.cxx
index b4eebc537250..7a1bda7cb5bd 100644
--- a/oox/qa/unit/export.cxx
+++ b/oox/qa/unit/export.cxx
@@ -632,6 +632,26 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf109169_OctagonBevel)
     assertXPath(pXmlDoc, "//a:pathLst/a:path[5]", "fill", "lightenLess");
     assertXPath(pXmlDoc, "//a:pathLst/a:path[6]", "fill", "lighten");
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFaultyPathCommandsAWT)
+{
+    // The odp file contains shapes whose path starts with command A, W, T or 
L. That is a faulty
+    // path. LO is tolerant and renders it so that is makes a moveTo to the 
start point of the arc or
+    // the end of the line respectively. Export to OOXML does the same now and 
writes a moveTo
+    // instead of the normally used lnTo. If a lnTo is written, MS Office 
shows nothing of the shape.
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"FaultyPathStart.odp";
+
+    loadAndSave(aURL, "Impress Office Open XML");
+
+    // Verify the markup:
+    std::unique_ptr<SvStream> pStream = parseExportStream(getTempFile(), 
"ppt/slides/slide1.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    // First child of a:path should be a moveTo in all four shapes.
+    assertXPath(pXmlDoc, 
"//p:spTree/p:sp[1]/p:spPr/a:custGeom/a:pathLst/a:path/a:moveTo");
+    assertXPath(pXmlDoc, 
"//p:spTree/p:sp[2]/p:spPr/a:custGeom/a:pathLst/a:path/a:moveTo");
+    assertXPath(pXmlDoc, 
"//p:spTree/p:sp[3]/p:spPr/a:custGeom/a:pathLst/a:path/a:moveTo");
+    assertXPath(pXmlDoc, 
"//p:spTree/p:sp[4]/p:spPr/a:custGeom/a:pathLst/a:path/a:moveTo");
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 327b567c4c40..78eac3d00f60 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -4218,10 +4218,21 @@ bool DrawingML::WriteCustomGeometrySegment(
         {
             if (rnPairIndex >= rPairs.getLength())
                 return false;
-
-            mpFS->startElementNS(XML_a, XML_lnTo);
-            WriteCustomGeometryPoint(rPairs[rnPairIndex], rCustomShape2d);
-            mpFS->endElementNS(XML_a, XML_lnTo);
+            // LINETO without valid current point is a faulty path. LO is 
tolerant and makes a
+            // moveTo instead. Do the same on export. MS OFFICE requires a 
current point for lnTo,
+            // otherwise it shows nothing of the shape.
+            if (rbCurrentValid)
+            {
+                mpFS->startElementNS(XML_a, XML_lnTo);
+                WriteCustomGeometryPoint(rPairs[rnPairIndex], rCustomShape2d);
+                mpFS->endElementNS(XML_a, XML_lnTo);
+            }
+            else
+            {
+                mpFS->startElementNS(XML_a, XML_moveTo);
+                WriteCustomGeometryPoint(rPairs[rnPairIndex], rCustomShape2d);
+                mpFS->endElementNS(XML_a, XML_moveTo);
+            }
             rCustomShape2d.GetParameter(rfCurrentX, rPairs[rnPairIndex].First, 
false, false);
             rCustomShape2d.GetParameter(rfCurrentY, 
rPairs[rnPairIndex].Second, false, false);
             rbCurrentValid = true;
@@ -4284,7 +4295,8 @@ bool DrawingML::WriteCustomGeometrySegment(
             getEllipsePointFromViewAngle(fSx, fSy, fWR, fHR, fCx, fCy, 
fStartAngle);
 
             // write markup for going to start point
-            if (eCommand == ANGLEELLIPSETO)
+            // lnTo requires a valid current point
+            if (eCommand == ANGLEELLIPSETO && rbCurrentValid)
             {
                 mpFS->startElementNS(XML_a, XML_lnTo);
                 mpFS->singleElementNS(XML_a, XML_pt, XML_x, 
OString::number(std::lround(fSx)),
@@ -4347,7 +4359,8 @@ bool DrawingML::WriteCustomGeometrySegment(
             getEllipsePointAndAngleFromRayPoint(fStartAngle, fPx, fPy, fWR, 
fHR, fCx, fCy, fX3,
                                                 fY3);
             // markup for going to start point
-            if (eCommand == ARCTO || eCommand == CLOCKWISEARCTO)
+            // lnTo requires a valid current point.
+            if ((eCommand == ARCTO || eCommand == CLOCKWISEARCTO) && 
rbCurrentValid)
             {
                 mpFS->startElementNS(XML_a, XML_lnTo);
                 mpFS->singleElementNS(XML_a, XML_pt, XML_x, 
OString::number(std::lround(fPx)),

Reply via email to