tdf#155488 svg export "peek-ahead" didn't see MapMode changes

normal 'playback' case is ok, but during the peek-ahead to get text positions
then the MapMode was skipped over so the rotate values were created with
the wrong MapMode.

Change-Id: I2b51dbc1b15e8d0d24b00b2bd4decb4c71772208
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173260
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
This commit is contained in:
Caolán McNamara 2024-09-12 13:06:53 +01:00
parent 0c43f53222
commit 623eb17d6b
3 changed files with 62 additions and 2 deletions

Binary file not shown.

View file

@ -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: */

View file

@ -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<MetaAction*>(pAction)->Execute(mpVDev);
++nPopsNeeded;
break;
case MetaActionType::POP:
const_cast<MetaAction*>(pAction)->Execute(mpVDev);
--nPopsNeeded;
break;
case MetaActionType::MAPMODE:
{
// keep MapMode up to date
const_cast<MetaAction*>(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;
}