tdf#149913: add support for auto-start-reverse

See https://svgwg.org/svg2-draft/painting.html#OrientAttribute

Change-Id: Iedcca7bc79a54333c0f80927364caec82ce61167
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136894
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/svgio/inc/svgmarkernode.hxx b/svgio/inc/svgmarkernode.hxx
index 41c2d71..3f4b087 100644
--- a/svgio/inc/svgmarkernode.hxx
+++ b/svgio/inc/svgmarkernode.hxx
@@ -34,6 +34,13 @@ namespace svgio::svgreader
                userSpaceOnUse
            };

            enum class MarkerOrient
            {
                notset,
                auto_start,
                auto_start_reverse
            };

        private:
            /// buffered decomposition
            drawinglayer::primitive2d::Primitive2DContainer aPrimitives;
@@ -51,8 +58,7 @@ namespace svgio::svgreader
            SvgNumber               maMarkerWidth;
            SvgNumber               maMarkerHeight;
            double                  mfAngle;

            bool                    mbOrientAuto : 1; // true == on, false == fAngle valid
            MarkerOrient            maMarkerOrient;

        public:
            SvgMarkerNode(
@@ -94,10 +100,11 @@ namespace svgio::svgreader

            /// Angle content, set if found in current context
            double getAngle() const { return mfAngle; }
            void setAngle(double fAngle) { mfAngle = fAngle; mbOrientAuto = false; }
            void setAngle(double fAngle) { mfAngle = fAngle;}

            /// OrientAuto content, set if found in current context
            bool getOrientAuto() const { return mbOrientAuto; }
            /// MarkerOrient content
            MarkerOrient getMarkerOrient() const { return maMarkerOrient; }
            void setMarkerOrient(const MarkerOrient aMarkerOrient) { maMarkerOrient = aMarkerOrient; }

        };

diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx
index 060c184..1ce9b2e 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -44,6 +44,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools
    void testFontsizeKeywords();
    void testFontsizePercentage();
    void testFontsizeRelative();
    void testMarkerOrient();
    void testTdf45771();
    void testTdf97941();
    void testTdf104339();
@@ -83,6 +84,7 @@ public:
    CPPUNIT_TEST(testFontsizeKeywords);
    CPPUNIT_TEST(testFontsizePercentage);
    CPPUNIT_TEST(testFontsizeRelative);
    CPPUNIT_TEST(testMarkerOrient);
    CPPUNIT_TEST(testTdf45771);
    CPPUNIT_TEST(testTdf97941);
    CPPUNIT_TEST(testTdf104339);
@@ -310,6 +312,37 @@ void Test::testFontsizeRelative()
    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "familyname", "serif");
}

void Test::testMarkerOrient()
{
    Primitive2DSequence aSequence = parseSvg(u"/svgio/qa/cppunit/data/MarkerOrient.svg");
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));

    drawinglayer::Primitive2dXmlDump dumper;
    xmlDocUniquePtr pDocument = dumper.dumpAndParse(aSequence);

    CPPUNIT_ASSERT (pDocument);

    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy11", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy12", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy13", "7");
    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy21", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy22", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy23", "13");
    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy31", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy32", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[1]", "xy33", "1");

    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy11", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy12", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy13", "87");
    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy21", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy22", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy23", "87");
    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy31", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy32", "0");
    assertXPath(pDocument, "/primitive2D/transform/transform[2]", "xy33", "1");
}

void Test::testTdf45771()
{
    //Check text fontsize when using relative units
diff --git a/svgio/qa/cppunit/data/MarkerOrient.svg b/svgio/qa/cppunit/data/MarkerOrient.svg
new file mode 100644
index 0000000..7997e1c
--- /dev/null
+++ b/svgio/qa/cppunit/data/MarkerOrient.svg
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <!-- arrowhead marker definition -->
    <marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5"
        markerWidth="6" markerHeight="6"
        orient="auto-start-reverse">
      <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>

    <marker id="arrow2" viewBox="0 0 10 10" refX="5" refY="5"
        markerWidth="6" markerHeight="6"
        orient="auto-start-reverse">
      <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>

  </defs>

  <!-- Coordinate axes with a arrowhead in both direction -->
  <polyline points="10,10 10,90 90,90" fill="none" stroke="black"
   marker-start="url(#arrow)" marker-end="url(#arrow2)" />
</svg>
diff --git a/svgio/source/svgreader/svgmarkernode.cxx b/svgio/source/svgreader/svgmarkernode.cxx
index 0c2ea6a..21223c9 100644
--- a/svgio/source/svgreader/svgmarkernode.cxx
+++ b/svgio/source/svgreader/svgmarkernode.cxx
@@ -33,7 +33,7 @@ namespace svgio::svgreader
            maMarkerWidth(3),
            maMarkerHeight(3),
            mfAngle(0.0),
            mbOrientAuto(false)
            maMarkerOrient(MarkerOrient::notset)
        {
        }

@@ -146,7 +146,11 @@ namespace svgio::svgreader
                    {
                        if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"auto"))
                        {
                            mbOrientAuto = true;
                            setMarkerOrient(MarkerOrient::auto_start);
                        }
                        if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"auto-start-reverse"))
                        {
                            setMarkerOrient(MarkerOrient::auto_start_reverse);
                        }
                        else
                        {
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx
index 9e0e24b..70b0195 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -998,7 +998,8 @@ namespace svgio::svgreader
                        basegfx::B2DHomMatrix aCombinedTransform(aPreparedMarkerTransform);

                        // get rotation
                        if(pPrepared->getOrientAuto())
                        if(pPrepared->getMarkerOrient() == SvgMarkerNode::MarkerOrient::auto_start ||
                            pPrepared->getMarkerOrient() == SvgMarkerNode::MarkerOrient::auto_start_reverse)
                        {
                            const sal_uInt32 nPointIndex(b % nSubPolygonPointCount);

@@ -1027,12 +1028,18 @@ namespace svgio::svgreader

                                if(bEntering)
                                {
                                    aSum += aEntering.normalize();
                                    if(bIsFirstMarker && pPrepared->getMarkerOrient() == SvgMarkerNode::MarkerOrient::auto_start_reverse)
                                        aSum -= aEntering.normalize();
                                    else
                                        aSum += aEntering.normalize();
                                }

                                if(bLeaving)
                                {
                                    aSum += aLeaving.normalize();
                                    if(bIsFirstMarker && pPrepared->getMarkerOrient() == SvgMarkerNode::MarkerOrient::auto_start_reverse)
                                        aSum -= aLeaving.normalize();
                                    else
                                        aSum += aLeaving.normalize();
                                }

                                if(!aSum.equalZero())