drawinglayer/source/tools/emfphelperdata.cxx | 28 +++----- drawinglayer/source/tools/emfphelperdata.hxx | 3 emfio/qa/cppunit/emf/EmfImportTest.cxx | 44 ++++++++++++-- emfio/qa/cppunit/emf/data/TestEmfPlusSetPageTransform.emf |binary 4 files changed, 50 insertions(+), 25 deletions(-)
New commits: commit 8b002437fbe29d5bac7ab0358a4e838a140d4e3c Author: Bartosz Kosiorek <[email protected]> AuthorDate: Sat Feb 14 18:22:57 2026 +0100 Commit: Bartosz Kosiorek <[email protected]> CommitDate: Sun Feb 15 12:21:53 2026 +0100 tdf#168227 EMF+ Fix implementation of SetPageTransform The implementation of SetPageTransform was incorrectly overwriting mnMmX and mnMmY with calculated pixel values. These variables represent the Reference Device size from the EMF+ header and should remain constant. Overwriting them causes mappingChanged() to calculate an incorrect transformation matrix, as it relies on the original ratio between reference millimeters and pixels. This led to incorrect scaling and cumulative errors if multiple SetPageTransform records were present in the document. This patch ensures that header constants are preserved and the Page Scale is applied as a separate step in the transformation pipeline. Change-Id: I7a957f57894cc079292e8f93c119dd0fdb456fb4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199380 Tested-by: Jenkins Reviewed-by: Bartosz Kosiorek <[email protected]> diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx index b911e5ec1272..e5bc612b4f40 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -443,6 +443,7 @@ namespace emfplushelper // To evtl. correct and see where this came from, please compare with the implementations // of EmfPlusHelperData::MapToDevice and EmfPlusHelperData::Map* in prev versions maMapTransform = maWorldTransform; + maMapTransform.scale(mfPageScaleX, mfPageScaleY); maMapTransform *= basegfx::utils::createScaleTranslateB2DHomMatrix(100.0 * mnMmX / mnPixX, 100.0 * mnMmY / mnPixY, double(-mnFrameLeft), double(-mnFrameTop)); maMapTransform *= maBaseTransform; @@ -907,7 +908,8 @@ namespace emfplushelper SvMemoryStream& rMS, wmfemfhelper::TargetHolders& rTargetHolders, wmfemfhelper::PropertyHolders& rPropertyHolders) - : mfPageScale(0.0), + : mfPageScaleX(1.0), + mfPageScaleY(1.0), mnOriginX(0), mnOriginY(0), mnHDPI(0), @@ -1751,19 +1753,14 @@ namespace emfplushelper } case EmfPlusRecordTypeSetPageTransform: { - rMS.ReadFloat(mfPageScale); - SAL_INFO("drawinglayer.emf", "EMF+ Scale: " << mfPageScale << " unit: " << UnitTypeToString(flags)); + float pageScale; + rMS.ReadFloat(pageScale); + SAL_INFO("drawinglayer.emf", "EMF+ Scale: " << pageScale << " unit: " << UnitTypeToString(flags)); + + mfPageScaleX = unitToPixel(pageScale, flags, Direction::horizontal); + mfPageScaleY = unitToPixel(pageScale, flags, Direction::vertical); + mappingChanged(); - if ((flags == UnitTypeDisplay) || (flags == UnitTypeWorld)) - { - SAL_WARN("drawinglayer.emf", "EMF+ file error. UnitTypeDisplay and UnitTypeWorld are not supported by SetPageTransform in EMF+ specification."); - } - else - { - mnMmX = std::round(unitToPixel(static_cast<double>(mnMmX) * mfPageScale, flags, Direction::horizontal)); - mnMmY = std::round(unitToPixel(static_cast<double>(mnMmY) * mfPageScale, flags, Direction::vertical)); - mappingChanged(); - } break; } case EmfPlusRecordTypeSetRenderingOrigin: @@ -1847,11 +1844,6 @@ namespace emfplushelper rMS.ReadUInt32(stackIndex); SAL_INFO("drawinglayer.emf", "EMF+ Begin Container stack index: " << stackIndex << ", PageUnit: " << flags); - if ((flags == UnitTypeDisplay) || (flags == UnitTypeWorld)) - { - SAL_WARN("drawinglayer.emf", "EMF+ file error. UnitTypeDisplay and UnitTypeWorld are not supported by BeginContainer in EMF+ specification."); - break; - } GraphicStatePush(mGSContainerStack, stackIndex); const basegfx::B2DHomMatrix transform = basegfx::utils::createScaleTranslateB2DHomMatrix( unitToPixel(static_cast<double>(dw) / sw, flags, Direction::horizontal), diff --git a/drawinglayer/source/tools/emfphelperdata.hxx b/drawinglayer/source/tools/emfphelperdata.hxx index 51561e3161fa..610079571828 100644 --- a/drawinglayer/source/tools/emfphelperdata.hxx +++ b/drawinglayer/source/tools/emfphelperdata.hxx @@ -183,7 +183,8 @@ namespace emfplushelper basegfx::B2DHomMatrix maMapTransform; std::unique_ptr<EMFPObject> maEMFPObjects[256]; - float mfPageScale; + double mfPageScaleX; + double mfPageScaleY; sal_Int32 mnOriginX; sal_Int32 mnOriginY; sal_uInt32 mnHDPI; diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index 659424d97de8..5d134baf3488 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -336,7 +336,7 @@ CPPUNIT_TEST_FIXTURE(Test, testDrawLine) assertXPath(pDocument, aXPathPrefix + "mask/unifiedtransparence/polypolygonstroke/line", "linecap", u"BUTT"); assertXPath(pDocument, aXPathPrefix + "mask/unifiedtransparence/polypolygonstroke/polypolygon", - "path", u"m89.1506452315894 403.573503917507 895.170581035125-345.821325648415"); + "path", u"m77.940249951477 403.573552502852 888.231320530266-345.821343684403"); } CPPUNIT_TEST_FIXTURE(Test, testDrawLineWithCaps) @@ -475,7 +475,7 @@ CPPUNIT_TEST_FIXTURE(Test, testLinearGradient) assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[1]", "opacity", u"0.392156862745098"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[1]/polypolygon", "path", - u"m0 0.216110019646294h7615.75822989746v7610.21611001965h-7615.75822989746z"); + u"m0 0.216110019646294h7615.75822989747v7610.21611001965h-7615.75822989747z"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]", "spreadmethod", u"repeat"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]", "startx", u"-1"); @@ -484,8 +484,8 @@ CPPUNIT_TEST_FIXTURE(Test, testLinearGradient) assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]", "endy", u"-1"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]", "opacity", u"1"); assertXPath(pDocument, aXPathPrefix + "mask/svglineargradient[2]/polypolygon", "path", - u"m7615.75822989746 " - u"0.216110019646294h7615.75822989746v7610.21611001965h-7615.75822989746z"); + u"m7615.75822989747 " + u"0.216110019646294h7615.75822989747v7610.21611001965h-7615.75822989747z"); } CPPUNIT_TEST_FIXTURE(Test, testTextMapMode) @@ -1061,9 +1061,41 @@ CPPUNIT_TEST_FIXTURE(Test, testEmfPlusGetDC) assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[6]/polypolygon", "path", u"m19428.4895833333 6632.22222222222h317.34375v-2398.88888888889h-317.34375z"); assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[6]", "color", u"#fcf2e3"); +} + +CPPUNIT_TEST_FIXTURE(Test, testEmfPlusSetPageTransform) +{ + // tdf#147818 EMF+ records: GetDC, SetPageTransform, FillRects + Primitive2DSequence aSequence + = parseEmf(u"emfio/qa/cppunit/emf/data/TestEmfPlusSetPageTransform.emf"); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength())); + drawinglayer::Primitive2dXmlDump dumper; + xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence)); + CPPUNIT_ASSERT(pDocument); + + assertXPath(pDocument, aXPathPrefix + "textsimpleportion", 2); + assertXPath(pDocument, aXPathPrefix + "textsimpleportion[1]", "text", + u"Flow Chart LM_SOP_01.04.04_02_Sonderfreigabe Lieferant_DE.igx"); + assertXPath(pDocument, aXPathPrefix + "textsimpleportion[1]", "fontcolor", u"#000000"); - assertXPath(pDocument, aXPathPrefix + "polypolygonstroke", 4); - assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow", 13); + assertXPath(pDocument, aXPathPrefix + "group", 2); + + assertXPath(pDocument, aXPathPrefix + "group[1]/mask/polypolygon", 1); + assertXPath(pDocument, aXPathPrefix + "group[1]/mask/polypolygoncolor", 1); + assertXPath(pDocument, aXPathPrefix + "group[1]/mask/polypolygoncolor", "color", u"#4080c0"); + assertXPath(pDocument, aXPathPrefix + "group[1]/mask/polypolygoncolor/polypolygon", "height", + u"1620"); + assertXPath(pDocument, aXPathPrefix + "group[1]/mask/polypolygoncolor/polypolygon", "maxy", + u"1994"); + + assertXPath(pDocument, aXPathPrefix + "group[2]/mask/polypolygon", 1); + assertXPath(pDocument, aXPathPrefix + "group[2]/mask/polypolygoncolor", 2); + assertXPath(pDocument, aXPathPrefix + "group[2]/mask/polypolygoncolor[1]", "color", u"#00eeee"); + assertXPath(pDocument, aXPathPrefix + "group[2]/mask/polypolygoncolor[1]/polypolygon", "height", + u"2457"); + assertXPath(pDocument, aXPathPrefix + "group[2]/mask/polypolygoncolor[2]", "color", u"#ee00ee"); + assertXPath(pDocument, aXPathPrefix + "group[2]/mask/polypolygoncolor[2]/polypolygon", "height", + u"2457"); } CPPUNIT_TEST_FIXTURE(Test, testEmfPlusSave) diff --git a/emfio/qa/cppunit/emf/data/TestEmfPlusSetPageTransform.emf b/emfio/qa/cppunit/emf/data/TestEmfPlusSetPageTransform.emf new file mode 100644 index 000000000000..0cc7050fbdfa Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestEmfPlusSetPageTransform.emf differ
