diff options
-rw-r--r-- | svgio/inc/svgcharacternode.hxx | 2 | ||||
-rw-r--r-- | svgio/qa/cppunit/SvgImportTest.cxx | 24 | ||||
-rw-r--r-- | svgio/qa/cppunit/data/tspan-fill-opacity.svg | 15 | ||||
-rw-r--r-- | svgio/source/svgreader/svgcharacternode.cxx | 19 |
4 files changed, 57 insertions, 3 deletions
diff --git a/svgio/inc/svgcharacternode.hxx b/svgio/inc/svgcharacternode.hxx index 50ecda7e3a89..738ddf4d9e73 100644 --- a/svgio/inc/svgcharacternode.hxx +++ b/svgio/inc/svgcharacternode.hxx @@ -123,7 +123,7 @@ namespace svgio::svgreader OUString maText; /// local helpers - rtl::Reference<drawinglayer::primitive2d::TextSimplePortionPrimitive2D> createSimpleTextPrimitive( + rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> createSimpleTextPrimitive( SvgTextPosition& rSvgTextPosition, const SvgStyleAttributes& rSvgStyleAttributes) const; void decomposeTextWithStyle( diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx index 9d9fb93dc8c1..cf678964b996 100644 --- a/svgio/qa/cppunit/SvgImportTest.cxx +++ b/svgio/qa/cppunit/SvgImportTest.cxx @@ -84,6 +84,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools void testTdf97663(); void testTdf149880(); void testCssClassRedefinition(); + void testTspanFillOpacity(); Primitive2DSequence parseSvg(std::u16string_view aSource); @@ -134,6 +135,7 @@ public: CPPUNIT_TEST(testTdf97663); CPPUNIT_TEST(testTdf149880); CPPUNIT_TEST(testCssClassRedefinition); + CPPUNIT_TEST(testTspanFillOpacity); CPPUNIT_TEST_SUITE_END(); }; @@ -1127,6 +1129,28 @@ void Test::testCssClassRedefinition() pDocument, "/primitive2D/transform/textsimpleportion[1]", "familyname", "Open Symbol"); } +void Test::testTspanFillOpacity() +{ + // Given an SVG file with <tspan fill-opacity="0.30">: + std::u16string_view aPath = u"/svgio/qa/cppunit/data/tspan-fill-opacity.svg"; + + // When rendering that SVG: + Primitive2DSequence aSequence = parseSvg(aPath); + + // Then make sure that the text portion is wrapped in a transparency primitive with the correct + // transparency value: + drawinglayer::Primitive2dXmlDump aDumper; + xmlDocUniquePtr pDocument = aDumper.dumpAndParse(Primitive2DContainer(aSequence)); + sal_Int32 nTransparence = getXPath(pDocument, "//textsimpleportion[@text='hello']/parent::unifiedtransparence", "transparence").toInt32(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // - XPath '//textsimpleportion[@text='hello']/parent::unifiedtransparence' number of nodes is incorrect + // i.e. the relevant <textsimpleportion> had no <unifiedtransparence> parent, the text was not + // semi-transparent. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(70), nTransparence); +} + CPPUNIT_TEST_SUITE_REGISTRATION(Test); } diff --git a/svgio/qa/cppunit/data/tspan-fill-opacity.svg b/svgio/qa/cppunit/data/tspan-fill-opacity.svg new file mode 100644 index 000000000000..ef6d5352a8d2 --- /dev/null +++ b/svgio/qa/cppunit/data/tspan-fill-opacity.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg version="1.2" width="210mm" height="297mm" viewBox="0 0 21000 29700" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xml:space="preserve"> + <g class="ClosedBezierShape"> + <rect stroke="none" fill="none" x="9737" y="6537" width="7527" height="3527"/> + <g style="opacity: 0.30"> + <path fill="none" stroke="rgb(255,0,0)" stroke-width="25" stroke-linejoin="round" d="M 9875,6550 C 9806,6550 9750,6606 9750,6675 L 9750,9925 C 9750,9994 9806,10050 9875,10050 L 17125,10050 C 17194,10050 17250,9994 17250,9925 L 17250,6675 C 17250,6606 17194,6550 17125,6550 L 17000,6550 9875,6550 Z"/> + </g> + </g> + <g class="TextShape"> + <rect stroke="none" fill="none" x="9825" y="6550" width="4076" height="955"/> + <text> + <tspan x="9825" y="7939" font-family="Arial Narrow, sans-serif" font-size="800px" fill-opacity="0.30" fill="rgb(255,0,0)" stroke="none">hello</tspan> + </text> + </g> +</svg> diff --git a/svgio/source/svgreader/svgcharacternode.cxx b/svgio/source/svgreader/svgcharacternode.cxx index d2949d5a0630..4ca8a3468c02 100644 --- a/svgio/source/svgreader/svgcharacternode.cxx +++ b/svgio/source/svgreader/svgcharacternode.cxx @@ -24,6 +24,7 @@ #include <drawinglayer/primitive2d/textlayoutdevice.hxx> #include <drawinglayer/primitive2d/textbreakuphelper.hxx> #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> #include <utility> #include <o3tl/string_view.hxx> #include <osl/diagnose.h> @@ -208,12 +209,12 @@ namespace svgio::svgreader } } - rtl::Reference<TextSimplePortionPrimitive2D> SvgCharacterNode::createSimpleTextPrimitive( + rtl::Reference<BasePrimitive2D> SvgCharacterNode::createSimpleTextPrimitive( SvgTextPosition& rSvgTextPosition, const SvgStyleAttributes& rSvgStyleAttributes) const { // prepare retval, index and length - rtl::Reference<TextSimplePortionPrimitive2D> pRetval; + rtl::Reference<BasePrimitive2D> pRetval; sal_uInt32 nLength(getText().getLength()); if(nLength) @@ -412,6 +413,13 @@ namespace svgio::svgreader if(rSvgStyleAttributes.getFill()) aFill = *rSvgStyleAttributes.getFill(); + // get fill opacity + double fFillOpacity = 1.0; + if (rSvgStyleAttributes.getFillOpacity().isSet()) + { + fFillOpacity = rSvgStyleAttributes.getFillOpacity().getNumber(); + } + // prepare TextTransformation basegfx::B2DHomMatrix aTextTransform; @@ -487,6 +495,13 @@ namespace svgio::svgreader aFill); } + if (fFillOpacity != 1.0) + { + pRetval = new UnifiedTransparencePrimitive2D( + drawinglayer::primitive2d::Primitive2DContainer{ pRetval }, + 1.0 - fFillOpacity); + } + // advance current TextPosition rSvgTextPosition.setPosition(rSvgTextPosition.getPosition() + basegfx::B2DVector(fTextWidth, 0.0)); } |