drawinglayer/source/tools/emfphelperdata.cxx | 4 drawinglayer/source/tools/emfppen.cxx | 23 +++- drawinglayer/source/tools/emfppen.hxx | 2 drawinglayer/source/tools/primitive2dxmldump.cxx | 5 + emfio/qa/cppunit/emf/EmfImportTest.cxx | 50 ++++++++++ emfio/qa/cppunit/emf/data/TestEmfPlusDrawPathWithMiterLimit.emf |binary 6 files changed, 76 insertions(+), 8 deletions(-)
New commits: commit e709ebe42ad06974b822366e4eea1a6c2ee61e10 Author: Bartosz Kosiorek <gan...@poczta.onet.pl> AuthorDate: Wed May 11 12:54:48 2022 +0200 Commit: Bartosz Kosiorek <gan...@poczta.onet.pl> CommitDate: Fri May 13 13:49:18 2022 +0200 tdf#142261 EMF+ Add support for Miter Limit With this commit the Miter is properly implemented, according to [EMF-PLUS] documentation: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-emfplus/5ef071f3-f503-4f16-b027-7c4bcf2d1d81 The formula for stroke miter limit is described here: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit Change-Id: Ida87063cc045460e61ffae118f64cf133c810dbf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134164 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 c5b282998d71..4d0db58c026b 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -596,8 +596,8 @@ namespace emfplushelper const double transformedPenWidth = mdExtractedYScale * pen->penWidth; drawinglayer::attribute::LineAttribute lineAttribute( pen->GetColor().getBColor(), transformedPenWidth, pen->GetLineJoinType(), - css::drawing::LineCap_BUTT, - basegfx::deg2rad(15.0)); // TODO Add MiterLimit support + css::drawing::LineCap_BUTT, //TODO implement PenDataDashedLineCap supportr here + pen->fMiterMinimumAngle); drawinglayer::attribute::LineStartEndAttribute aStart; if (pen->penDataFlags & EmfPlusPenDataStartCap) diff --git a/drawinglayer/source/tools/emfppen.cxx b/drawinglayer/source/tools/emfppen.cxx index b0408f8d0e80..ec073d56ea59 100644 --- a/drawinglayer/source/tools/emfppen.cxx +++ b/drawinglayer/source/tools/emfppen.cxx @@ -58,7 +58,7 @@ namespace emfplushelper , startCap(0) , endCap(0) , lineJoin(0) - , miterLimit(0.0) + , fMiterMinimumAngle(basegfx::deg2rad(5.0)) , dashStyle(0) , dashCap(0) , dashOffset(0.0) @@ -286,13 +286,26 @@ namespace emfplushelper if (penDataFlags & PenDataMiterLimit) { + float miterLimit; s.ReadFloat(miterLimit); - SAL_WARN("drawinglayer.emf", "EMF+\t\tTODO PenDataMiterLimit: " << std::dec << miterLimit); + + // EMF+ JoinTypeMiterClipped is working as our B2DLineJoin::Miter + // For EMF+ LineJoinTypeMiter we are simulating it by changing angle + if (lineJoin == EmfPlusLineJoinTypeMiter) + miterLimit = 3.0 * miterLimit; + // asin angle must be in range [-1, 1] + if (abs(miterLimit) > 1.0) + fMiterMinimumAngle = 2.0 * asin(1.0 / miterLimit); + else + // enable miter limit for all angles + fMiterMinimumAngle = basegfx::deg2rad(180.0); + SAL_INFO("drawinglayer.emf", + "EMF+\t\t MiterLimit: " << std::dec << miterLimit + << ", Miter minimum angle (rad): " << fMiterMinimumAngle); } else - { - miterLimit = 0; - } + fMiterMinimumAngle = basegfx::deg2rad(5.0); + if (penDataFlags & PenDataLineStyle) { diff --git a/drawinglayer/source/tools/emfppen.hxx b/drawinglayer/source/tools/emfppen.hxx index cad849e4f278..6a7929f332f8 100644 --- a/drawinglayer/source/tools/emfppen.hxx +++ b/drawinglayer/source/tools/emfppen.hxx @@ -105,7 +105,7 @@ namespace emfplushelper sal_Int32 startCap; sal_Int32 endCap; sal_Int32 lineJoin; - float miterLimit; + double fMiterMinimumAngle; sal_Int32 dashStyle; sal_Int32 dashCap; float dashOffset; diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx b/drawinglayer/source/tools/primitive2dxmldump.cxx index 886ffbf7fdd3..4e35d599876f 100644 --- a/drawinglayer/source/tools/primitive2dxmldump.cxx +++ b/drawinglayer/source/tools/primitive2dxmldump.cxx @@ -167,8 +167,12 @@ void writeLineAttribute(::tools::XmlWriter& rWriter, rWriter.attribute("linejoin", "Bevel"); break; case basegfx::B2DLineJoin::Miter: + { rWriter.attribute("linejoin", "Miter"); + rWriter.attribute("miterangle", + basegfx::rad2deg(rLineAttribute.getMiterMinimumAngle())); break; + } case basegfx::B2DLineJoin::Round: rWriter.attribute("linejoin", "Round"); break; @@ -191,6 +195,7 @@ void writeLineAttribute(::tools::XmlWriter& rWriter, rWriter.attribute("linecap", "Unknown"); break; } + rWriter.endElement(); } diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index f83688745e02..6c5e77bb67dd 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -67,6 +67,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest: void TestFillRegion(); void TestEmfPlusGetDC(); void TestEmfPlusSave(); + void TestEmfPlusDrawPathWithMiterLimit(); void TestExtTextOutOpaqueAndClipTransform(); void TestBitBltStretchBltWMF(); @@ -115,6 +116,7 @@ public: CPPUNIT_TEST(TestFillRegion); CPPUNIT_TEST(TestEmfPlusGetDC); CPPUNIT_TEST(TestEmfPlusSave); + CPPUNIT_TEST(TestEmfPlusDrawPathWithMiterLimit); CPPUNIT_TEST(TestExtTextOutOpaqueAndClipTransform); CPPUNIT_TEST(TestBitBltStretchBltWMF); @@ -1019,6 +1021,54 @@ void Test::TestEmfPlusSave() "12832.6557236512,4907.54325697157"); } +void Test::TestEmfPlusDrawPathWithMiterLimit() +{ + // tdf#142261 EMF+ records: DrawPath, TranslateWorldTransform, Object (Brush, Pen, Path) + // Check if Miter is correctly set for Lines + Primitive2DSequence aSequence + = parseEmf(u"emfio/qa/cppunit/emf/data/TestEmfPlusDrawPathWithMiterLimit.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 + "polypolygonstroke", 3); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "color", "#c800c8"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "width", "1057"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "linejoin", "Miter"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", "miterangle", "5"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/stroke", 0); + + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence", 3); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[1]", "transparence", "85"); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[1]/polypolygonstroke/line", "color", + "#6400c8"); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[1]/polypolygonstroke/line", "width", + "1057"); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[1]/polypolygonstroke/line", + "linejoin", "Miter"); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[1]/polypolygonstroke/line", + "miterangle", "19"); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[2]", "transparence", "69"); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[2]/polypolygonstroke/line", + "miterangle", "19"); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[3]", "transparence", "53"); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[3]/polypolygonstroke/line", + "miterangle", "19"); + + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "color", "#0000ff"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "width", "1057"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "linejoin", "Miter"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", "miterangle", "60"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/stroke", 0); + + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[3]/line", "color", "#0000ff"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[3]/line", "width", "1057"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[3]/line", "linejoin", "Miter"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[3]/line", "miterangle", "60"); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[3]/stroke", 0); +} + void Test::TestExtTextOutOpaqueAndClipTransform() { // tdf#142495 EMF records: SETBKCOLOR, SELECTOBJECT, EXTTEXTOUTW, MODIFYWORLDTRANSFORM, CREATEFONTINDIRECT. diff --git a/emfio/qa/cppunit/emf/data/TestEmfPlusDrawPathWithMiterLimit.emf b/emfio/qa/cppunit/emf/data/TestEmfPlusDrawPathWithMiterLimit.emf new file mode 100644 index 000000000000..e8e46486384b Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestEmfPlusDrawPathWithMiterLimit.emf differ