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),