emfio/README.md | 2 emfio/inc/mtftools.hxx | 1 emfio/qa/cppunit/emf/EmfImportTest.cxx | 30 ++++++++ emfio/qa/cppunit/emf/data/TestSmallTextOut.emf |binary emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf |binary emfio/source/reader/emfreader.cxx | 76 ++++++++++++++++++++- 6 files changed, 107 insertions(+), 2 deletions(-)
New commits: commit aad62f783bd1bced7a6f850058be9c833f998ec1 Author: Andras Timar <[email protected]> AuthorDate: Sun Feb 8 12:09:12 2026 +0100 Commit: Andras Timar <[email protected]> CommitDate: Sun Feb 8 19:20:56 2026 +0100 tdf#142226 emfio: implement EMR_SMALLTEXTOUT Change-Id: Ib031c0d771045b80c99274974de8267e759e8557 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198903 Tested-by: Jenkins Reviewed-by: Andras Timar <[email protected]> diff --git a/emfio/README.md b/emfio/README.md index f9f33a2ba4e1..b1a0de61c888 100644 --- a/emfio/README.md +++ b/emfio/README.md @@ -82,7 +82,7 @@ EMR_SETPALETTEENTRIES EMR_RESIZEPALETTE EMR_EXTFLOODFILL EMR_ANGLEARC EMR_SETCOLORADJUSTMENT EMR_POLYDRAW16 EMR_CREATECOLORSPACE EMR_SETCOLORSPACE EMR_DELETECOLORSPACE EMR_GLSRECORD EMR_GLSBOUNDEDRECORD EMR_PIXELFORMAT EMR_DRAWESCAPE -EMR_EXTESCAPE EMR_STARTDOC EMR_SMALLTEXTOUT EMR_FORCEUFIMAPPING +EMR_EXTESCAPE EMR_STARTDOC EMR_FORCEUFIMAPPING EMR_NAMEDESCAPE EMR_COLORCORRECTPALETTE EMR_SETICMPROFILEA EMR_SETICMPROFILEW EMR_TRANSPARENTBLT EMR_TRANSPARENTDIB EMR_GRADIENTFILL EMR_SETLINKEDUFIS EMR_SETMAPPERFLAGS EMR_SETICMMODE diff --git a/emfio/inc/mtftools.hxx b/emfio/inc/mtftools.hxx index 91d7ce815450..50e206618625 100644 --- a/emfio/inc/mtftools.hxx +++ b/emfio/inc/mtftools.hxx @@ -267,6 +267,7 @@ namespace emfio ETO_RTLREADING = 0x0080, /* _WIN32_WINNT >= 0x0500 */ ETO_NO_RECT = 0x0100, + ETO_SMALL_CHARS = 0x0200, ETO_PDY = 0x2000 }; diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index b032ed4b33b1..7dcb76160772 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -1701,6 +1701,36 @@ CPPUNIT_TEST_FIXTURE(Test, testAlignRtlReading) assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion[3]", "rtl", u"true"); } +CPPUNIT_TEST_FIXTURE(Test, testSmallTextOut) +{ + // EMR_SMALLTEXTOUT with Unicode text (no ETO_SMALL_CHARS), ETO_NO_RECT. + // Verifies the text "SmallTextOut" is correctly imported. + OUString aUrl = m_directories.getURLFromSrc(u"/emfio/qa/cppunit/emf/data/TestSmallTextOut.emf"); + SvFileStream aFileStream(aUrl, StreamMode::READ); + GDIMetaFile aGDIMetaFile; + ReadWindowMetafile(aFileStream, aGDIMetaFile); + + xmlDocUniquePtr pDoc = dumpAndParse(aGDIMetaFile); + CPPUNIT_ASSERT(pDoc); + + assertXPathContent(pDoc, "/metafile/push[2]/textarray/text", u"SmallTextOut"); +} + +CPPUNIT_TEST_FIXTURE(Test, testSmallTextOutAnsi) +{ + // EMR_SMALLTEXTOUT with ETO_SMALL_CHARS (8-bit text) and bounds rectangle. + OUString aUrl + = m_directories.getURLFromSrc(u"/emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf"); + SvFileStream aFileStream(aUrl, StreamMode::READ); + GDIMetaFile aGDIMetaFile; + ReadWindowMetafile(aFileStream, aGDIMetaFile); + + xmlDocUniquePtr pDoc = dumpAndParse(aGDIMetaFile); + CPPUNIT_ASSERT(pDoc); + + assertXPathContent(pDoc, "/metafile/push[2]/textarray/text", u"AnsiSmall"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/emfio/qa/cppunit/emf/data/TestSmallTextOut.emf b/emfio/qa/cppunit/emf/data/TestSmallTextOut.emf new file mode 100644 index 000000000000..2505d2d65f2c Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestSmallTextOut.emf differ diff --git a/emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf b/emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf new file mode 100644 index 000000000000..cfba2f8e1a4f Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf differ diff --git a/emfio/source/reader/emfreader.cxx b/emfio/source/reader/emfreader.cxx index ec6eb4dcbd62..b78e028cf283 100644 --- a/emfio/source/reader/emfreader.cxx +++ b/emfio/source/reader/emfreader.cxx @@ -1884,6 +1884,81 @@ namespace emfio } break; + case EMR_SMALLTEXTOUT : + { + sal_Int32 ptlReferenceX, ptlReferenceY; + sal_uInt32 nLen, nOptions, nGfxMode; + float nXScale, nYScale; + + mpInputStream->ReadInt32( ptlReferenceX ).ReadInt32( ptlReferenceY ) + .ReadUInt32( nLen ).ReadUInt32( nOptions ) + .ReadUInt32( nGfxMode ).ReadFloat( nXScale ).ReadFloat( nYScale ); + SAL_INFO("emfio", " Reference: (" << ptlReferenceX << ", " << ptlReferenceY << ")"); + SAL_INFO("emfio", " cChars: " << nLen); + SAL_INFO("emfio", " fuOptions: 0x" << std::hex << nOptions << std::dec); + SAL_INFO("emfio", " iGraphicsMode: 0x" << std::hex << nGfxMode << std::dec); + SAL_INFO("emfio", " Scale: " << nXScale << " x " << nYScale); + + // Read optional bounding rectangle (present only if ETO_NO_RECT is NOT set) + tools::Rectangle aRect; + if ( !( nOptions & ETO_NO_RECT ) ) + { + sal_Int32 nLeftRect, nTopRect, nRightRect, nBottomRect; + mpInputStream->ReadInt32( nLeftRect ).ReadInt32( nTopRect ).ReadInt32( nRightRect ).ReadInt32( nBottomRect ); + aRect = tools::Rectangle( nLeftRect, nTopRect, nRightRect, nBottomRect ); + SAL_INFO("emfio", " Bounds: " << nLeftRect << ", " << nTopRect << ", " << nRightRect << ", " << nBottomRect); + } + + if (!mpInputStream->good()) + { + bStatus = false; + } + else + { + const BackgroundMode mnBkModeBackup = mnBkMode; + if ( nOptions & ETO_NO_RECT ) + mnBkMode = BackgroundMode::Transparent; + else if ( nOptions & ETO_OPAQUE ) + DrawRectWithBGColor( aRect ); + + vcl::text::ComplexTextLayoutFlags nTextLayoutMode = vcl::text::ComplexTextLayoutFlags::Default; + if ( nOptions & ETO_RTLREADING ) + nTextLayoutMode = vcl::text::ComplexTextLayoutFlags::BiDiRtl | vcl::text::ComplexTextLayoutFlags::TextOriginLeft; + SetTextLayoutMode( nTextLayoutMode ); + + Point aPos( ptlReferenceX, ptlReferenceY ); + OUString aText; + if ( nOptions & ETO_SMALL_CHARS ) + { + if ( nLen <= ( mnEndPos - mpInputStream->Tell() ) ) + { + std::vector<char> pBuf( nLen ); + mpInputStream->ReadBytes(pBuf.data(), nLen); + aText = OUString(pBuf.data(), nLen, GetCharSet()); + } + } + else + { + if ( ( nLen * sizeof(sal_Unicode) ) <= ( mnEndPos - mpInputStream->Tell() ) ) + { + aText = read_uInt16s_ToOUString(*mpInputStream, nLen); + } + } + SAL_INFO("emfio", " Text: " << aText); + + if ( nOptions & ETO_CLIPPED ) + { + Push(); + IntersectClipRect( aRect ); + } + DrawText(aPos, aText, nullptr, nullptr, mbRecordPath, static_cast<GraphicsMode>(nGfxMode)); + if ( nOptions & ETO_CLIPPED ) + Pop(); + mnBkMode = mnBkModeBackup; + } + } + break; + case EMR_POLYTEXTOUTA : case EMR_EXTTEXTOUTA : bFlag = true; @@ -2224,7 +2299,6 @@ namespace emfio case EMR_DRAWESCAPE : case EMR_EXTESCAPE : case EMR_STARTDOC : - case EMR_SMALLTEXTOUT : case EMR_FORCEUFIMAPPING : case EMR_NAMEDESCAPE : case EMR_COLORCORRECTPALETTE :
