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 <xiscofauli@libreoffice.org>
(cherry picked from commit 3b357ecb7bca4ab3844d1900eced55f46e6f8e1c)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155913
diff --git a/svgio/inc/svgstyleattributes.hxx b/svgio/inc/svgstyleattributes.hxx
index 0db3132..acd310a 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,
@@ -229,6 +236,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,
@@ -444,6 +453,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 6c1a176..3a4a89f 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 c7bf11b..fde5c7e 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -727,6 +727,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", "57");
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 0000000..74dc154
--- /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 91ec98a..cb39d6d 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 95c83c2..94209c32 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -1292,7 +1292,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)
{
@@ -1964,6 +1965,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;
@@ -3113,6 +3134,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 961c4ec..492c786 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),