diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2016-12-29 11:45:38 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2016-12-29 12:17:48 +0000 |
commit | fa96ffbc6b51154533557e2b4e03a611ebf09b6c (patch) | |
tree | 34747643161fa4272b7722d963d86b7b549848b1 | |
parent | 767ec2f138d824b6b51eef73ac9b7d2b193a1e98 (diff) |
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@libreoffice.org>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r-- | test/source/mtfxmldump.cxx | 17 | ||||
-rw-r--r-- | vcl/qa/cppunit/wmf/data/ETO_PDY.emf | bin | 0 -> 1644 bytes | |||
-rw-r--r-- | vcl/qa/cppunit/wmf/data/ETO_PDY.wmf | bin | 0 -> 306 bytes | |||
-rw-r--r-- | vcl/qa/cppunit/wmf/wmfimporttest.cxx | 26 | ||||
-rw-r--r-- | vcl/source/filter/wmf/enhwmf.cxx | 82 | ||||
-rw-r--r-- | vcl/source/filter/wmf/winmtf.cxx | 111 | ||||
-rw-r--r-- | vcl/source/filter/wmf/winmtf.hxx | 1 | ||||
-rw-r--r-- | vcl/source/filter/wmf/winwmf.cxx | 20 |
8 files changed, 166 insertions, 91 deletions
diff --git a/test/source/mtfxmldump.cxx b/test/source/mtfxmldump.cxx index e89c1cd0983c..3b208753b6e2 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 Binary files differnew file mode 100644 index 000000000000..065698eaff2c --- /dev/null +++ b/vcl/qa/cppunit/wmf/data/ETO_PDY.emf diff --git a/vcl/qa/cppunit/wmf/data/ETO_PDY.wmf b/vcl/qa/cppunit/wmf/data/ETO_PDY.wmf Binary files differnew file mode 100644 index 000000000000..bd97740698e3 --- /dev/null +++ b/vcl/qa/cppunit/wmf/data/ETO_PDY.wmf diff --git a/vcl/qa/cppunit/wmf/wmfimporttest.cxx b/vcl/qa/cppunit/wmf/wmfimporttest.cxx index 9315c1e74ea9..ca9900c18ad9 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 f5ee19a9abba..d4641c6bd98c 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 3165cee3ffec..a169fce6422a 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 5fca59bb42fe..2e3074721097 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 7fd1fc7ec2a6..b8ac93dcd646 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 ); } |