[Libreoffice-commits] core.git: test/source vcl/qa vcl/source

Mike Kaganski mike.kaganski at collabora.com
Thu Dec 29 12:18:10 UTC 2016


 test/source/mtfxmldump.cxx           |   17 +++--
 vcl/qa/cppunit/wmf/data/ETO_PDY.emf  |binary
 vcl/qa/cppunit/wmf/data/ETO_PDY.wmf  |binary
 vcl/qa/cppunit/wmf/wmfimporttest.cxx |   26 ++++++++
 vcl/source/filter/wmf/enhwmf.cxx     |   82 ++++++++++++++-----------
 vcl/source/filter/wmf/winmtf.cxx     |  111 +++++++++++++++++++++--------------
 vcl/source/filter/wmf/winmtf.hxx     |    1 
 vcl/source/filter/wmf/winwmf.cxx     |   20 ++++--
 8 files changed, 166 insertions(+), 91 deletions(-)

New commits:
commit fa96ffbc6b51154533557e2b4e03a611ebf09b6c
Author: Mike Kaganski <mike.kaganski at collabora.com>
Date:   Thu Dec 29 11:45:38 2016 +0300

    Add support for ETO_PDY in WMF/EMF
    
    Currently it is implemented by making all characters different
    text arrays.
    
    Unit test included.
    
    Change-Id: I850bf192cf5d978a126d3f37b1084021d37bdf30
    Reviewed-on: https://gerrit.libreoffice.org/32490
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/test/source/mtfxmldump.cxx b/test/source/mtfxmldump.cxx
index e89c1cd..3b20875 100644
--- a/test/source/mtfxmldump.cxx
+++ b/test/source/mtfxmldump.cxx
@@ -421,15 +421,18 @@ void MetafileXmlDump::writeXml(const GDIMetaFile& rMetaFile, XmlWriter& rWriter)
                 rWriter.attribute("index", aIndex);
                 rWriter.attribute("length", aLength);
 
-                rWriter.startElement("dxarray");
-                OUString sDxLengthString;
-                for (sal_Int32 i = 0; i < aLength; ++i)
+                if (pMetaTextArrayAction->GetDXArray())
                 {
-                    sDxLengthString += OUString::number(pMetaTextArrayAction->GetDXArray()[aIndex+i]);
-                    sDxLengthString += " ";
+                    rWriter.startElement("dxarray");
+                    OUString sDxLengthString;
+                    for (sal_Int32 i = 0; i < aLength; ++i)
+                    {
+                        sDxLengthString += OUString::number(pMetaTextArrayAction->GetDXArray()[aIndex + i]);
+                        sDxLengthString += " ";
+                    }
+                    rWriter.content(sDxLengthString);
+                    rWriter.endElement();
                 }
-                rWriter.content(sDxLengthString);
-                rWriter.endElement();
 
                 rWriter.startElement("text");
                 rWriter.content(pMetaTextArrayAction->GetText());
diff --git a/vcl/qa/cppunit/wmf/data/ETO_PDY.emf b/vcl/qa/cppunit/wmf/data/ETO_PDY.emf
new file mode 100644
index 0000000..065698e
Binary files /dev/null and b/vcl/qa/cppunit/wmf/data/ETO_PDY.emf differ
diff --git a/vcl/qa/cppunit/wmf/data/ETO_PDY.wmf b/vcl/qa/cppunit/wmf/data/ETO_PDY.wmf
new file mode 100644
index 0000000..bd97740
Binary files /dev/null and b/vcl/qa/cppunit/wmf/data/ETO_PDY.wmf differ
diff --git a/vcl/qa/cppunit/wmf/wmfimporttest.cxx b/vcl/qa/cppunit/wmf/wmfimporttest.cxx
index 9315c1e..ca9900c 100644
--- a/vcl/qa/cppunit/wmf/wmfimporttest.cxx
+++ b/vcl/qa/cppunit/wmf/wmfimporttest.cxx
@@ -60,6 +60,7 @@ public:
     void testTdf93750();
     void testTdf99402();
     void testTdf39894();
+    void testETO_PDY();
 
     CPPUNIT_TEST_SUITE(WmfTest);
     CPPUNIT_TEST(globalSetUp);
@@ -71,6 +72,7 @@ public:
     CPPUNIT_TEST(testTdf93750);
     CPPUNIT_TEST(testTdf99402);
     CPPUNIT_TEST(testTdf39894);
+    CPPUNIT_TEST(testETO_PDY);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -289,6 +291,30 @@ void WmfTest::testTdf39894()
     }
 }
 
+void WmfTest::testETO_PDY()
+{
+    OUString files[] = { "ETO_PDY.wmf", "ETO_PDY.emf" };
+    for (const auto& file: files)
+    {
+        SvFileStream aFileStream(getFullUrl(file), StreamMode::READ);
+        GDIMetaFile aGDIMetaFile;
+        ReadWindowMetafile(aFileStream, aGDIMetaFile);
+
+        MetafileXmlDump dumper;
+        xmlDocPtr pDoc = dumper.dumpAndParse(aGDIMetaFile);
+
+        CPPUNIT_ASSERT(pDoc);
+
+        // The y position of following text
+        // must be smaller than that of previous
+        auto y1 = getXPath(pDoc, "/metafile/push[2]/textarray[1]", "y");
+        auto y2 = getXPath(pDoc, "/metafile/push[2]/textarray[2]", "y");
+        auto y3 = getXPath(pDoc, "/metafile/push[2]/textarray[3]", "y");
+        CPPUNIT_ASSERT_MESSAGE(file.toUtf8().getStr(), y2.toInt32() < y1.toInt32());
+        CPPUNIT_ASSERT_MESSAGE(file.toUtf8().getStr(), y3.toInt32() < y2.toInt32());
+    }
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(WmfTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/filter/wmf/enhwmf.cxx b/vcl/source/filter/wmf/enhwmf.cxx
index f5ee19a..d4641c6 100644
--- a/vcl/source/filter/wmf/enhwmf.cxx
+++ b/vcl/source/filter/wmf/enhwmf.cxx
@@ -1547,7 +1547,6 @@ bool EnhWMFReader::ReadEnhWMF()
                     sal_Int32   nLeft, nTop, nRight, nBottom, ptlReferenceX, ptlReferenceY, nGfxMode, nXScale, nYScale;
                     sal_uInt32  nOffString, nOptions, offDx;
                     sal_Int32   nLen;
-                    std::vector<long> aDX;
 
                     nCurPos = pWMF->Tell() - 8;
 
@@ -1568,23 +1567,6 @@ bool EnhWMFReader::ReadEnhWMF()
                     bool bOffStringSane = nOffString <= nEndPos - nCurPos;
                     if (bLenSane && bOffStringSane)
                     {
-                        sal_Int32 nDxSize = nLen * ((nOptions & ETO_PDY) ? 8 : 4);
-                        if ( offDx && (( nCurPos + offDx + nDxSize ) <= nNextPos ) && nNextPos <= nEndPos )
-                        {
-                            pWMF->Seek( nCurPos + offDx );
-                            aDX.resize(nLen);
-                            for (sal_Int32 i = 0; i < nLen; ++i)
-                            {
-                                sal_Int32 val(0);
-                                pWMF->ReadInt32(val);
-                                aDX[i] = val;
-                                if (nOptions & ETO_PDY)
-                                {
-                                    pWMF->ReadInt32(val);
-                                    // TODO: Use Dy value
-                                }
-                            }
-                        }
                         pWMF->Seek( nCurPos + nOffString );
                         OUString aText;
                         if ( bFlag )
@@ -1594,22 +1576,6 @@ bool EnhWMFReader::ReadEnhWMF()
                                 std::unique_ptr<sal_Char[]> pBuf(new sal_Char[ nLen ]);
                                 pWMF->ReadBytes(pBuf.get(), nLen);
                                 aText = OUString(pBuf.get(), nLen, pOut->GetCharSet());
-                                pBuf.reset();
-
-                                if ( aText.getLength() != nLen )
-                                {
-                                    std::vector<long> aOldDX(aText.getLength());
-                                    aOldDX.swap(aDX);
-                                    sal_Int32 nDXLen = std::min<sal_Int32>(nLen, aOldDX.size());
-                                    for (sal_Int32 i = 0, j = 0; i < aText.getLength(); ++i)
-                                    {
-                                        sal_Unicode cUniChar = aText[i];
-                                        OString aCharacter(&cUniChar, 1, pOut->GetCharSet());
-                                        aDX[i] = 0;
-                                        for (sal_Int32 k = 0; ( k < aCharacter.getLength() ) && ( j < nDXLen ) && ( i < aText.getLength() ); ++k)
-                                            aDX[ i ] += aOldDX[j++];
-                                    }
-                                }
                             }
                         }
                         else
@@ -1630,7 +1596,53 @@ bool EnhWMFReader::ReadEnhWMF()
                                 aText = OUString(pBuf.get(), nLen);
                             }
                         }
-                        pOut->DrawText(aPos, aText, aDX.data(), bRecordPath, nGfxMode);
+
+                        std::unique_ptr<long[]> pDXAry, pDYAry;
+                        sal_Int32 nDxSize = nLen * ((nOptions & ETO_PDY) ? 8 : 4);
+                        if ( offDx && (( nCurPos + offDx + nDxSize ) <= nNextPos ) && nNextPos <= nEndPos )
+                        {
+                            pWMF->Seek( nCurPos + offDx );
+                            pDXAry.reset( new long[aText.getLength()] );
+                            if (nOptions & ETO_PDY)
+                            {
+                                pDYAry.reset( new long[aText.getLength()] );
+                            }
+
+                            for (sal_Int32 i = 0; i < aText.getLength(); ++i)
+                            {
+                                sal_Int32 nDxCount = 1;
+                                if (aText.getLength() != nLen)
+                                {
+                                    sal_Unicode cUniChar = aText[i];
+                                    OString aTmp(&cUniChar, 1, pOut->GetCharSet());
+                                    if (aTmp.getLength() > 1)
+                                    {
+                                        nDxCount = aTmp.getLength();
+                                    }
+                                }
+
+                                sal_Int32 nDx = 0, nDy = 0;
+                                while (nDxCount--)
+                                {
+                                    sal_Int32 nDxTmp = 0;
+                                    pWMF->ReadInt32(nDxTmp);
+                                    nDx += nDxTmp;
+                                    if (nOptions & ETO_PDY)
+                                    {
+                                        sal_Int32 nDyTmp = 0;
+                                        pWMF->ReadInt32(nDyTmp);
+                                        nDy += nDyTmp;
+                                    }
+                                }
+
+                                pDXAry[i] = nDx;
+                                if (nOptions & ETO_PDY)
+                                {
+                                    pDYAry[i] = nDy;
+                                }
+                            }
+                        }
+                        pOut->DrawText(aPos, aText, pDXAry.get(), pDYAry.get(), bRecordPath, nGfxMode);
                     }
                 }
                 break;
diff --git a/vcl/source/filter/wmf/winmtf.cxx b/vcl/source/filter/wmf/winmtf.cxx
index 3165cee..a169fce 100644
--- a/vcl/source/filter/wmf/winmtf.cxx
+++ b/vcl/source/filter/wmf/winmtf.cxx
@@ -1348,7 +1348,7 @@ void WinMtfOutput::DrawPolyBezier( tools::Polygon& rPolygon, bool bTo, bool bRec
     }
 }
 
-void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, bool bRecordPath, sal_Int32 nGfxMode )
+void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, long* pDYArry, bool bRecordPath, sal_Int32 nGfxMode )
 {
     UpdateClipRegion();
     rPosition = ImplMap( rPosition );
@@ -1357,18 +1357,25 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b
 
     if (pDXArry)
     {
-        sal_Int32 i;
-        sal_Int32 nSum = 0;
-        sal_Int32 nLen = rText.getLength();
-
-        for (i = 0; i < nLen; i++ )
+        sal_Int32 nSumX = 0, nSumY = 0;
+        for (sal_Int32 i = 0; i < rText.getLength(); i++ )
         {
-            nSum += pDXArry[i];
+            nSumX += pDXArry[i];
 
             // #i121382# Map DXArray using WorldTransform
-            const Size aSize(ImplMap(Size(nSum, 0)));
-            const basegfx::B2DVector aVector(aSize.Width(), aSize.Height());
-            pDXArry[i] = basegfx::fround(aVector.getLength());
+            const Size aSizeX(ImplMap(Size(nSumX, 0)));
+            const basegfx::B2DVector aVectorX(aSizeX.Width(), aSizeX.Height());
+            pDXArry[i] = basegfx::fround(aVectorX.getLength()) * (nSumX >= 0 ? 1 : -1);
+
+            if (pDYArry)
+            {
+                nSumY += pDYArry[i];
+
+                const Size aSizeY(ImplMap(Size(0, nSumY)));
+                const basegfx::B2DVector aVectorY(aSizeY.Width(), aSizeY.Height());
+                // Reverse Y
+                pDYArry[i] = basegfx::fround(aVectorY.getLength()) * (nSumY >= 0 ? -1 : 1);
+            }
         }
     }
     if ( mnLatestTextLayoutMode != mnTextLayoutMode )
@@ -1377,18 +1384,18 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b
         mpGDIMetaFile->AddAction( new MetaLayoutModeAction( mnTextLayoutMode ) );
     }
     SetGfxMode( nGfxMode );
+    TextAlign eTextAlign;
+    if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE )
+        eTextAlign = ALIGN_BASELINE;
+    else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM )
+        eTextAlign = ALIGN_BOTTOM;
+    else
+        eTextAlign = ALIGN_TOP;
     bool bChangeFont = false;
     if ( mnLatestTextAlign != mnTextAlign )
     {
         bChangeFont = true;
         mnLatestTextAlign = mnTextAlign;
-        TextAlign eTextAlign;
-        if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE )
-            eTextAlign = ALIGN_BASELINE;
-        else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM )
-            eTextAlign = ALIGN_BOTTOM;
-        else
-            eTextAlign = ALIGN_TOP;
         mpGDIMetaFile->AddAction( new MetaTextAlignAction( eTextAlign ) );
     }
     if ( maLatestTextColor != maTextColor )
@@ -1422,12 +1429,7 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b
     else
         aTmp.SetTransparent( false );
 
-    if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE )
-        aTmp.SetAlignment( ALIGN_BASELINE );
-    else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM )
-        aTmp.SetAlignment( ALIGN_BOTTOM );
-    else
-        aTmp.SetAlignment( ALIGN_TOP );
+    aTmp.SetAlignment( eTextAlign );
 
     if ( nGfxMode == GM_ADVANCED )
     {
@@ -1455,7 +1457,8 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b
         // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
         SolarMutexGuard aGuard;
         ScopedVclPtrInstance< VirtualDevice > pVDev;
-        sal_Int32 nTextWidth, nActPosDeltaX = 0;
+        sal_Int32 nTextWidth;
+        Point aActPosDelta;
         pVDev->SetMapMode( MapMode( MapUnit::Map100thMM ) );
         pVDev->SetFont( maFont );
         if( pDXArry )
@@ -1465,23 +1468,33 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b
             if( nLen > 1 )
                 nTextWidth += pDXArry[ nLen - 2 ];
             // tdf#39894: We should consider the distance to next character cell origin
-            nActPosDeltaX = pDXArry[ nLen - 1 ];
+            aActPosDelta.X() = pDXArry[ nLen - 1 ];
+            if ( pDYArry )
+            {
+                aActPosDelta.Y() = pDYArry[ nLen - 1 ];
+            }
         }
         else
+        {
             nTextWidth = pVDev->GetTextWidth( rText );
+            aActPosDelta.X() = nTextWidth;
+        }
 
         if( mnTextAlign & TA_UPDATECP )
             rPosition = maActPos;
 
         if ( mnTextAlign & TA_RIGHT_CENTER )
         {
-            double fLength = ( ( mnTextAlign & TA_RIGHT_CENTER ) == TA_RIGHT ) ? nTextWidth : nTextWidth >> 1;
-            rPosition.X() -= (sal_Int32)( fLength * cos( maFont.GetOrientation() * F_PI1800 ) );
-            rPosition.Y() -= (sal_Int32)(-( fLength * sin( maFont.GetOrientation() * F_PI1800 ) ) );
+            Point aDisplacement( ( ( mnTextAlign & TA_RIGHT_CENTER ) == TA_RIGHT ) ? nTextWidth : nTextWidth >> 1, 0 );
+            Point().RotateAround(aDisplacement.X(), aDisplacement.Y(), maFont.GetOrientation());
+            rPosition -= aDisplacement;
         }
 
         if( mnTextAlign & TA_UPDATECP )
-            maActPos.X() = rPosition.X() + (pDXArry ? nActPosDeltaX : nTextWidth);
+        {
+            Point().RotateAround(aActPosDelta.X(), aActPosDelta.Y(), maFont.GetOrientation());
+            maActPos = rPosition + aActPosDelta;
+        }
     }
     if ( bChangeFont || ( maLatestFont != aTmp ) )
     {
@@ -1497,22 +1510,34 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b
     }
     else
     {
-        /* because text without dx array is badly scaled, we
-           will create such an array if necessary */
-        long* pDX = pDXArry;
-        if (!pDXArry)
+        if ( pDXArry && pDYArry )
+        {
+            for (sal_Int32 i = 0; i < rText.getLength(); ++i)
+            {
+                Point aCharDisplacement( i ? pDXArry[i-1] : 0, i ? pDYArry[i-1] : 0 );
+                Point().RotateAround(aCharDisplacement.X(), aCharDisplacement.Y(), maFont.GetOrientation());
+                mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition + aCharDisplacement, OUString( rText[i] ), nullptr, 0, 1 ) );
+            }
+        }
+        else
         {
-            // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
-            SolarMutexGuard aGuard;
-            ScopedVclPtrInstance< VirtualDevice > pVDev;
-            pDX = new long[ rText.getLength() ];
-            pVDev->SetMapMode( MapUnit::Map100thMM );
-            pVDev->SetFont( maLatestFont );
-            pVDev->GetTextArray( rText, pDX, 0, rText.getLength());
+            /* because text without dx array is badly scaled, we
+               will create such an array if necessary */
+            long* pDX = pDXArry;
+            if (!pDXArry)
+            {
+                // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading
+                SolarMutexGuard aGuard;
+                ScopedVclPtrInstance< VirtualDevice > pVDev;
+                pDX = new long[ rText.getLength() ];
+                pVDev->SetMapMode( MapUnit::Map100thMM );
+                pVDev->SetFont( maLatestFont );
+                pVDev->GetTextArray( rText, pDX, 0, rText.getLength());
+            }
+            mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, rText.getLength() ) );
+            if ( !pDXArry )     // this means we have created our own array
+                delete[] pDX;   // which must be deleted
         }
-        mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, rText.getLength() ) );
-        if ( !pDXArry )     // this means we have created our own array
-            delete[] pDX;   // which must be deleted
     }
     SetGfxMode( nOldGfxMode );
 }
diff --git a/vcl/source/filter/wmf/winmtf.hxx b/vcl/source/filter/wmf/winmtf.hxx
index 5fca59b..2e30747 100644
--- a/vcl/source/filter/wmf/winmtf.hxx
+++ b/vcl/source/filter/wmf/winmtf.hxx
@@ -600,6 +600,7 @@ public:
     void                DrawText( Point& rPosition,
                                   OUString& rString,
                                   long* pDXArry = nullptr,
+                                  long* pDYArry = nullptr,
                                   bool bRecordPath = false,
                                   sal_Int32 nGraphicsMode = GM_COMPATIBLE);
 
diff --git a/vcl/source/filter/wmf/winwmf.cxx b/vcl/source/filter/wmf/winwmf.cxx
index 7fd1fc7..b8ac93d 100644
--- a/vcl/source/filter/wmf/winwmf.cxx
+++ b/vcl/source/filter/wmf/winwmf.cxx
@@ -551,7 +551,7 @@ void WMFReader::ReadRecordParams( sal_uInt16 nFunc )
                                                                                                 // dxAry will not fit
                 if ( nNewTextLen )
                 {
-                    std::unique_ptr<long[]> pDXAry;
+                    std::unique_ptr<long[]> pDXAry, pDYAry;
                     sal_uInt32  nMaxStreamPos = nRecordPos + ( nRecordSize << 1 );
                     sal_Int32   nDxArySize =  nMaxStreamPos - pWMF->Tell();
                     sal_Int32   nDxAryEntries = nDxArySize >> 1;
@@ -561,6 +561,10 @@ void WMFReader::ReadRecordParams( sal_uInt16 nFunc )
                     {
                         sal_uInt16 i; // needed just outside the for
                         pDXAry.reset(new long[ nNewTextLen ]);
+                        if ( nOptions & ETO_PDY )
+                        {
+                            pDYAry.reset(new long[ nNewTextLen ]);
+                        }
                         for (i = 0; i < nNewTextLen; i++ )
                         {
                             if ( pWMF->Tell() >= nMaxStreamPos )
@@ -568,15 +572,15 @@ void WMFReader::ReadRecordParams( sal_uInt16 nFunc )
                             sal_Int32 nDxCount = 1;
                             if ( nNewTextLen != nOriginalTextLen )
                             {
-                                sal_Unicode nUniChar = aText[i];
-                                OString aTmp(&nUniChar, 1, pOut->GetCharSet());
+                                sal_Unicode cUniChar = aText[i];
+                                OString aTmp(&cUniChar, 1, pOut->GetCharSet());
                                 if ( aTmp.getLength() > 1 )
                                 {
                                     nDxCount = aTmp.getLength();
                                 }
                             }
 
-                            sal_Int16 nDx = 0;
+                            sal_Int16 nDx = 0, nDy = 0;
                             while ( nDxCount-- )
                             {
                                 if ( ( pWMF->Tell() + 2 ) > nMaxStreamPos )
@@ -590,17 +594,21 @@ void WMFReader::ReadRecordParams( sal_uInt16 nFunc )
                                         break;
                                     sal_Int16 nDyTmp = 0;
                                     pWMF->ReadInt16(nDyTmp);
-                                    // TODO: use Dy offset
+                                    nDy += nDyTmp;
                                 }
                             }
 
                             pDXAry[ i ] = nDx;
+                            if ( nOptions & ETO_PDY )
+                            {
+                                pDYAry[i] = nDy;
+                            }
                         }
                         if ( i == nNewTextLen )
                             bUseDXAry = true;
                     }
                     if ( pDXAry && bUseDXAry )
-                        pOut->DrawText( aPosition, aText, pDXAry.get() );
+                        pOut->DrawText( aPosition, aText, pDXAry.get(), pDYAry.get() );
                     else
                         pOut->DrawText( aPosition, aText );
                 }


More information about the Libreoffice-commits mailing list