svgio/inc/svgsymbolnode.hxx              |   15 ++++
 svgio/qa/cppunit/SvgImportTest.cxx       |   15 ++++
 svgio/qa/cppunit/data/tdf158445.svg      |    5 +
 svgio/source/svgreader/svgsymbolnode.cxx |   94 ++++++++++++++++++++++++++++++-
 4 files changed, 128 insertions(+), 1 deletion(-)

New commits:
commit e7186b49a9a0b24ddc3b1c5384b5d9facb03518c
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Fri Jan 26 15:10:58 2024 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Fri Jan 26 19:31:03 2024 +0100

    tdf#158445: support viewBox in symbol elements
    
    Change-Id: Ie45b1e1dd4a4dcfc3cf3ce3d30f8dd9e040e37fb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162605
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/svgio/inc/svgsymbolnode.hxx b/svgio/inc/svgsymbolnode.hxx
index 7a19b335b7b5..e82f75a7671c 100644
--- a/svgio/inc/svgsymbolnode.hxx
+++ b/svgio/inc/svgsymbolnode.hxx
@@ -29,6 +29,12 @@ namespace svgio::svgreader
             /// use styles
             SvgStyleAttributes      maSvgStyleAttributes;
 
+            SvgNumber               maX;
+            SvgNumber               maY;
+            SvgNumber               maWidth;
+            SvgNumber               maHeight;
+
+            std::unique_ptr<basegfx::B2DRange> mpViewBox;
             SvgAspectRatio          maSvgAspectRatio;
 
         public:
@@ -39,6 +45,15 @@ namespace svgio::svgreader
 
             virtual const SvgStyleAttributes* getSvgStyleAttributes() const 
override;
             virtual void parseAttribute(SVGToken aSVGToken, const OUString& 
aContent) override;
+            virtual void 
decomposeSvgNode(drawinglayer::primitive2d::Primitive2DContainer& rTarget, bool 
bReferenced) const override;
+
+            /// viewBox content
+            const basegfx::B2DRange* getViewBox() const { return 
mpViewBox.get(); }
+            void setViewBox(const basegfx::B2DRange* pViewBox) { 
mpViewBox.reset(); if(pViewBox) mpViewBox.reset( new 
basegfx::B2DRange(*pViewBox) ); }
+
+            /// SvgAspectRatio content
+            const SvgAspectRatio& getSvgAspectRatio() const { return 
maSvgAspectRatio; }
+
         };
 
 } // end of namespace svgio::svgreader
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 1b0be44177fe..d99e56bfef35 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -1591,6 +1591,21 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf155733)
     assertXPath(pDocument, 
"/primitive2D/transform/transform/unifiedtransparence"_ostr, 
"transparence"_ostr, "50");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf158445)
+{
+    Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/tdf158445.svg");
+    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
+
+    drawinglayer::Primitive2dXmlDump dumper;
+    xmlDocUniquePtr pDocument = 
dumper.dumpAndParse(Primitive2DContainer(aSequence));
+
+    CPPUNIT_ASSERT (pDocument);
+
+    assertXPath(pDocument, 
"/primitive2D/transform/transform/transform/transform/polypolygoncolor"_ostr, 
"color"_ostr, "#000000");
+    assertXPath(pDocument, 
"/primitive2D/transform/transform/transform/transform/polypolygoncolor/polypolygon"_ostr,
 "height"_ostr, "8.052");
+    assertXPath(pDocument, 
"/primitive2D/transform/transform/transform/transform/polypolygoncolor/polypolygon"_ostr,
 "width"_ostr, "5.328");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf97663)
 {
     Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/em_units.svg");
diff --git a/svgio/qa/cppunit/data/tdf158445.svg 
b/svgio/qa/cppunit/data/tdf158445.svg
new file mode 100644
index 000000000000..20e084dd05e5
--- /dev/null
+++ b/svgio/qa/cppunit/data/tdf158445.svg
@@ -0,0 +1,5 @@
+<svg width="160.353" height="30.488" xmlns="http://www.w3.org/2000/svg"; 
viewBox="-0.376 -26.625 160.353 30.488">
+<symbol id="STIXTwoMathRegular_4275" width="5.868" height="51.216" viewBox="0 
-31.524 5.868 51.216">
+<path d="M 5.868 -2.088 L 5.868 -2.088 L 5.46 0 L 0.54 0 L 0.54 -0.588 L 2.244 
-2.316 Q 2.916 -2.988 3.354 -3.504 Q 3.792 -4.02 4.008 -4.542 Q 4.224 -5.064 
4.224 -5.736 Q 4.224 -6.372 3.834 -6.786 Q 3.444 -7.2 2.736 -7.2 Q 2.088 -7.2 
1.65 -6.942 Q 1.212 -6.684 0.876 -6.096 L 0.552 -6.252 Q 0.852 -7.092 1.482 
-7.572 Q 2.112 -8.052 3.036 -8.052 Q 3.756 -8.052 4.308 -7.794 Q 4.86 -7.536 
5.172 -7.056 Q 5.484 -6.576 5.484 -5.892 Q 5.484 -5.304 5.22 -4.788 Q 4.956 
-4.272 4.47 -3.732 Q 3.984 -3.192 3.312 -2.532 L 1.812 -1.08 L 1.812 -0.996 L 
2.748 -1.044 L 4.308 -1.044 Q 4.656 -1.044 4.842 -1.14 Q 5.028 -1.236 5.16 
-1.47 Q 5.292 -1.704 5.448 -2.088 Z " viewBox="0 -31.524 5.868 51.216"/>
+</symbol>
+<use href="#STIXTwoMathRegular_4275" transform="translate(151.174 -52.774) 
scale(1.4)" fill="black" /></svg>
diff --git a/svgio/source/svgreader/svgsymbolnode.cxx 
b/svgio/source/svgreader/svgsymbolnode.cxx
index 6e18d4bca049..f86dd27bb3a0 100644
--- a/svgio/source/svgreader/svgsymbolnode.cxx
+++ b/svgio/source/svgreader/svgsymbolnode.cxx
@@ -18,6 +18,8 @@
  */
 
 #include <svgsymbolnode.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
 
 namespace svgio::svgreader
 {
@@ -54,9 +56,60 @@ namespace svgio::svgreader
                     readLocalCssStyle(aContent);
                     break;
                 }
+                case SVGToken::X:
+                {
+                    SvgNumber aNum;
+
+                    if(readSingleNumber(aContent, aNum))
+                    {
+                        maX = aNum;
+                    }
+                    break;
+                }
+                case SVGToken::Y:
+                {
+                    SvgNumber aNum;
+
+                    if(readSingleNumber(aContent, aNum))
+                    {
+                        maY = aNum;
+                    }
+                    break;
+                }
+                case SVGToken::Width:
+                {
+                    SvgNumber aNum;
+
+                    if(readSingleNumber(aContent, aNum))
+                    {
+                        if(aNum.isPositive())
+                        {
+                            maWidth = aNum;
+                        }
+                    }
+                    break;
+                }
+                case SVGToken::Height:
+                {
+                    SvgNumber aNum;
+
+                    if(readSingleNumber(aContent, aNum))
+                    {
+                        if(aNum.isPositive())
+                        {
+                            maHeight = aNum;
+                        }
+                    }
+                    break;
+                }
                 case SVGToken::ViewBox:
                 {
-                    readViewBox(aContent, *this);
+                    const basegfx::B2DRange aRange(readViewBox(aContent, 
*this));
+
+                    if(!aRange.isEmpty())
+                    {
+                        setViewBox(&aRange);
+                    }
                     break;
                 }
                 case SVGToken::PreserveAspectRatio:
@@ -71,6 +124,45 @@ namespace svgio::svgreader
             }
         }
 
+        void 
SvgSymbolNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DContainer&
 rTarget, bool bReferenced) const
+        {
+            drawinglayer::primitive2d::Primitive2DContainer aNewTarget;
+
+            // decompose children
+            SvgNode::decomposeSvgNode(aNewTarget, bReferenced);
+
+            if(aNewTarget.empty())
+                return;
+
+            if(getViewBox())
+            {
+                // create mapping
+                // #i122610 SVG 1.1 defines in section 5.1.2 that if the 
attribute preserveAspectRatio is not specified,
+                // then the effect is as if a value of 'xMidYMid meet' were 
specified.
+                SvgAspectRatio aRatioDefault(SvgAlign::xMidYMid, true);
+                const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? 
getSvgAspectRatio() : aRatioDefault;
+
+                const double fX(maX.solve(*this, NumberType::xcoordinate));
+                const double fY(maY.solve(*this, NumberType::ycoordinate));
+                const double fWidth(maWidth.solve(*this, 
NumberType::xcoordinate));
+                const double fHeight(maHeight.solve(*this, 
NumberType::ycoordinate));
+                const basegfx::B2DRange aRange(fX, fY, fX + fWidth, fY + 
fHeight);
+
+                // let mapping be created from SvgAspectRatio
+                const basegfx::B2DHomMatrix aEmbeddingTransform(
+                    rRatio.createMapping(aRange, *getViewBox()));
+
+                // prepare embedding in transformation
+                // create embedding group element with transformation
+                const drawinglayer::primitive2d::Primitive2DReference xRef(
+                    new drawinglayer::primitive2d::TransformPrimitive2D(
+                        aEmbeddingTransform,
+                        std::move(aNewTarget)));
+
+                rTarget.push_back(xRef);
+            }
+        }
+
 } // end of namespace svgio::svgreader
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to