drawinglayer/source/tools/emfphelperdata.cxx | 144 ++++++++++---- drawinglayer/source/tools/emfphelperdata.hxx | 4 drawinglayer/source/tools/emfppen.cxx | 17 - drawinglayer/source/tools/emfppen.hxx | 1 drawinglayer/source/tools/primitive2dxmldump.cxx | 44 ++++ emfio/qa/cppunit/emf/EmfImportTest.cxx | 116 +++++++++-- emfio/qa/cppunit/emf/data/TestDrawLine.emf |binary emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithCaps.emf |binary 8 files changed, 260 insertions(+), 66 deletions(-)
New commits: commit 1440ab87386bb5d1ad3634082577bf27f279e066 Author: Bartosz Kosiorek <gan...@poczta.onet.pl> AuthorDate: Sun Apr 24 02:29:59 2022 +0200 Commit: Bartosz Kosiorek <gan...@poczta.onet.pl> CommitDate: Mon May 9 20:50:37 2022 +0200 tdf#143875 tdf#55058 EMF+ Add support for individual line endings EMF+ is allowing different caps and arrows on both ends It is not possible to implement that with css::drawing::LineCap, as it is set line endings on both line start and line end. Additionally when the Dash Pattern is used, the css::drawing::LineCap is also applied there. To resolve that limitation, the Cap needs to be implemented independetly by using PolygonStrokeArrowPrimitive2D, and the css::drawing::LineCap inside drawinglayer::attribute::LineAttribute always set to css::drawing::LineCap_BUTT Change-Id: I4be76e2dbefcb34154a1404c3b57dc4b7f7ada85 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133299 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 c405a4c4876b..c5b282998d71 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -29,6 +29,7 @@ #include "emfpstringformat.hxx" #include <basegfx/curve/b2dcubicbezier.hxx> #include <wmfemfhelper.hxx> +#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx> #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> #include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx> #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> @@ -519,7 +520,72 @@ namespace emfplushelper } } - void EmfPlusHelperData::EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon, sal_uInt32 penIndex) + drawinglayer::attribute::LineStartEndAttribute + EmfPlusHelperData::CreateLineEnd(const sal_Int32 aCap, const float aPenWidth) const + { + const double pw = mdExtractedYScale * aPenWidth; + if (aCap == LineCapTypeSquare) + { + basegfx::B2DPolygon aCapPolygon( + { {-1.0, -1.0}, {1.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} }); + aCapPolygon.setClosed(true); + return drawinglayer::attribute::LineStartEndAttribute( + pw, basegfx::B2DPolyPolygon(aCapPolygon), true); + } + else if (aCap == LineCapTypeRound) + { + basegfx::B2DPolygon aCapPolygon( + { {-1.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.9236, -0.3827}, + {0.7071, -0.7071}, {0.3827, -0.9236}, {0.0, -1.0}, {-0.3827, -0.9236}, + {-0.7071, -0.7071}, {-0.9236, -0.3827}, {-1.0, 0.0} }); + aCapPolygon.setClosed(true); + return drawinglayer::attribute::LineStartEndAttribute( + pw, basegfx::B2DPolyPolygon(aCapPolygon), true); + } + else if (aCap == LineCapTypeTriangle) + { + basegfx::B2DPolygon aCapPolygon( + { {-1.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, -1.0}, {-1.0, 0.0} }); + aCapPolygon.setClosed(true); + return drawinglayer::attribute::LineStartEndAttribute( + pw, basegfx::B2DPolyPolygon(aCapPolygon), true); + } + else if (aCap == LineCapTypeSquareAnchor) + { + basegfx::B2DPolygon aCapPolygon( + { {-1.0, -1.0}, {1.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} }); + aCapPolygon.setClosed(true); + return drawinglayer::attribute::LineStartEndAttribute( + 1.5 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true); + } + else if (aCap == LineCapTypeRoundAnchor) + { + const basegfx::B2DPolygon aCapPolygon + = ::basegfx::utils::createPolygonFromEllipse(::basegfx::B2DPoint(0.0, 0.0), 1.0, 1.0); + return drawinglayer::attribute::LineStartEndAttribute( + 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true); + } + else if (aCap == LineCapTypeDiamondAnchor) + { + basegfx::B2DPolygon aCapPolygon({ {0.0, -1.0}, {1.0, 0.0}, {0.5, 0.5}, + {0.5, 1.0}, {-0.5, 1.0}, {-0.5, 0.5}, + {-1.0, 0.0} }); + aCapPolygon.setClosed(true); + return drawinglayer::attribute::LineStartEndAttribute( + 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true); + } + else if (aCap == LineCapTypeArrowAnchor) + { + basegfx::B2DPolygon aCapPolygon({ {0.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} }); + aCapPolygon.setClosed(true); + return drawinglayer::attribute::LineStartEndAttribute( + 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true); + } + return drawinglayer::attribute::LineStartEndAttribute(); + } + + void EmfPlusHelperData::EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon, + sal_uInt32 penIndex) { const EMFPPen* pen = dynamic_cast<EMFPPen*>(maEMFPObjects[penIndex & 0xff].get()); SAL_WARN_IF(!pen, "drawinglayer.emf", "emf+ missing pen"); @@ -527,40 +593,56 @@ namespace emfplushelper if (!(pen && polygon.count())) return; - // we need a line cap attribute - css::drawing::LineCap lineCap = css::drawing::LineCap_BUTT; - if (pen->penDataFlags & EmfPlusPenDataStartCap) // additional line cap information - { - lineCap = static_cast<css::drawing::LineCap>(EMFPPen::lcl_convertStrokeCap(pen->startCap)); - SAL_WARN_IF(pen->startCap != pen->endCap, "drawinglayer.emf", "emf+ pen uses different start and end cap"); - } - const double transformedPenWidth = mdExtractedYScale * pen->penWidth; - drawinglayer::attribute::LineAttribute lineAttribute(pen->GetColor().getBColor(), - transformedPenWidth, - pen->GetLineJoinType(), - lineCap, - basegfx::deg2rad(15.0)); // TODO Add MiterLimit support - if (!pen->GetColor().IsTransparent()) + drawinglayer::attribute::LineAttribute lineAttribute( + pen->GetColor().getBColor(), transformedPenWidth, pen->GetLineJoinType(), + css::drawing::LineCap_BUTT, + basegfx::deg2rad(15.0)); // TODO Add MiterLimit support + + drawinglayer::attribute::LineStartEndAttribute aStart; + if (pen->penDataFlags & EmfPlusPenDataStartCap) + aStart = EmfPlusHelperData::CreateLineEnd(pen->startCap, pen->penWidth); + + drawinglayer::attribute::LineStartEndAttribute aEnd; + if (pen->penDataFlags & EmfPlusPenDataEndCap) + aEnd = EmfPlusHelperData::CreateLineEnd(pen->endCap, pen->penWidth); + + if (pen->GetColor().IsTransparent()) { + drawinglayer::primitive2d::Primitive2DContainer aContainer; + if ((pen->penDataFlags & EmfPlusPenDataStartCap) + || (pen->penDataFlags & EmfPlusPenDataEndCap)) + { + aContainer.resize(polygon.count()); + for (sal_uInt32 i = 0; i < polygon.count(); i++) + aContainer[i] = drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::PolygonStrokeArrowPrimitive2D( + 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::PolyPolygonStrokePrimitive2D( - polygon, - lineAttribute, - pen->GetStrokeAttribute(mdExtractedXScale))); + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + std::move(aContainer), (255 - pen->GetColor().GetAlpha()) / 255.0)); } else { - const drawinglayer::primitive2d::Primitive2DReference aPrimitive( - new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - polygon, - lineAttribute, - pen->GetStrokeAttribute(mdExtractedXScale))); - - mrTargetHolders.Current().append( - new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( - drawinglayer::primitive2d::Primitive2DContainer { aPrimitive }, - (255 - pen->GetColor().GetAlpha()) / 255.0)); + if ((pen->penDataFlags & EmfPlusPenDataStartCap) + || (pen->penDataFlags & EmfPlusPenDataEndCap)) + for (sal_uInt32 i = 0; i < polygon.count(); i++) + { + mrTargetHolders.Current().append( + new drawinglayer::primitive2d::PolygonStrokeArrowPrimitive2D( + 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)) @@ -604,7 +686,7 @@ namespace emfplushelper new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( startCapPolygon, lineAttribute, - pen->GetStrokeAttribute(maMapTransform.get(1, 1)))); + pen->GetStrokeAttribute(mdExtractedXScale))); } } @@ -649,7 +731,7 @@ namespace emfplushelper new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( endCapPolygon, lineAttribute, - pen->GetStrokeAttribute(maMapTransform.get(1, 1)))); + pen->GetStrokeAttribute(mdExtractedXScale))); } } diff --git a/drawinglayer/source/tools/emfphelperdata.hxx b/drawinglayer/source/tools/emfphelperdata.hxx index 600f666145af..796cbff03387 100644 --- a/drawinglayer/source/tools/emfphelperdata.hxx +++ b/drawinglayer/source/tools/emfphelperdata.hxx @@ -21,6 +21,7 @@ #include <wmfemfhelper.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/attribute/linestartendattribute.hxx> #include <tools/stream.hxx> #include <basegfx/point/b2dpoint.hxx> #include <map> @@ -232,6 +233,9 @@ namespace emfplushelper void GraphicStatePush(GraphicStateMap& map, sal_Int32 index); void GraphicStatePop(GraphicStateMap& map, sal_Int32 index); + drawinglayer::attribute::LineStartEndAttribute CreateLineEnd(const sal_Int32 aCap, + const float aPenWidth) const; + // primitive creators void EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon, sal_uInt32 penIndex); void EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon& polygon, const bool isColor, const sal_uInt32 brushIndexOrColor); diff --git a/drawinglayer/source/tools/emfppen.cxx b/drawinglayer/source/tools/emfppen.cxx index b927ac186174..b0408f8d0e80 100644 --- a/drawinglayer/source/tools/emfppen.cxx +++ b/drawinglayer/source/tools/emfppen.cxx @@ -173,23 +173,6 @@ namespace emfplushelper return ""; } - /// Convert stroke caps between EMF+ and rendering API - sal_Int8 EMFPPen::lcl_convertStrokeCap(sal_uInt32 nEmfStroke) - { - switch (nEmfStroke) - { - case EmfPlusLineCapTypeSquare: - return rendering::PathCapType::SQUARE; - // we have no mapping for EmfPlusLineCapTypeTriangle, - // but it is similar to Round - case EmfPlusLineCapTypeTriangle: // fall-through - case EmfPlusLineCapTypeRound: - return rendering::PathCapType::ROUND; - } - - return rendering::PathCapType::BUTT; - } - basegfx::B2DLineJoin EMFPPen::GetLineJoinType() const { if (penDataFlags & EmfPlusPenDataJoin) // additional line join information diff --git a/drawinglayer/source/tools/emfppen.hxx b/drawinglayer/source/tools/emfppen.hxx index a22ae14fc247..cad849e4f278 100644 --- a/drawinglayer/source/tools/emfppen.hxx +++ b/drawinglayer/source/tools/emfppen.hxx @@ -123,7 +123,6 @@ namespace emfplushelper void Read(SvStream& s, EmfPlusHelperData const & rR); - static sal_Int8 lcl_convertStrokeCap(sal_uInt32 nEmfStroke); drawinglayer::attribute::StrokeAttribute GetStrokeAttribute(const double aTransformation) const; basegfx::B2DLineJoin GetLineJoinType() const; }; diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx b/drawinglayer/source/tools/primitive2dxmldump.cxx index 3074ad30690a..886ffbf7fdd3 100644 --- a/drawinglayer/source/tools/primitive2dxmldump.cxx +++ b/drawinglayer/source/tools/primitive2dxmldump.cxx @@ -23,6 +23,7 @@ #include <drawinglayer/primitive2d/Tools.hxx> #include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx> +#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx> #include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx> #include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx> #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> @@ -722,6 +723,49 @@ void Primitive2dXmlDump::decomposeAndWrite( rWriter.endElement(); } break; + + case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D: + { + const PolygonStrokeArrowPrimitive2D& rPolygonStrokeArrowPrimitive2D + = dynamic_cast<const PolygonStrokeArrowPrimitive2D&>(*pBasePrimitive); + rWriter.startElement("polygonstrokearrow"); + + rWriter.startElement("polygon"); + rWriter.content(basegfx::utils::exportToSvgPoints( + rPolygonStrokeArrowPrimitive2D.getB2DPolygon())); + rWriter.endElement(); + + if (rPolygonStrokeArrowPrimitive2D.getStart().getB2DPolyPolygon().count()) + { + rWriter.startElement("linestartattribute"); + rWriter.attribute("width", + rPolygonStrokeArrowPrimitive2D.getStart().getWidth()); + rWriter.attribute("centered", + static_cast<sal_Int32>( + rPolygonStrokeArrowPrimitive2D.getStart().isCentered())); + writePolyPolygon(rWriter, + rPolygonStrokeArrowPrimitive2D.getStart().getB2DPolyPolygon()); + rWriter.endElement(); + } + + if (rPolygonStrokeArrowPrimitive2D.getEnd().getB2DPolyPolygon().count()) + { + rWriter.startElement("lineendattribute"); + rWriter.attribute("width", rPolygonStrokeArrowPrimitive2D.getEnd().getWidth()); + rWriter.attribute("centered", + static_cast<sal_Int32>( + rPolygonStrokeArrowPrimitive2D.getEnd().isCentered())); + writePolyPolygon(rWriter, + rPolygonStrokeArrowPrimitive2D.getEnd().getB2DPolyPolygon()); + rWriter.endElement(); + } + + writeLineAttribute(rWriter, rPolygonStrokeArrowPrimitive2D.getLineAttribute()); + writeStrokeAttribute(rWriter, rPolygonStrokeArrowPrimitive2D.getStrokeAttribute()); + rWriter.endElement(); + } + break; + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: { const PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index 5891799dd607..f83688745e02 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -51,6 +51,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest: void TestDrawStringTransparent(); void TestDrawStringWithBrush(); void TestDrawLine(); + void TestDrawLineWithCaps(); void TestDrawLineWithDash(); void TestLinearGradient(); void TestTextMapMode(); @@ -98,6 +99,7 @@ public: CPPUNIT_TEST(TestDrawStringTransparent); CPPUNIT_TEST(TestDrawStringWithBrush); CPPUNIT_TEST(TestDrawLine); + CPPUNIT_TEST(TestDrawLineWithCaps); CPPUNIT_TEST(TestDrawLineWithDash); CPPUNIT_TEST(TestLinearGradient); CPPUNIT_TEST(TestTextMapMode); @@ -155,6 +157,7 @@ Primitive2DSequence Test::parseEmf(std::u16string_view aSource) SvFileStream aFileStream(aUrl, StreamMode::READ); std::size_t nSize = aFileStream.remainingSize(); + CPPUNIT_ASSERT_MESSAGE("Unable to open file", nSize); std::unique_ptr<sal_Int8[]> pBuffer(new sal_Int8[nSize + 1]); aFileStream.ReadBytes(pBuffer.get(), nSize); pBuffer[nSize] = 0; @@ -379,30 +382,91 @@ void Test::TestDrawLine() { // EMF+ with records: DrawLine // The line is colored and has a specified width, therefore a polypolygonstroke primitive is the optimal choice - Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestDrawLine.emf"); + Primitive2DSequence aSequence = parseEmf(u"emfio/qa/cppunit/emf/data/TestDrawLine.emf"); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength())); drawinglayer::Primitive2dXmlDump dumper; xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence)); CPPUNIT_ASSERT(pDocument); // check correct import of the DrawLine: color and width of the line - assertXPath(pDocument, aXPathPrefix + "polypolygonstroke/line", "color", "#000000"); - assertXPath(pDocument, aXPathPrefix + "polypolygonstroke/line", "width", "23"); + assertXPath(pDocument, aXPathPrefix + "mask/unifiedtransparence", "transparence", "14"); + assertXPath(pDocument, aXPathPrefix + "mask/unifiedtransparence/polypolygonstroke/line", + "color", "#c01002"); + assertXPath(pDocument, aXPathPrefix + "mask/unifiedtransparence/polypolygonstroke/line", + "width", "115"); + assertXPath(pDocument, aXPathPrefix + "mask/unifiedtransparence/polypolygonstroke/line", + "linecap", "BUTT"); + assertXPath(pDocument, aXPathPrefix + "mask/unifiedtransparence/polypolygonstroke/polypolygon", + "path", "m55.5192348773662 403.573503917507 874.352660545936-345.821325648415"); +} + +void Test::TestDrawLineWithCaps() +{ + // EMF+ with records: DrawLine + // Test lines with different caps styles and arrows + Primitive2DSequence aSequence + = parseEmf(u"emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithCaps.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 + "polygonstrokearrow", 3); + + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[1]/line", "width", "211"); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[1]/stroke", 0); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[1]/linestartattribute/polypolygon", + "path", "m0-1 1 2h-2z"); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[1]/lineendattribute", 0); + + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[2]/line", "width", "211"); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[2]/stroke", 0); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[2]/linestartattribute/polypolygon", + "path", "m0-1 1 2h-2z"); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[2]/lineendattribute", 0); + + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[3]/line", "width", "423"); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[3]/stroke", 0); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[3]/linestartattribute", 0); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow[3]/lineendattribute/polypolygon", + "path", "m-1-1h2v2h-2z"); + + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence", 3); + assertXPath(pDocument, aXPathPrefix + "unifiedtransparence[1]", "transparence", "39"); + assertXPath(pDocument, + aXPathPrefix + + "unifiedtransparence[1]/polygonstrokearrow/linestartattribute/polypolygon", + "path", + "m-1 1h2v-1l-0.0764-0.3827-0.2165-0.3244-0.3244-0.2165-0.3827-0.0764-0.3827 " + "0.0764-0.3244 0.2165-0.2165 0.3244-0.0764 0.3827z"); + assertXPath(pDocument, + aXPathPrefix + + "unifiedtransparence[1]/polygonstrokearrow/lineendattribute/polypolygon", + "path", "m-1 1h2v-1l-1-1-1 1z"); + assertXPath(pDocument, + aXPathPrefix + "unifiedtransparence[2]/polygonstrokearrow/linestartattribute", 0); + assertXPath(pDocument, + aXPathPrefix + + "unifiedtransparence[2]/polygonstrokearrow/lineendattribute/polypolygon", + "path", "m-1-1h2v2h-2z"); + assertXPath(pDocument, + aXPathPrefix + + "unifiedtransparence[3]/polygonstrokearrow/lineendattribute/polypolygon", + "path", "m0-1 1 1-0.5 0.5v0.5h-1v-0.5l-0.5-0.5z"); } void Test::TestDrawLineWithDash() { // EMF+ with records: DrawLine, ScaleWorldTransform, RotateWorldTransform - // Test lines with different dash styles and different World Rotation + // Test lines with different dash styles, different line arrows and different World Rotation Primitive2DSequence aSequence - = parseEmf(u"/emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithDash.emf"); + = parseEmf(u"emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithDash.emf"); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength())); drawinglayer::Primitive2dXmlDump dumper; xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence)); CPPUNIT_ASSERT(pDocument); // check correct import of the DrawLine: color and width of the line - assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke", 12); + assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke", 10); assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[1]/line", "color", "#000000"); assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[1]/line", "width", "185"); assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[1]/stroke", 0); @@ -419,14 +483,30 @@ void Test::TestDrawLineWithDash() assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[5]/line", "width", "370"); assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[5]/stroke", "dotDashArray", "556 185 185 185 185 185 "); + + assertXPath(pDocument, aXPathPrefix + "mask/polygonstrokearrow", 2); //TODO polypolygonstroke[6-9]/stroke add support for PenDataDashedLineOffset - assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[10]/line", "width", "370"); - assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[10]/stroke", "dotDashArray", - "1851 741 5554 1481 "); - assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[11]/line", "width", "370"); - assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[11]/stroke", "dotDashArray", + assertXPath(pDocument, aXPathPrefix + "mask/polygonstrokearrow[1]/line", "width", "370"); + assertXPath(pDocument, aXPathPrefix + "mask/polygonstrokearrow[1]/stroke", "dotDashArray", "1851 741 5554 1481 "); - assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke[12]/line", "width", "370"); + // Arrows on both ends + assertXPath(pDocument, + aXPathPrefix + "mask/polygonstrokearrow[1]/linestartattribute/polypolygon", "path", + "m0-1 1 2h-2z"); + assertXPath(pDocument, aXPathPrefix + "mask/polygonstrokearrow[1]/lineendattribute/polypolygon", + "path", "m0-1 1 2h-2z"); + + assertXPath(pDocument, aXPathPrefix + "mask/polygonstrokearrow[2]/line", "width", "370"); + assertXPath(pDocument, aXPathPrefix + "mask/polygonstrokearrow[2]/stroke", "dotDashArray", + "1852 741 5555 1481 "); + assertXPath(pDocument, + aXPathPrefix + "mask/polygonstrokearrow[2]/linestartattribute/polypolygon", "path", + "m-1 1h2v-1l-0.0764-0.3827-0.2165-0.3244-0.3244-0.2165-0.3827-0.0764-0.3827 " + "0.0764-0.3244 0.2165-0.2165 0.3244-0.0764 0.3827z"); + assertXPath(pDocument, aXPathPrefix + "mask/polygonstrokearrow[2]/lineendattribute/polypolygon", + "path", + "m-1 1h2v-1l-0.0764-0.3827-0.2165-0.3244-0.3244-0.2165-0.3827-0.0764-0.3827 " + "0.0764-0.3244 0.2165-0.2165 0.3244-0.0764 0.3827z"); } void Test::TestLinearGradient() @@ -878,7 +958,7 @@ void Test::TestPolylinetoCloseStroke() void Test::TestEmfPlusGetDC() { // tdf#147818 EMF+ records: GetDC, DrawPath, FillRects - Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestEmfPlusGetDC.emf"); + Primitive2DSequence aSequence = parseEmf(u"emfio/qa/cppunit/emf/data/TestEmfPlusGetDC.emf"); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength())); drawinglayer::Primitive2dXmlDump dumper; xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence)); @@ -910,7 +990,8 @@ void Test::TestEmfPlusGetDC() "m19428.4895833333 6632.22222222222h317.34375v-2398.88888888889h-317.34375z"); assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[6]", "color", "#fcf2e3"); - assertXPath(pDocument, aXPathPrefix + "polypolygonstroke", 15); + assertXPath(pDocument, aXPathPrefix + "polypolygonstroke", 4); + assertXPath(pDocument, aXPathPrefix + "polygonstrokearrow", 13); } void Test::TestEmfPlusSave() @@ -932,9 +1013,10 @@ void Test::TestEmfPlusSave() "m10853.4145539602 7321.41354709201h41952690v29630720h-41952690z"); assertXPath(pDocument, aXPathPrefix + "mask/polypolygoncolor", "color", "#00ffad"); - assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke/line", "color", "#000000"); - assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke/polypolygon", "path", - "m10853.4145539602 7321.41354709201v-2413.87029012044h1979.24116969109"); + assertXPath(pDocument, aXPathPrefix + "mask/polygonstrokearrow/line", "color", "#000000"); + assertXPathContent(pDocument, aXPathPrefix + "mask/polygonstrokearrow/polygon", + "10853.4145539602,7321.41354709201 10853.4145539602,4907.54325697157 " + "12832.6557236512,4907.54325697157"); } void Test::TestExtTextOutOpaqueAndClipTransform() diff --git a/emfio/qa/cppunit/emf/data/TestDrawLine.emf b/emfio/qa/cppunit/emf/data/TestDrawLine.emf index 89946c523f98..8d8c620b2c81 100644 Binary files a/emfio/qa/cppunit/emf/data/TestDrawLine.emf and b/emfio/qa/cppunit/emf/data/TestDrawLine.emf differ diff --git a/emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithCaps.emf b/emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithCaps.emf new file mode 100644 index 000000000000..1b4cedb63514 Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithCaps.emf differ