diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2016-12-26 22:04:23 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2016-12-27 00:22:32 +0000 |
commit | 3fe6703ac30177a939839a70e650eb344c8a9abc (patch) | |
tree | abf5b20da1d9db45f5cc34280b89e2f286415ecf | |
parent | d0288a482a3dc0f50f535565e4c66a95bb140942 (diff) |
tdf#39894: Metafile: use distance from last char cell to next
The optional Dx array of WMF's META_EXTTEXTOUT (and its EMF
counterpart) define not only spacing between char cells of this
record, but also of spacing to first char cell of next text
(if TA_UPDATECP is set). Additionally, both WMF and EMF EXTTEXTOUT
records define not only X spacing, but also Y (if ETO_PDY is set
in its options).
Unit test is included.
Change-Id: I45ed872210c81b3050ba65d68145b64861bfec22
Reviewed-on: https://gerrit.libreoffice.org/32436
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r-- | vcl/qa/cppunit/wmf/data/tdf39894.emf | bin | 0 -> 1628 bytes | |||
-rw-r--r-- | vcl/qa/cppunit/wmf/data/tdf39894.wmf | bin | 0 -> 300 bytes | |||
-rw-r--r-- | vcl/qa/cppunit/wmf/wmfimporttest.cxx | 23 | ||||
-rw-r--r-- | vcl/source/filter/wmf/enhwmf.cxx | 15 | ||||
-rw-r--r-- | vcl/source/filter/wmf/winmtf.cxx | 18 | ||||
-rw-r--r-- | vcl/source/filter/wmf/winwmf.cxx | 54 |
6 files changed, 71 insertions, 39 deletions
diff --git a/vcl/qa/cppunit/wmf/data/tdf39894.emf b/vcl/qa/cppunit/wmf/data/tdf39894.emf Binary files differnew file mode 100644 index 000000000000..c9d5b957b87a --- /dev/null +++ b/vcl/qa/cppunit/wmf/data/tdf39894.emf diff --git a/vcl/qa/cppunit/wmf/data/tdf39894.wmf b/vcl/qa/cppunit/wmf/data/tdf39894.wmf Binary files differnew file mode 100644 index 000000000000..32e41dee9070 --- /dev/null +++ b/vcl/qa/cppunit/wmf/data/tdf39894.wmf diff --git a/vcl/qa/cppunit/wmf/wmfimporttest.cxx b/vcl/qa/cppunit/wmf/wmfimporttest.cxx index 769830055f24..9315c1e74ea9 100644 --- a/vcl/qa/cppunit/wmf/wmfimporttest.cxx +++ b/vcl/qa/cppunit/wmf/wmfimporttest.cxx @@ -59,6 +59,7 @@ public: void testWorldTransformFontSize(); void testTdf93750(); void testTdf99402(); + void testTdf39894(); CPPUNIT_TEST_SUITE(WmfTest); CPPUNIT_TEST(globalSetUp); @@ -69,6 +70,7 @@ public: CPPUNIT_TEST(testWorldTransformFontSize); CPPUNIT_TEST(testTdf93750); CPPUNIT_TEST(testTdf99402); + CPPUNIT_TEST(testTdf39894); CPPUNIT_TEST_SUITE_END(); }; @@ -266,6 +268,27 @@ void WmfTest::testTdf99402() CPPUNIT_ASSERT_EQUAL(RTL_TEXTENCODING_SYMBOL, fontStyle.aFont.GetCharSet()); } +void WmfTest::testTdf39894() +{ + OUString files[] = { "tdf39894.wmf", "tdf39894.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 x position of the second text must take into account + // the previous text's last Dx (previously was ~300) + auto x = getXPath(pDoc, "/metafile/push[2]/textarray[2]", "x"); + CPPUNIT_ASSERT_MESSAGE(file.toUtf8().getStr(), x.toInt32() > 2700); + } +} + 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 a8118a274744..f5ee19a9abba 100644 --- a/vcl/source/filter/wmf/enhwmf.cxx +++ b/vcl/source/filter/wmf/enhwmf.cxx @@ -1568,17 +1568,20 @@ bool EnhWMFReader::ReadEnhWMF() bool bOffStringSane = nOffString <= nEndPos - nCurPos; if (bLenSane && bOffStringSane) { - if ( offDx && (( nCurPos + offDx + nLen * 4 ) <= nNextPos ) ) + sal_Int32 nDxSize = nLen * ((nOptions & ETO_PDY) ? 8 : 4); + if ( offDx && (( nCurPos + offDx + nDxSize ) <= nNextPos ) && nNextPos <= nEndPos ) { pWMF->Seek( nCurPos + offDx ); - if ( ( nLen * sizeof(sal_uInt32) ) <= ( nEndPos - pWMF->Tell() ) ) + aDX.resize(nLen); + for (sal_Int32 i = 0; i < nLen; ++i) { - 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) { - sal_Int32 val(0); pWMF->ReadInt32(val); - aDX[i] = val; + // TODO: Use Dy value } } } diff --git a/vcl/source/filter/wmf/winmtf.cxx b/vcl/source/filter/wmf/winmtf.cxx index c318956d40d9..3165cee3ffec 100644 --- a/vcl/source/filter/wmf/winmtf.cxx +++ b/vcl/source/filter/wmf/winmtf.cxx @@ -1363,14 +1363,12 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b for (i = 0; i < nLen; i++ ) { - if (i > 0) - { - // #i121382# Map DXArray using WorldTransform - const Size aSize(ImplMap(Size(nSum, 0))); - const basegfx::B2DVector aVector(aSize.Width(), aSize.Height()); - pDXArry[i - 1] = basegfx::fround(aVector.getLength()); - } nSum += 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()); } } if ( mnLatestTextLayoutMode != mnTextLayoutMode ) @@ -1457,7 +1455,7 @@ 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; + sal_Int32 nTextWidth, nActPosDeltaX = 0; pVDev->SetMapMode( MapMode( MapUnit::Map100thMM ) ); pVDev->SetFont( maFont ); if( pDXArry ) @@ -1466,6 +1464,8 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b nTextWidth = pVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) ); if( nLen > 1 ) nTextWidth += pDXArry[ nLen - 2 ]; + // tdf#39894: We should consider the distance to next character cell origin + nActPosDeltaX = pDXArry[ nLen - 1 ]; } else nTextWidth = pVDev->GetTextWidth( rText ); @@ -1481,7 +1481,7 @@ void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, b } if( mnTextAlign & TA_UPDATECP ) - maActPos.X() = rPosition.X() + nTextWidth; + maActPos.X() = rPosition.X() + (pDXArry ? nActPosDeltaX : nTextWidth); } if ( bChangeFont || ( maLatestFont != aTmp ) ) { diff --git a/vcl/source/filter/wmf/winwmf.cxx b/vcl/source/filter/wmf/winwmf.cxx index 72a726ae3c47..7fd1fc7ec2a6 100644 --- a/vcl/source/filter/wmf/winwmf.cxx +++ b/vcl/source/filter/wmf/winwmf.cxx @@ -519,19 +519,13 @@ void WMFReader::ReadRecordParams( sal_uInt16 nFunc ) case W_META_EXTTEXTOUT: { - sal_uInt16 nLen = 0, nOptions = 0; - sal_Int32 nRecordPos, nRecordSize = 0, nOriginalTextLen, nNewTextLen; - Point aPosition; - Rectangle aRect; - std::unique_ptr<long[]> pDXAry; - pWMF->SeekRel(-6); - nRecordPos = pWMF->Tell(); + sal_Int32 nRecordPos = pWMF->Tell(), nRecordSize = 0; pWMF->ReadInt32( nRecordSize ); pWMF->SeekRel(2); - aPosition = ReadYX(); - pWMF->ReadUInt16( nLen ); - pWMF->ReadUInt16( nOptions ); + Point aPosition = ReadYX(); + sal_uInt16 nLen = 0, nOptions = 0; + pWMF->ReadUInt16( nLen ).ReadUInt16( nOptions ); ComplexTextLayoutFlags nTextLayoutMode = ComplexTextLayoutFlags::Default; if ( nOptions & ETO_RTLREADING ) @@ -542,7 +536,8 @@ void WMFReader::ReadRecordParams( sal_uInt16 nFunc ) // output only makes sense if the text contains characters if( nLen ) { - nOriginalTextLen = nLen; + sal_Int32 nOriginalTextLen = nLen; + Rectangle aRect; if( nOptions & ETO_CLIPPED ) { const Point aPt1( ReadPoint() ); @@ -552,11 +547,11 @@ void WMFReader::ReadRecordParams( sal_uInt16 nFunc ) std::unique_ptr<char[]> pChar(new char[ ( nOriginalTextLen + 1 ) &~ 1 ]); pWMF->ReadBytes(pChar.get(), (nOriginalTextLen + 1) &~ 1); OUString aText( pChar.get(), (sal_uInt16)nOriginalTextLen, pOut->GetCharSet() );// after this conversion the text may contain - nNewTextLen = aText.getLength(); // less character (japanese version), so the - pChar.reset(); // dxAry will not fit - + sal_Int32 nNewTextLen = aText.getLength(); // less character (japanese version), so the + // dxAry will not fit if ( nNewTextLen ) { + std::unique_ptr<long[]> pDXAry; sal_uInt32 nMaxStreamPos = nRecordPos + ( nRecordSize << 1 ); sal_Int32 nDxArySize = nMaxStreamPos - pWMF->Tell(); sal_Int32 nDxAryEntries = nDxArySize >> 1; @@ -564,30 +559,41 @@ void WMFReader::ReadRecordParams( sal_uInt16 nFunc ) if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) ) { - sal_Int16 nDx = 0, nDxTmp = 0; - sal_uInt16 i; //needed just outside the for + sal_uInt16 i; // needed just outside the for pDXAry.reset(new long[ nNewTextLen ]); for (i = 0; i < nNewTextLen; i++ ) { if ( pWMF->Tell() >= nMaxStreamPos ) break; - pWMF->ReadInt16( nDx ); + sal_Int32 nDxCount = 1; if ( nNewTextLen != nOriginalTextLen ) { sal_Unicode nUniChar = aText[i]; OString aTmp(&nUniChar, 1, pOut->GetCharSet()); if ( aTmp.getLength() > 1 ) { - sal_Int32 nDxCount = aTmp.getLength() - 1; - if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos ) + nDxCount = aTmp.getLength(); + } + } + + sal_Int16 nDx = 0; + while ( nDxCount-- ) + { + if ( ( pWMF->Tell() + 2 ) > nMaxStreamPos ) + break; + sal_Int16 nDxTmp = 0; + pWMF->ReadInt16(nDxTmp); + nDx += nDxTmp; + if ( nOptions & ETO_PDY ) + { + if ( ( pWMF->Tell() + 2 ) > nMaxStreamPos ) break; - while ( nDxCount-- ) - { - pWMF->ReadInt16( nDxTmp ); - nDx = nDx + nDxTmp; - } + sal_Int16 nDyTmp = 0; + pWMF->ReadInt16(nDyTmp); + // TODO: use Dy offset } } + pDXAry[ i ] = nDx; } if ( i == nNewTextLen ) |