svgio/inc/svgstyleattributes.hxx              |   13 +++++++
 svgio/inc/svgtoken.hxx                        |    3 +
 svgio/qa/cppunit/SvgImportTest.cxx            |   24 ++++++++++++++
 svgio/qa/cppunit/data/tdf156834.svg           |    7 ++++
 svgio/source/svgreader/svgcharacternode.cxx   |   24 ++++++++++++++
 svgio/source/svgreader/svgstyleattributes.cxx |   43 +++++++++++++++++++++++++-
 svgio/source/svgreader/svgtoken.cxx           |    6 ++-
 7 files changed, 116 insertions(+), 4 deletions(-)

New commits:
commit 8fa209ce2e800dc8a51e941cd42a65fa8b2eb14b
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Mon Aug 21 12:35:49 2023 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Aug 21 19:59:27 2023 +0200

    tdf#156834: Add basic support for dominant-baseline attribute
    
    Change-Id: I005d6ca6bc340d73cae639ccd09321a0a00bc4b7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155892
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/svgio/inc/svgstyleattributes.hxx b/svgio/inc/svgstyleattributes.hxx
index 751ee6014e41..60781942667b 100644
--- a/svgio/inc/svgstyleattributes.hxx
+++ b/svgio/inc/svgstyleattributes.hxx
@@ -162,6 +162,13 @@ namespace svgio::svgreader
             Length
         };
 
+        enum class DominantBaseline
+        {
+            Auto,
+            Middle,
+            Hanging
+        };
+
         enum class Visibility
         {
             notset,
@@ -223,6 +230,8 @@ namespace svgio::svgreader
             BaselineShift               maBaselineShift;
             SvgNumber                   maBaselineShiftNumber;
 
+            DominantBaseline            maDominantBaseline;
+
             mutable std::vector<sal_uInt16> maResolvingParent;
 
             // defines if this attributes are part of a ClipPath. If yes,
@@ -438,6 +447,10 @@ namespace svgio::svgreader
             void setBaselineShift(const BaselineShift aBaselineShift) { 
maBaselineShift = aBaselineShift; }
             BaselineShift getBaselineShift() const;
             SvgNumber getBaselineShiftNumber() const;
+
+            // DominantBaseline
+            void setDominantBaseline(const DominantBaseline aDominantBaseline) 
{ maDominantBaseline = aDominantBaseline; }
+            DominantBaseline getDominantBaseline() const;
         };
 
 } // end of namespace svgio::svgreader
diff --git a/svgio/inc/svgtoken.hxx b/svgio/inc/svgtoken.hxx
index 6c1a17692f22..3a4a89f285e2 100644
--- a/svgio/inc/svgtoken.hxx
+++ b/svgio/inc/svgtoken.hxx
@@ -188,7 +188,8 @@ namespace svgio::svgreader
 
             // text tokens
             Text,
-            BaselineShift
+            BaselineShift,
+            DominantBaseline
         };
 
         SVGToken StrToSVGToken(const OUString& rStr, bool bCaseIndependent);
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 95cbc0bcda6a..4d7cd9772d51 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -731,6 +731,30 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf156777)
     assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "y", 
"23");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf156834)
+{
+    Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/tdf156834.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/textsimpleportion", 3);
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", 
"text", "Auto");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "x", 
"30");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[1]", "y", 
"20");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", 
"text", "Middle");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "x", 
"30");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[2]", "y", 
"56");
+
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", 
"text", "Hanging");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "x", 
"30");
+    assertXPath(pDocument, "/primitive2D/transform/textsimpleportion[3]", "y", 
"94");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf104339)
 {
     Primitive2DSequence aSequenceTdf104339 = 
parseSvg(u"/svgio/qa/cppunit/data/tdf104339.svg");
diff --git a/svgio/qa/cppunit/data/tdf156834.svg 
b/svgio/qa/cppunit/data/tdf156834.svg
new file mode 100644
index 000000000000..74dc1548186e
--- /dev/null
+++ b/svgio/qa/cppunit/data/tdf156834.svg
@@ -0,0 +1,7 @@
+<svg viewBox="0 0 200 120" xmlns="http://www.w3.org/2000/svg";>
+  <path d="M20,20 L180,20 M20,50 L180,50 M20,80 L180,80" stroke="grey" />
+
+  <text dominant-baseline="auto" x="30" y="20" font-size="20">Auto</text>
+  <text dominant-baseline="middle" x="30" y="50" font-size="20">Middle</text>
+  <text dominant-baseline="Hanging" x="30" y="80" font-size="20">Hanging</text>
+</svg>
diff --git a/svgio/source/svgreader/svgcharacternode.cxx 
b/svgio/source/svgreader/svgcharacternode.cxx
index 9b9e87d23dca..0199a1ff9105 100644
--- a/svgio/source/svgreader/svgcharacternode.cxx
+++ b/svgio/source/svgreader/svgcharacternode.cxx
@@ -279,6 +279,30 @@ namespace svgio::svgreader
                     }
                 }
 
+                // get DominantBaseline
+                const DominantBaseline 
aDominantBaseline(rSvgStyleAttributes.getDominantBaseline());
+
+                basegfx::B2DRange 
aRange(aTextLayouterDevice.getTextBoundRect(getText(), nIndex, nLength));
+                // apply DominantBaseline
+                switch(aDominantBaseline)
+                {
+                    case DominantBaseline::Middle:
+                    {
+                        aPosition.setY(aPosition.getY() - aRange.getCenterY());
+                        break;
+                    }
+                    case DominantBaseline::Hanging:
+                    {
+                        aPosition.setY(aPosition.getY() - aRange.getMinY());
+                        break;
+                    }
+                    default: // DominantBaseline::Auto
+                    {
+                        // nothing to do
+                        break;
+                    }
+                }
+
                 // get BaselineShift
                 const BaselineShift 
aBaselineShift(rSvgStyleAttributes.getBaselineShift());
 
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx 
b/svgio/source/svgreader/svgstyleattributes.cxx
index 68e8b59d76c2..4ed60d297e4f 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -1285,7 +1285,8 @@ namespace svgio::svgreader
             maClipRule(FillRule::notset),
             maBaselineShift(BaselineShift::Baseline),
             maBaselineShiftNumber(0),
-            maResolvingParent(30, 0),
+            maDominantBaseline(DominantBaseline::Auto),
+            maResolvingParent(31, 0),
             mbIsClipPathContent(SVGToken::ClipPathNode == mrOwner.getType()),
             mbStrokeDasharraySet(false)
         {
@@ -1957,6 +1958,26 @@ namespace svgio::svgreader
                     }
                     break;
                 }
+                case SVGToken::DominantBaseline:
+                {
+                    if(!aContent.isEmpty())
+                    {
+                        if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), 
u"middle"))
+                        {
+                            setDominantBaseline(DominantBaseline::Middle);
+                        }
+                        else 
if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"hanging"))
+                        {
+                            setDominantBaseline(DominantBaseline::Hanging);
+                        }
+                        else
+                        {
+                            // no DominantBaseline
+                            setDominantBaseline(DominantBaseline::Auto);
+                        }
+                    }
+                    break;
+                }
                 default:
                 {
                     break;
@@ -3082,6 +3103,26 @@ namespace svgio::svgreader
 
             return BaselineShift::Baseline;
         }
+
+        DominantBaseline SvgStyleAttributes::getDominantBaseline() const
+        {
+            if(maDominantBaseline != DominantBaseline::Auto)
+            {
+                return maDominantBaseline;
+            }
+
+            const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+            if (pSvgStyleAttributes && maResolvingParent[30] < 
nStyleDepthLimit)
+            {
+                ++maResolvingParent[30];
+                auto ret = pSvgStyleAttributes->getDominantBaseline();
+                --maResolvingParent[30];
+                return ret;
+            }
+
+            return DominantBaseline::Auto;
+        }
 } // end of namespace svgio
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgtoken.cxx 
b/svgio/source/svgreader/svgtoken.cxx
index 961c4ec3b5a4..492c78623f14 100644
--- a/svgio/source/svgreader/svgtoken.cxx
+++ b/svgio/source/svgreader/svgtoken.cxx
@@ -177,7 +177,8 @@ constexpr auto aSVGTokenMapperList = 
frozen::make_unordered_map<std::u16string_v
     { u"stroke-width", SVGToken::StrokeWidth },
 
     { u"text", SVGToken::Text },
-    { u"baseline-shift", SVGToken::BaselineShift }
+    { u"baseline-shift", SVGToken::BaselineShift },
+    { u"dominant-baseline", SVGToken::DominantBaseline }
 });
 
 // The same elements as the map above but lowercase. CSS is case insensitive
@@ -334,7 +335,8 @@ constexpr auto  aSVGLowerCaseTokenMapperList = 
frozen::make_unordered_map<std::u
     { u"stroke-width", SVGToken::StrokeWidth },
 
     { u"text", SVGToken::Text },
-    { u"baseline-shift", SVGToken::BaselineShift }
+    { u"baseline-shift", SVGToken::BaselineShift },
+    { u"dominant-baseline", SVGToken::DominantBaseline }
 });
 
 static_assert(sizeof(aSVGTokenMapperList) == 
sizeof(aSVGLowerCaseTokenMapperList),

Reply via email to