drawinglayer/source/tools/emfphelperdata.cxx | 64 +++++++++++---- drawinglayer/source/tools/emfphelperdata.hxx | 4 emfio/qa/cppunit/emf/EmfImportTest.cxx | 48 +++++++++++ emfio/qa/cppunit/emf/data/TestEmfPlusFillClosedCurve.emf |binary 4 files changed, 98 insertions(+), 18 deletions(-)
New commits: commit 2156c1090d318b4d28bc14537754bea73507d501 Author: Bartosz Kosiorek <gan...@poczta.onet.pl> AuthorDate: Sun May 15 00:09:44 2022 +0200 Commit: Bartosz Kosiorek <gan...@poczta.onet.pl> CommitDate: Mon May 16 17:26:20 2022 +0200 tdf#143876 EMF+ Add DrawClosedCurve and FillClosedCurve support With this commit EmfPlusDrawClosedCurve and EmfPlusFillClosedCurve support was added. There is still missing Filling Mode (it is always set to Even Odd Alternate: https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule ) and Tension support for spline bends. The graphics is displayed as Tension=0. A value of Tension=0 specifies that the spline is a sequence of straight lines. As the value increases, the curve becomes more rounded. For more information, see [SPLINE77] and [PETZOLD]. Change-Id: Ibccfd584e3d55cd0ca8a29da9f450916d56705d5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134333 Tested-by: Jenkins Reviewed-by: Bartosz Kosiorek <gan...@poczta.onet.pl> diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx index 0734dad6d6ea..231e86e7c767 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -80,6 +80,7 @@ namespace emfplushelper case EmfPlusRecordTypeDrawRects: return "EmfPlusRecordTypeDrawRects"; case EmfPlusRecordTypeFillPolygon: return "EmfPlusRecordTypeFillPolygon"; case EmfPlusRecordTypeDrawLines: return "EmfPlusRecordTypeDrawLines"; + case EmfPlusRecordTypeFillClosedCurve: return "EmfPlusRecordTypeFillClosedCurve"; case EmfPlusRecordTypeFillEllipse: return "EmfPlusRecordTypeFillEllipse"; case EmfPlusRecordTypeDrawEllipse: return "EmfPlusRecordTypeDrawEllipse"; case EmfPlusRecordTypeFillPie: return "EmfPlusRecordTypeFillPie"; @@ -89,6 +90,7 @@ namespace emfplushelper case EmfPlusRecordTypeFillPath: return "EmfPlusRecordTypeFillPath"; case EmfPlusRecordTypeDrawPath: return "EmfPlusRecordTypeDrawPath"; case EmfPlusRecordTypeDrawBeziers: return "EmfPlusRecordTypeDrawBeziers"; + case EmfPlusRecordTypeDrawClosedCurve: return "EmfPlusRecordTypeDrawClosedCurve"; case EmfPlusRecordTypeDrawImage: return "EmfPlusRecordTypeDrawImage"; case EmfPlusRecordTypeDrawImagePoints: return "EmfPlusRecordTypeDrawImagePoints"; case EmfPlusRecordTypeDrawString: return "EmfPlusRecordTypeDrawString"; @@ -610,8 +612,11 @@ namespace emfplushelper if (pen->GetColor().IsTransparent()) { drawinglayer::primitive2d::Primitive2DContainer aContainer; - if ((pen->penDataFlags & EmfPlusPenDataStartCap) - || (pen->penDataFlags & EmfPlusPenDataEndCap)) + if (aStart.isDefault() && aEnd.isDefault()) + aContainer.append(drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale)))); + else { aContainer.resize(polygon.count()); for (sal_uInt32 i = 0; i < polygon.count(); i++) @@ -620,18 +625,17 @@ namespace emfplushelper polygon.getB2DPolygon(i), lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale), aStart, aEnd)); } - else - aContainer.append(drawinglayer::primitive2d::Primitive2DReference( - new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale)))); mrTargetHolders.Current().append( new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( std::move(aContainer), (255 - pen->GetColor().GetAlpha()) / 255.0)); } else { - if ((pen->penDataFlags & EmfPlusPenDataStartCap) - || (pen->penDataFlags & EmfPlusPenDataEndCap)) + if (aStart.isDefault() && aEnd.isDefault()) + mrTargetHolders.Current().append( + new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale))); + else for (sal_uInt32 i = 0; i < polygon.count(); i++) { mrTargetHolders.Current().append( @@ -639,10 +643,6 @@ namespace emfplushelper polygon.getB2DPolygon(i), lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale), aStart, aEnd)); } - else - mrTargetHolders.Current().append( - new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale))); } if ((pen->penDataFlags & EmfPlusPenDataCustomStartCap) && (pen->customStartCap->polygon.begin()->count() > 1)) @@ -1393,26 +1393,24 @@ namespace emfplushelper } case EmfPlusRecordTypeFillPolygon: { - const sal_uInt8 index = flags & 0xff; sal_uInt32 brushIndexOrColor, points; rMS.ReadUInt32(brushIndexOrColor); rMS.ReadUInt32(points); - SAL_INFO("drawinglayer.emf", "EMF+\t FillPolygon in slot: " << index << " points: " << points); + SAL_INFO("drawinglayer.emf", "EMF+\t Points: " << points); SAL_INFO("drawinglayer.emf", "EMF+\t " << ((flags & 0x8000) ? "Color" : "Brush index") << " : 0x" << std::hex << brushIndexOrColor << std::dec); EMFPPath path(points, true); path.Read(rMS, flags); EMFPPlusFillPolygon(path.GetPolygon(*this), flags & 0x8000, brushIndexOrColor); - break; } case EmfPlusRecordTypeDrawLines: { sal_uInt32 points; rMS.ReadUInt32(points); - SAL_INFO("drawinglayer.emf", "EMF+\t DrawLines in slot: " << (flags & 0xff) << " points: " << points); + SAL_INFO("drawinglayer.emf", "EMF+\t Points: " << points); EMFPPath path(points, true); path.Read(rMS, flags); @@ -1482,6 +1480,40 @@ namespace emfplushelper } break; } + case EmfPlusRecordTypeDrawClosedCurve: + case EmfPlusRecordTypeFillClosedCurve: + { + // Silent MSVC warning C4701: potentially uninitialized local variable 'brushIndexOrColor' used + sal_uInt32 brushIndexOrColor = 999, points; + float aTension; + if (type == EmfPlusRecordTypeFillClosedCurve) + { + rMS.ReadUInt32(brushIndexOrColor); + SAL_INFO("drawinglayer.emf", + "EMF+\t Fill Mode: " << (flags & 0x2000 ? "Winding" : "Alternate")); + } + rMS.ReadFloat(aTension); + rMS.ReadUInt32(points); + SAL_WARN("drawinglayer.emf", + "EMF+\t Tension: " << aTension << " Points: " << points); + SAL_WARN_IF(aTension != 0, "drawinglayer.emf", + "EMF+\t TODO Add support for tension different than 0"); + SAL_INFO("drawinglayer.emf", + "EMF+\t " << (flags & 0x8000 ? "Color" : "Brush index") << " : 0x" + << std::hex << brushIndexOrColor << std::dec); + + EMFPPath path(points, true); + path.Read(rMS, flags); + if (type == EmfPlusRecordTypeFillClosedCurve) + EMFPPlusFillPolygon(path.GetPolygon(*this, /* bMapIt */ true, + /*bAddLineToCloseShape */ true), + flags & 0x8000, brushIndexOrColor); + else + EMFPPlusDrawPolygon(path.GetPolygon(*this, /* bMapIt */ true, + /*bAddLineToCloseShape */ true), + flags & 0xff); + break; + } case EmfPlusRecordTypeDrawImage: case EmfPlusRecordTypeDrawImagePoints: { diff --git a/drawinglayer/source/tools/emfphelperdata.hxx b/drawinglayer/source/tools/emfphelperdata.hxx index 796cbff03387..ef870f31e687 100644 --- a/drawinglayer/source/tools/emfphelperdata.hxx +++ b/drawinglayer/source/tools/emfphelperdata.hxx @@ -54,8 +54,8 @@ namespace emfplushelper #define EmfPlusRecordTypeFillRegion 0x4013 #define EmfPlusRecordTypeFillPath 0x4014 #define EmfPlusRecordTypeDrawPath 0x4015 - //TODO EmfPlusRecordTypeFillClosedCurve 0x4016 - //TODO EmfPlusRecordTypeDrawClosedCurve 0x4017 + #define EmfPlusRecordTypeFillClosedCurve 0x4016 + #define EmfPlusRecordTypeDrawClosedCurve 0x4017 //TODO EmfPlusRecordTypeDrawCurve 0x4018 #define EmfPlusRecordTypeDrawBeziers 0x4019 #define EmfPlusRecordTypeDrawImage 0x401A diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index 6c5e77bb67dd..cf999c2dff6e 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -68,6 +68,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest: void TestEmfPlusGetDC(); void TestEmfPlusSave(); void TestEmfPlusDrawPathWithMiterLimit(); + void TestEmfPlusFillClosedCurve(); void TestExtTextOutOpaqueAndClipTransform(); void TestBitBltStretchBltWMF(); @@ -117,6 +118,7 @@ public: CPPUNIT_TEST(TestEmfPlusGetDC); CPPUNIT_TEST(TestEmfPlusSave); CPPUNIT_TEST(TestEmfPlusDrawPathWithMiterLimit); + CPPUNIT_TEST(TestEmfPlusFillClosedCurve); CPPUNIT_TEST(TestExtTextOutOpaqueAndClipTransform); CPPUNIT_TEST(TestBitBltStretchBltWMF); @@ -1069,6 +1071,52 @@ void Test::TestEmfPlusDrawPathWithMiterLimit() assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[3]/stroke", 0); } +void Test::TestEmfPlusFillClosedCurve() +{ + // tdf#143876 EMF+ records: SetWorldTransform, FillClosedCurve, DrawClosedCurve + Primitive2DSequence aSequence + = parseEmf(u"emfio/qa/cppunit/emf/data/TestEmfPlusFillClosedCurve.emf"); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength())); + drawinglayer::Primitive2dXmlDump dumper; + xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence)); + CPPUNIT_ASSERT(pDocument); + + assertXPath(pDocument, aXPathPrefix + "polypolygoncolor", 2); + assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[1]", "color", "#808080"); + assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[1]/polypolygon", "path", + "m18202.841744243 13758.4401790456 1269.96570308672 " + "3175.02465670283-2539.93140617345-2116.68310446856h2539.93140617345l-2539." + "93140617345 2116.68310446856z"); + + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke", 2); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "color", "#000000"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "width", "10"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "linejoin", "Miter"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "miterangle", "3"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "linecap", "BUTT"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/polypolygon", "path", + "m18202.841744243 13758.4401790456 1269.96570308672 " + "3175.02465670283-2539.93140617345-2116.68310446856h2539.93140617345l-2539." + "93140617345 2116.68310446856z"); + + assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[2]", "color", "#808080"); + //TODO Check path with implemented Winding + assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[2]/polypolygon", "path", + "m22012.7388535032 13758.4401790456 1269.96570308672 " + "3175.02465670283-2539.93140617344-2116.68310446856h2539.93140617344l-2539." + "93140617344 2116.68310446856z"); + + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "color", "#000000"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "width", "10"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "linejoin", "Miter"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "miterangle", "3"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "linecap", "BUTT"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/polypolygon", "path", + "m22012.7388535032 13758.4401790456 1269.96570308672 " + "3175.02465670283-2539.93140617344-2116.68310446856h2539.93140617344l-2539." + "93140617344 2116.68310446856z"); +} + void Test::TestExtTextOutOpaqueAndClipTransform() { // tdf#142495 EMF records: SETBKCOLOR, SELECTOBJECT, EXTTEXTOUTW, MODIFYWORLDTRANSFORM, CREATEFONTINDIRECT. diff --git a/emfio/qa/cppunit/emf/data/TestEmfPlusFillClosedCurve.emf b/emfio/qa/cppunit/emf/data/TestEmfPlusFillClosedCurve.emf new file mode 100644 index 000000000000..ad9140a770d0 Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestEmfPlusFillClosedCurve.emf differ