summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--emfio/inc/mtftools.hxx3
-rw-r--r--emfio/qa/cppunit/emf/EmfImportTest.cxx113
-rw-r--r--emfio/qa/cppunit/emf/data/TestExtTextOutOpaqueAndClipTransform.emfbin0 -> 1232 bytes
-rw-r--r--emfio/qa/cppunit/wmf/data/TestExtTextOutOpaqueAndClip.wmfbin0 -> 328 bytes
-rw-r--r--emfio/qa/cppunit/wmf/wmfimporttest.cxx18
-rw-r--r--emfio/source/reader/emfreader.cxx37
-rw-r--r--emfio/source/reader/mtftools.cxx35
-rw-r--r--emfio/source/reader/wmfreader.cxx23
8 files changed, 190 insertions, 39 deletions
diff --git a/emfio/inc/mtftools.hxx b/emfio/inc/mtftools.hxx
index 0fb99761d386..cffe5e4fa511 100644
--- a/emfio/inc/mtftools.hxx
+++ b/emfio/inc/mtftools.hxx
@@ -207,11 +207,13 @@ namespace emfio
#define MAC_CHARSET 77
#define BALTIC_CHARSET 186
+#define ETO_OPAQUE 0x0002
#define ETO_CLIPPED 0x0004
/*WINVER >= 0x0400*/
#define ETO_GLYPH_INDEX 0x0010
#define ETO_RTLREADING 0x0080
/*_WIN32_WINNT >= 0x0500*/
+#define ETO_NO_RECT 0x0100
#define ETO_PDY 0x2000
#define DEFAULT_PITCH 0x00
@@ -642,6 +644,7 @@ namespace emfio
void LineTo(const Point& rPoint, bool bRecordPath = false);
void DrawPixel(const Point& rSource, const Color& rColor);
void DrawRect(const tools::Rectangle& rRect, bool bEdge = true);
+ void DrawRectWithBGColor(const tools::Rectangle& rRect);
void DrawRoundRect(const tools::Rectangle& rRect, const Size& rSize);
void DrawEllipse(const tools::Rectangle& rRect);
void DrawArc(
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index 5de9faa36714..1b134551c7ff 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -60,6 +60,9 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest:
void TestEllipseXformIntersectClipRect();
void TestDrawPolyLine16WithClip();
void TestFillRegion();
+ void TestExtTextOutOpaqueAndClipTransform();
+
+ void TestExtTextOutOpaqueAndClipWMF();
void TestPaletteWMF();
void TestRoundrectWMF();
void TestPolylinetoCloseStroke();
@@ -91,6 +94,8 @@ public:
CPPUNIT_TEST(TestEllipseXformIntersectClipRect);
CPPUNIT_TEST(TestDrawPolyLine16WithClip);
CPPUNIT_TEST(TestFillRegion);
+ CPPUNIT_TEST(TestExtTextOutOpaqueAndClipTransform);
+ CPPUNIT_TEST(TestExtTextOutOpaqueAndClipWMF);
CPPUNIT_TEST(TestPaletteWMF);
CPPUNIT_TEST(TestRoundrectWMF);
CPPUNIT_TEST(TestPolylinetoCloseStroke);
@@ -504,6 +509,114 @@ void Test::TestPolylinetoCloseStroke()
"color", "#000000");
}
+
+void Test::TestExtTextOutOpaqueAndClipTransform()
+{
+ // tdf#142495 EMF records: SETBKCOLOR, SELECTOBJECT, EXTTEXTOUTW, MODIFYWORLDTRANSFORM, CREATEFONTINDIRECT.
+ Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestExtTextOutOpaqueAndClipTransform.emf");
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
+ drawinglayer::Primitive2dXmlDump dumper;
+ xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence));
+ CPPUNIT_ASSERT (pDocument);
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion",
+ "text", "No_rect- DLP-");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion",
+ "fontcolor", "#000000");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/polypolygoncolor", 2);
+ assertXPath(pDocument, "/primitive2D/metafile/transform/polypolygoncolor[1]/polypolygon",
+ "path", "m966 490-477-275-84 147 476 275z");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/polypolygoncolor[1]",
+ "color", "#ff0000");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/polypolygoncolor[2]/polypolygon",
+ "path", "m251 713 623 361-148 257-623-361z");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/polypolygoncolor[2]",
+ "color", "#0080ff");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group", 3);
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[1]/polypolygoncolor",
+ "color", "#ff0000");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[1]/textsimpleportion",
+ "text", "Opaque - DLP-");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[1]/textsimpleportion",
+ "fontcolor", "#000000");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[2]/mask/group/polypolygoncolor",
+ "color", "#00ff00");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[2]/mask/polypolygon",
+ "path", "m320 508 586 340-169 293-586-339z");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[2]/mask/group/textsimpleportion",
+ "text", "Clip - DLP-");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[2]/mask/group/textsimpleportion",
+ "fontcolor", "#000000");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[3]/mask/group/polypolygoncolor",
+ "color", "#0080ff");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[3]/mask/polypolygon",
+ "path", "m251 713 623 361-148 257-623-361z");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[3]/mask/group/textsimpleportion",
+ "text", "Opaque ClipP-");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/group[3]/mask/group/textsimpleportion",
+ "fontcolor", "#000000");
+}
+
+void Test::TestExtTextOutOpaqueAndClipWMF()
+{
+ // tdf#53004 WMF records: SETBKCOLOR, SELECTOBJECT, EXTTEXTOUT, CREATEBRUSHINDIRECT.
+ Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/wmf/data/TestExtTextOutOpaqueAndClip.wmf");
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
+ drawinglayer::Primitive2dXmlDump dumper;
+ xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence));
+ CPPUNIT_ASSERT (pDocument);
+
+#ifdef MACOSX
+ // On some operating systems (Linux on LO Jenkins CI), the `/mask/` string is not added to XPath
+ // As a result tests are failing. On my Ubuntu 20.04 the `/mask/` string was added
+ // I would leave this test case for macOS to make sure there is no regression at least on one platform.
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor", 5);
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[1]/polypolygon",
+ "path", "m7219 1825h319v3608h-319z");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[1]",
+ "color", "#ff0000");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[2]/polypolygon",
+ "path", "m7219 5942h319v318h-319z");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[2]",
+ "color", "#00ff00");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[3]/polypolygon",
+ "path", "m10149 5942h319v318h-319z");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[3]",
+ "color", "#8080ff");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group", 5);
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[1]/polypolygoncolor",
+ "color", "#00ff00");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[1]/textsimpleportion",
+ "text", "ABCD");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[1]/textsimpleportion",
+ "fontcolor", "#000000");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[2]/polypolygoncolor",
+ "color", "#8080ff");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[2]/textsimpleportion",
+ "text", "MMMM");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[2]/textsimpleportion",
+ "fontcolor", "#000000");
+
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[3]/mask/group/polypolygoncolor",
+ "color", "#ff8000");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[3]/mask/group/polypolygoncolor/polypolygon",
+ "path", "m1062 1061h1270v473h-1270z");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[3]/mask/group/textsimpleportion",
+ "text", "OOOO");
+ assertXPath(pDocument, "/primitive2D/metafile/transform/mask/group[3]/mask/group/textsimpleportion",
+ "fontcolor", "#000000");
+#endif
+}
+
void Test::TestPaletteWMF()
{
// WMF import with records: CREATEPALETTE, SELECTOBJECT, CREATEPENINDIRECT, CREATEBRUSHINDIRECT, ELLIPSE.
diff --git a/emfio/qa/cppunit/emf/data/TestExtTextOutOpaqueAndClipTransform.emf b/emfio/qa/cppunit/emf/data/TestExtTextOutOpaqueAndClipTransform.emf
new file mode 100644
index 000000000000..7d59ac3e5bd2
--- /dev/null
+++ b/emfio/qa/cppunit/emf/data/TestExtTextOutOpaqueAndClipTransform.emf
Binary files differ
diff --git a/emfio/qa/cppunit/wmf/data/TestExtTextOutOpaqueAndClip.wmf b/emfio/qa/cppunit/wmf/data/TestExtTextOutOpaqueAndClip.wmf
new file mode 100644
index 000000000000..fb6fd20f0cb4
--- /dev/null
+++ b/emfio/qa/cppunit/wmf/data/TestExtTextOutOpaqueAndClip.wmf
Binary files differ
diff --git a/emfio/qa/cppunit/wmf/wmfimporttest.cxx b/emfio/qa/cppunit/wmf/wmfimporttest.cxx
index 41c15e3989f8..62a669fe3676 100644
--- a/emfio/qa/cppunit/wmf/wmfimporttest.cxx
+++ b/emfio/qa/cppunit/wmf/wmfimporttest.cxx
@@ -206,7 +206,7 @@ void WmfTest::testWorldTransformFontSize()
CPPUNIT_ASSERT(pDoc);
- assertXPath(pDoc, "/metafile/font", 8);
+ assertXPath(pDoc, "/metafile/font", 9);
assertXPath(pDoc, "/metafile/font[1]", "color", "#595959");
assertXPath(pDoc, "/metafile/font[1]", "width", "0");
@@ -214,13 +214,19 @@ void WmfTest::testWorldTransformFontSize()
assertXPath(pDoc, "/metafile/font[1]", "orientation", "0");
assertXPath(pDoc, "/metafile/font[1]", "weight", "bold");
- // World transform should not affect font size. Rotating text for 90 degrees
- // should not exchange font width and height.
assertXPath(pDoc, "/metafile/font[3]", "color", "#000000");
assertXPath(pDoc, "/metafile/font[3]", "width", "0");
- assertXPath(pDoc, "/metafile/font[3]", "height", "530");
- assertXPath(pDoc, "/metafile/font[3]", "orientation", "900");
- assertXPath(pDoc, "/metafile/font[3]", "weight", "normal");
+ assertXPath(pDoc, "/metafile/font[3]", "height", "389");
+ assertXPath(pDoc, "/metafile/font[3]", "orientation", "0");
+ assertXPath(pDoc, "/metafile/font[3]", "weight", "bold");
+
+ // World transform should not affect font size. Rotating text for 90 degrees
+ // should not exchange font width and height.
+ assertXPath(pDoc, "/metafile/font[4]", "color", "#000000");
+ assertXPath(pDoc, "/metafile/font[4]", "width", "0");
+ assertXPath(pDoc, "/metafile/font[4]", "height", "530");
+ assertXPath(pDoc, "/metafile/font[4]", "orientation", "900");
+ assertXPath(pDoc, "/metafile/font[4]", "weight", "normal");
}
void WmfTest::testTdf93750()
diff --git a/emfio/source/reader/emfreader.cxx b/emfio/source/reader/emfreader.cxx
index 9a8784c7e631..e6a758175fb5 100644
--- a/emfio/source/reader/emfreader.cxx
+++ b/emfio/source/reader/emfreader.cxx
@@ -1795,14 +1795,18 @@ namespace emfio
[[fallthrough]];
case EMR_EXTTEXTOUTW :
{
- sal_Int32 nLeft, nTop, nRight, nBottom, ptlReferenceX, ptlReferenceY, nGfxMode, nXScale, nYScale;
- sal_uInt32 nOffString, nOptions, offDx;
- sal_Int32 nLen;
+ sal_Int32 nLeft, nTop, nRight, nBottom;
+ sal_uInt32 nGfxMode;
+ float nXScale, nYScale;
+ sal_Int32 ptlReferenceX, ptlReferenceY;
+ sal_uInt32 nLen, nOffString, nOptions, offDx;
+ sal_Int32 nLeftRect, nTopRect, nRightRect, nBottomRect;
nCurPos = mpInputStream->Tell() - 8;
- mpInputStream->ReadInt32( nLeft ).ReadInt32( nTop ).ReadInt32( nRight ).ReadInt32( nBottom ).ReadInt32( nGfxMode ).ReadInt32( nXScale ).ReadInt32( nYScale )
- .ReadInt32( ptlReferenceX ).ReadInt32( ptlReferenceY ).ReadInt32( nLen ).ReadUInt32( nOffString ).ReadUInt32( nOptions );
+ mpInputStream->ReadInt32( nLeft ).ReadInt32( nTop ).ReadInt32( nRight ).ReadInt32( nBottom )
+ .ReadUInt32( nGfxMode ).ReadFloat( nXScale ).ReadFloat( nYScale )
+ .ReadInt32( ptlReferenceX ).ReadInt32( ptlReferenceY ).ReadUInt32( nLen ).ReadUInt32( nOffString ).ReadUInt32( nOptions );
SAL_INFO("emfio", "\t\tBounds: " << nLeft << ", " << nTop << ", " << nRight << ", " << nBottom);
SAL_INFO("emfio", "\t\tiGraphicsMode: 0x" << std::hex << nGfxMode << std::dec);
@@ -1810,7 +1814,13 @@ namespace emfio
SAL_INFO("emfio", "\t\teyScale: " << nYScale);
SAL_INFO("emfio", "\t\tReference: (" << ptlReferenceX << ", " << ptlReferenceY << ")");
- mpInputStream->SeekRel( 0x10 );
+ mpInputStream->ReadInt32( nLeftRect ).ReadInt32( nTopRect ).ReadInt32( nRightRect ).ReadInt32( nBottomRect );
+ const tools::Rectangle aRect( nLeftRect, nTopRect, nRightRect, nBottomRect );
+ BkMode mnBkModeBackup = mnBkMode;
+ if ( nOptions & ETO_NO_RECT ) // Don't draw the background rectangle
+ mnBkMode = BkMode::Transparent;
+ if ( nOptions & ETO_OPAQUE )
+ DrawRectWithBGColor( aRect );
mpInputStream->ReadUInt32( offDx );
ComplexTextLayoutFlags nTextLayoutMode = ComplexTextLayoutFlags::Default;
@@ -1820,15 +1830,14 @@ namespace emfio
SAL_WARN_IF( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) != 0, "emfio", "SJ: ETO_PDY || ETO_GLYPH_INDEX in EMF" );
Point aPos( ptlReferenceX, ptlReferenceY );
- bool bLenSane = nLen > 0 && nLen < static_cast<sal_Int32>( SAL_MAX_UINT32 / sizeof(sal_Int32) );
bool bOffStringSane = nOffString <= mnEndPos - nCurPos;
- if (bLenSane && bOffStringSane)
+ if ( bOffStringSane )
{
mpInputStream->Seek( nCurPos + nOffString );
OUString aText;
if ( bFlag )
{
- if ( nLen <= static_cast<sal_Int32>( mnEndPos - mpInputStream->Tell() ) )
+ if ( nLen <= ( mnEndPos - mpInputStream->Tell() ) )
{
std::unique_ptr<char[]> pBuf(new char[ nLen ]);
mpInputStream->ReadBytes(pBuf.get(), nLen);
@@ -1862,7 +1871,7 @@ namespace emfio
for (sal_Int32 i = 0; i < aText.getLength(); ++i)
{
sal_Int32 nDxCount = 1;
- if (aText.getLength() != nLen)
+ if (aText.getLength() != static_cast<sal_Int32>( nLen ) )
{
sal_Unicode cUniChar = aText[i];
OString aTmp(&cUniChar, 1, GetCharSet());
@@ -1894,7 +1903,15 @@ namespace emfio
}
}
}
+ if ( nOptions & ETO_CLIPPED )
+ {
+ Push(); // Save the current clip. It will be restored after text drawing
+ IntersectClipRect( aRect );
+ }
DrawText(aPos, aText, pDXAry.get(), pDYAry.get(), mbRecordPath, nGfxMode);
+ if ( nOptions & ETO_CLIPPED )
+ Pop();
+ mnBkMode = mnBkModeBackup;
}
}
break;
diff --git a/emfio/source/reader/mtftools.cxx b/emfio/source/reader/mtftools.cxx
index d68e36e361ef..6bf0d98a3e76 100644
--- a/emfio/source/reader/mtftools.cxx
+++ b/emfio/source/reader/mtftools.cxx
@@ -1051,14 +1051,8 @@ namespace emfio
{
return; // empty rectangles cause trouble
}
- Point aPoints[] { Point(rRect.Left(), rRect.Top()),
- Point(rRect.Right(), rRect.Top()),
- Point(rRect.Right(), rRect.Bottom()),
- Point(rRect.Left(), rRect.Bottom()) };
- tools::Polygon aPoly(4, aPoints);
- aPoly = ImplMap( aPoly );
- aPoly.Optimize( PolyOptimizeFlags::CLOSE );
- tools::PolyPolygon aPolyPolyRect( aPoly );
+ tools::Polygon aPoly( rRect );
+ const tools::PolyPolygon aPolyPolyRect( ImplMap( aPoly ) );
maClipPath.intersectClip( aPolyPolyRect.getB2DPolyPolygon() );
}
@@ -1067,15 +1061,8 @@ namespace emfio
if (utl::ConfigManager::IsFuzzing())
return;
mbClipNeedsUpdate=true;
-
- Point aPoints[] { Point(rRect.Left(), rRect.Top()),
- Point(rRect.Right(), rRect.Top()),
- Point(rRect.Right(), rRect.Bottom()),
- Point(rRect.Left(), rRect.Bottom()) };
- tools::Polygon aPoly(4, aPoints);
- aPoly = ImplMap( aPoly );
- aPoly.Optimize( PolyOptimizeFlags::CLOSE );
- tools::PolyPolygon aPolyPolyRect( aPoly );
+ tools::Polygon aPoly( rRect );
+ const tools::PolyPolygon aPolyPolyRect( ImplMap( aPoly ) );
maClipPath.excludeClip( aPolyPolyRect.getB2DPolyPolygon() );
}
@@ -1390,6 +1377,20 @@ namespace emfio
maActPos = aDest;
}
+ void MtfTools::DrawRectWithBGColor(const tools::Rectangle& rRect)
+ {
+ WinMtfFillStyle aFillStyleBackup = maFillStyle;
+ bool aTransparentBackup = maLineStyle.bTransparent;
+
+ const tools::Polygon aPoly( rRect );
+ maLineStyle.bTransparent = true;
+ maFillStyle = maBkColor;
+ ImplSetNonPersistentLineColorTransparenz();
+ DrawPolygon(aPoly, false);
+ maFillStyle = aFillStyleBackup;
+ maLineStyle.bTransparent = aTransparentBackup;
+ }
+
void MtfTools::DrawRect( const tools::Rectangle& rRect, bool bEdge )
{
UpdateClipRegion();
diff --git a/emfio/source/reader/wmfreader.cxx b/emfio/source/reader/wmfreader.cxx
index 2f0aafabfaa9..f14949135ad4 100644
--- a/emfio/source/reader/wmfreader.cxx
+++ b/emfio/source/reader/wmfreader.cxx
@@ -666,8 +666,9 @@ namespace emfio
Point aPosition = ReadYX();
sal_uInt16 nLen = 0, nOptions = 0;
mpInputStream->ReadUInt16( nLen ).ReadUInt16( nOptions );
-
- if (nOptions & ETO_CLIPPED)
+ SAL_INFO( "emfio", "\t\t\t Pos: " << aPosition.getX() << ":" << aPosition.getY() << " String Length: " << nLen << " Options: " << nOptions );
+ tools::Rectangle aRect;
+ if ( ( nOptions & ETO_CLIPPED ) || ( nOptions & ETO_OPAQUE ) )
{
nNonStringLen += 2 * sizeof(sal_uInt16);
@@ -676,10 +677,12 @@ namespace emfio
SAL_WARN("emfio", "W_META_TEXTOUT too short");
break;
}
-
- ReadPoint();
- ReadPoint();
- SAL_WARN("emfio", "clipping unsupported");
+ const Point aTopLeft = ReadPoint();
+ const Point aBottomRight = ReadPoint();
+ aRect = tools::Rectangle( aTopLeft, aBottomRight );
+ if ( nOptions & ETO_OPAQUE )
+ DrawRectWithBGColor( aRect );
+ SAL_INFO( "emfio", "\t\t\t Rectangle : " << aTopLeft.getX() << ":" << aTopLeft.getY() << ", " << aBottomRight.getX() << ":" << aBottomRight.getY() );
}
ComplexTextLayoutFlags nTextLayoutMode = ComplexTextLayoutFlags::Default;
@@ -709,6 +712,12 @@ namespace emfio
// dxAry will not fit
if ( nNewTextLen )
{
+ if ( nOptions & ETO_CLIPPED )
+ {
+ Push(); // Save the current clip. It will be restored after text drawing
+ IntersectClipRect( aRect );
+ }
+ SAL_INFO( "emfio", "\t\t\t Text : " << aText );
std::unique_ptr<tools::Long[]> pDXAry, pDYAry;
auto nDxArySize = nMaxStreamPos - mpInputStream->Tell();
auto nDxAryEntries = nDxArySize >> 1;
@@ -768,6 +777,8 @@ namespace emfio
DrawText( aPosition, aText, pDXAry.get(), pDYAry.get() );
else
DrawText( aPosition, aText );
+ if ( nOptions & ETO_CLIPPED )
+ Pop();
}
}
}