diff --git a/filter/qa/unit/data/YAxis.odg b/filter/qa/unit/data/YAxis.odg new file mode 100644 index 000000000000..1d01ec508b65 Binary files /dev/null and b/filter/qa/unit/data/YAxis.odg differ diff --git a/filter/qa/unit/svg.cxx b/filter/qa/unit/svg.cxx index a7b055c8dbe8..63b914eb9b7b 100644 --- a/filter/qa/unit/svg.cxx +++ b/filter/qa/unit/svg.cxx @@ -341,6 +341,34 @@ CPPUNIT_TEST_FIXTURE(SvgFilterTest, testSemiTransparentTextBullet) 0); } +CPPUNIT_TEST_FIXTURE(SvgFilterTest, testMapModeText) +{ + loadFromFile(u"YAxis.odg"); + + // Export to SVG. + save(u"draw_svg_Export"_ustr); + + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + + OUString sTransform + = getXPath(pXmlDoc, "(//svg:text[@class='SVGTextShape'])[last()]"_ostr, "transform"_ostr); + + OUString aTextPositionX + = getXPath(pXmlDoc, "(//svg:tspan[@class='TextPosition'])[last()]"_ostr, "x"_ostr); + OUString aTextPositionY + = getXPath(pXmlDoc, "(//svg:tspan[@class='TextPosition'])[last()]"_ostr, "y"_ostr); + + OUString sExpectedTransform("rotate(-90 " + aTextPositionX + " " + aTextPositionY + ")"); + + // We expect the rotate point of the rotated text to match the start position of the text + CPPUNIT_ASSERT_EQUAL(sExpectedTransform, sTransform); + // Without the accompanying fix, this test would have failed with: + // - Expected: rotate(-90 3386 14754) + // - Actual : rotate(-90 -1651 14488) + // Because the (local) MapMode wasn't taken into account for the text position when peeking + // ahead to get the rotation. +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx index 92825412250a..c3aa21599512 100644 --- a/filter/source/svg/svgwriter.cxx +++ b/filter/source/svg/svgwriter.cxx @@ -601,6 +601,11 @@ sal_Int32 SVGTextWriter::setTextPosition(const GDIMetaFile& rMtf, size_t& nCurAc bool bConfigured = false; bool bEmpty = true; + // similar to OutputDevice::Push, but we may conditionally not restore these + MapMode aOrigMapMode = mpVDev->GetMapMode(); + bool bOrigMapMapModeEnabled = mpVDev->IsMapModeEnabled(); + int nPopsNeeded = 0; + size_t nActionIndex = nCurAction + 1; for( ; nActionIndex < nCount; ++nActionIndex ) { @@ -717,6 +722,23 @@ sal_Int32 SVGTextWriter::setTextPosition(const GDIMetaFile& rMtf, size_t& nCurAc } } break; + + case MetaActionType::PUSH: + const_cast(pAction)->Execute(mpVDev); + ++nPopsNeeded; + break; + case MetaActionType::POP: + const_cast(pAction)->Execute(mpVDev); + --nPopsNeeded; + break; + case MetaActionType::MAPMODE: + { + // keep MapMode up to date + const_cast(pAction)->Execute(mpVDev); + break; + } + break; + default: break; } if( bConfigured || bEOL || bEOP || bETS ) break; @@ -725,13 +747,23 @@ sal_Int32 SVGTextWriter::setTextPosition(const GDIMetaFile& rMtf, size_t& nCurAc if( bEmpty ) { + // If we fast-forward to this nActionIndex, then leave + // the OutputDevice state as it is. nCurAction = nActionIndex; return ( bEOL ? -2 : ( bEOP ? -1 : 0 ) ); } - else + + // If we are leaving nCurAction untouched, then restore the OutputDevice + // to its original state + while (nPopsNeeded > 0) { - return 1; + mpVDev->Pop(); + --nPopsNeeded; } + + mpVDev->SetMapMode(aOrigMapMode); + mpVDev->EnableMapMode(bOrigMapMapModeEnabled); + return 1; }