summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2016-12-29 11:45:38 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2016-12-29 12:17:48 +0000
commitfa96ffbc6b51154533557e2b4e03a611ebf09b6c (patch)
tree34747643161fa4272b7722d963d86b7b549848b1 /vcl
parent767ec2f138d824b6b51eef73ac9b7d2b193a1e98 (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>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/qa/cppunit/wmf/data/ETO_PDY.emfbin0 -> 1644 bytes
-rw-r--r--vcl/qa/cppunit/wmf/data/ETO_PDY.wmfbin0 -> 306 bytes
-rw-r--r--vcl/qa/cppunit/wmf/wmfimporttest.cxx26
-rw-r--r--vcl/source/filter/wmf/enhwmf.cxx82
-rw-r--r--vcl/source/filter/wmf/winmtf.cxx111
-rw-r--r--vcl/source/filter/wmf/winmtf.hxx1
-rw-r--r--vcl/source/filter/wmf/winwmf.cxx20
7 files changed, 156 insertions, 84 deletions
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 000000000000..065698eaff2c
--- /dev/null
+++ b/vcl/qa/cppunit/wmf/data/ETO_PDY.emf
Binary files 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 000000000000..bd97740698e3
--- /dev/null
+++ b/vcl/qa/cppunit/wmf/data/ETO_PDY.wmf
Binary files differ
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 );
}