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 :

Reply via email to