compilerplugins/clang/redundantfcast.cxx                  |    3 
 drawinglayer/source/tools/emfpcustomlinecap.cxx           |    9 -
 drawinglayer/source/tools/emfpcustomlinecap.hxx           |    2 
 drawinglayer/source/tools/emfphelperdata.cxx              |   62 +-----------
 drawinglayer/source/tools/emfppen.cxx                     |   70 +++++++++++---
 drawinglayer/source/tools/emfppen.hxx                     |    5 -
 drawinglayer/source/tools/primitive2dxmldump.cxx          |   32 ++++--
 emfio/qa/cppunit/emf/EmfImportTest.cxx                    |   34 ++++++
 emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithDash.emf |binary
 svx/qa/unit/svdraw.cxx                                    |    3 
 10 files changed, 127 insertions(+), 93 deletions(-)

New commits:
commit 547ac0aa23a25f03a17014cb474eedc1fd88017f
Author:     Bartosz Kosiorek <gan...@poczta.onet.pl>
AuthorDate: Wed Apr 20 19:44:05 2022 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Fri Apr 22 16:13:54 2022 +0200

    tdf#55058 tdf#143875 EMF+ Fix display of dashed lines and line joints
    
    With previous implementation, empty spaces between dashes
    were too long.
    Additionally line joints were not working correctly, after
    EMF+ reworking: tdf#111486
    
    This commit fixes all these issues and additionally it is
    covering it with tests.
    Change-Id: I9404e566d2d7d3405ab817268ad9b1f538c200eb
    
    Change-Id: I523f92a928ab592ff175d0d01c1ad1a3bc22e324
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133207
    Tested-by: Jenkins
    Reviewed-by: Bartosz Kosiorek <gan...@poczta.onet.pl>
    (cherry picked from commit 80c856336668e35837667323957fa3ad4172f3c0)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133152

diff --git a/compilerplugins/clang/redundantfcast.cxx 
b/compilerplugins/clang/redundantfcast.cxx
index 67ff2c56edef..85386eb4ea8e 100644
--- a/compilerplugins/clang/redundantfcast.cxx
+++ b/compilerplugins/clang/redundantfcast.cxx
@@ -334,6 +334,9 @@ public:
         // tdf#145203: FIREBIRD cannot create a table
         if (fn == SRCDIR 
"/connectivity/source/drivers/firebird/DatabaseMetaData.cxx")
             return false;
+        // false positive during using contructor 
drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw })
+        if (fn == SRCDIR "/drawinglayer/source/tools/emfppen.cxx")
+            return false;
         return true;
     }
 
diff --git a/drawinglayer/source/tools/emfpcustomlinecap.cxx 
b/drawinglayer/source/tools/emfpcustomlinecap.cxx
index e24cbcc32cb1..49cc912ed33c 100644
--- a/drawinglayer/source/tools/emfpcustomlinecap.cxx
+++ b/drawinglayer/source/tools/emfpcustomlinecap.cxx
@@ -43,15 +43,6 @@ namespace emfplushelper
     {
     }
 
-    void EMFPCustomLineCap::SetAttributes(rendering::StrokeAttributes& 
aAttributes)
-    {
-        aAttributes.StartCapType = 
EMFPPen::lcl_convertStrokeCap(strokeStartCap);
-        aAttributes.EndCapType = EMFPPen::lcl_convertStrokeCap(strokeEndCap);
-        aAttributes.JoinType = EMFPPen::lcl_convertLineJoinType(strokeJoin);
-
-        aAttributes.MiterLimit = miterLimit;
-    }
-
     void EMFPCustomLineCap::ReadPath(SvStream& s, EmfPlusHelperData const & 
rR, bool bFill)
     {
         sal_Int32 pathLength;
diff --git a/drawinglayer/source/tools/emfpcustomlinecap.hxx 
b/drawinglayer/source/tools/emfpcustomlinecap.hxx
index a42e0ab4ef46..e6202ae98179 100644
--- a/drawinglayer/source/tools/emfpcustomlinecap.hxx
+++ b/drawinglayer/source/tools/emfpcustomlinecap.hxx
@@ -19,7 +19,6 @@
 
 #pragma once
 
-#include <com/sun/star/rendering/StrokeAttributes.hpp>
 #include "emfphelperdata.hxx"
 
 namespace emfplushelper
@@ -34,7 +33,6 @@ namespace emfplushelper
 
         EMFPCustomLineCap();
 
-        void SetAttributes(com::sun::star::rendering::StrokeAttributes& 
aAttributes);
         void ReadPath(SvStream& s, EmfPlusHelperData const & rR, bool bFill);
         void Read(SvStream& s, EmfPlusHelperData const & rR);
     };
diff --git a/drawinglayer/source/tools/emfphelperdata.cxx 
b/drawinglayer/source/tools/emfphelperdata.cxx
index 447686167837..79ced761e8a2 100644
--- a/drawinglayer/source/tools/emfphelperdata.cxx
+++ b/drawinglayer/source/tools/emfphelperdata.cxx
@@ -509,13 +509,6 @@ namespace emfplushelper
         if (!(pen && polygon.count()))
             return;
 
-        // we need a line join attribute
-        basegfx::B2DLineJoin lineJoin = basegfx::B2DLineJoin::Round;
-        if (pen->penDataFlags & EmfPlusPenDataJoin) // additional line join 
information
-        {
-            lineJoin = 
static_cast<basegfx::B2DLineJoin>(EMFPPen::lcl_convertLineJoinType(pen->lineJoin));
-        }
-
         // we need a line cap attribute
         css::drawing::LineCap lineCap = css::drawing::LineCap_BUTT;
         if (pen->penDataFlags & EmfPlusPenDataStartCap) // additional line cap 
information
@@ -527,57 +520,16 @@ namespace emfplushelper
         const double transformedPenWidth = maMapTransform.get(0, 0) * 
pen->penWidth;
         drawinglayer::attribute::LineAttribute 
lineAttribute(pen->GetColor().getBColor(),
                                                              
transformedPenWidth,
-                                                             lineJoin,
-                                                             lineCap);
-
-        drawinglayer::attribute::StrokeAttribute aStrokeAttribute;
-        if (pen->penDataFlags & EmfPlusPenDataLineStyle && pen->dashStyle != 
EmfPlusLineStyleCustom) // pen has a predefined line style
-        {
-            // short writing
-            const double pw = maMapTransform.get(1, 1) * pen->penWidth;
-            // taken from the old cppcanvas implementation and multiplied with 
pen width
-            const std::vector<double> dash = { 3*pw, 3*pw };
-            const std::vector<double> dot = { pw, 3*pw };
-            const std::vector<double> dashdot = { 3*pw, 3*pw, pw, 3*pw };
-            const std::vector<double> dashdotdot = { 3*pw, 3*pw, pw, 3*pw, pw, 
3*pw };
-
-            switch (pen->dashStyle)
-            {
-                case EmfPlusLineStyleSolid: // do nothing special, use default 
stroke attribute
-                    break;
-                case EmfPlusLineStyleDash:
-                    aStrokeAttribute = 
drawinglayer::attribute::StrokeAttribute(std::vector(dash));
-                    break;
-                case EmfPlusLineStyleDot:
-                    aStrokeAttribute = 
drawinglayer::attribute::StrokeAttribute(std::vector(dot));
-                    break;
-                case EmfPlusLineStyleDashDot:
-                    aStrokeAttribute = 
drawinglayer::attribute::StrokeAttribute(std::vector(dashdot));
-                    break;
-                case EmfPlusLineStyleDashDotDot:
-                    aStrokeAttribute = 
drawinglayer::attribute::StrokeAttribute(std::vector(dashdotdot));
-                    break;
-            }
-        }
-        else if (pen->penDataFlags & EmfPlusPenDataDashedLine) // pen has a 
custom dash line
-        {
-            // StrokeAttribute needs a double vector while the pen provides a 
float vector
-            std::vector<double> aPattern(pen->dashPattern.size());
-            for (size_t i=0; i<aPattern.size(); i++)
-            {
-                // convert from float to double and multiply with the adjusted 
pen width
-                aPattern[i] = maMapTransform.get(1, 1) * pen->penWidth * 
pen->dashPattern[i];
-            }
-            aStrokeAttribute = 
drawinglayer::attribute::StrokeAttribute(std::move(aPattern));
-        }
-
+                                                             
pen->GetLineJoinType(),
+                                                             lineCap,
+                                                             
basegfx::deg2rad(15.0)); // TODO Add MiterLimit support
         if (!pen->GetColor().IsTransparent())
         {
             mrTargetHolders.Current().append(
                 new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
                     polygon,
                     lineAttribute,
-                    aStrokeAttribute));
+                    pen->GetStrokeAttribute(maMapTransform.get(1, 1))));
         }
         else
         {
@@ -585,7 +537,7 @@ namespace emfplushelper
                         new 
drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
                             polygon,
                             lineAttribute,
-                            aStrokeAttribute));
+                            pen->GetStrokeAttribute(maMapTransform.get(1, 
1))));
 
             mrTargetHolders.Current().append(
                         new 
drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
@@ -634,7 +586,7 @@ namespace emfplushelper
                             new 
drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
                                 startCapPolygon,
                                 lineAttribute,
-                                aStrokeAttribute));
+                                pen->GetStrokeAttribute(maMapTransform.get(1, 
1))));
             }
         }
 
@@ -679,7 +631,7 @@ namespace emfplushelper
                             new 
drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
                                 endCapPolygon,
                                 lineAttribute,
-                                aStrokeAttribute));
+                                pen->GetStrokeAttribute(maMapTransform.get(1, 
1))));
             }
         }
 
diff --git a/drawinglayer/source/tools/emfppen.cxx 
b/drawinglayer/source/tools/emfppen.cxx
index d41dca676d4e..f348391b0519 100644
--- a/drawinglayer/source/tools/emfppen.cxx
+++ b/drawinglayer/source/tools/emfppen.cxx
@@ -18,7 +18,6 @@
  */
 
 #include <com/sun/star/rendering/PathCapType.hpp>
-#include <com/sun/star/rendering/PathJoinType.hpp>
 #include <o3tl/safeint.hxx>
 #include <sal/log.hxx>
 #include <rtl/ustrbuf.hxx>
@@ -179,27 +178,70 @@ namespace emfplushelper
     {
         switch (nEmfStroke)
         {
-            case EmfPlusLineCapTypeSquare: return 
rendering::PathCapType::SQUARE;
-            case EmfPlusLineCapTypeRound:  return 
rendering::PathCapType::ROUND;
+            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;
         }
 
-        // we have no mapping for EmfPlusLineCapTypeTriangle = 0x00000003,
-        // so return BUTT always
         return rendering::PathCapType::BUTT;
     }
 
-    sal_Int8 EMFPPen::lcl_convertLineJoinType(sal_uInt32 nEmfLineJoin)
+    basegfx::B2DLineJoin EMFPPen::GetLineJoinType() const
     {
-        switch (nEmfLineJoin)
+        if (penDataFlags & EmfPlusPenDataJoin) // additional line join 
information
         {
-            case EmfPlusLineJoinTypeMiter:        // fall-through
-            case EmfPlusLineJoinTypeMiterClipped: return 
rendering::PathJoinType::MITER;
-            case EmfPlusLineJoinTypeBevel:        return 
rendering::PathJoinType::BEVEL;
-            case EmfPlusLineJoinTypeRound:        return 
rendering::PathJoinType::ROUND;
+            switch (lineJoin)
+            {
+                case EmfPlusLineJoinTypeMiter: // fall-through
+                case EmfPlusLineJoinTypeMiterClipped:
+                    return basegfx::B2DLineJoin::Miter;
+                case EmfPlusLineJoinTypeBevel:
+                    return basegfx::B2DLineJoin::Bevel;
+                case EmfPlusLineJoinTypeRound:
+                    return basegfx::B2DLineJoin::Round;
+            }
         }
+        // If nothing set, then miter applied with no limit
+        return basegfx::B2DLineJoin::Miter;
+    }
 
-        assert(false); // Line Join type isn't in specification.
-        return 0;
+    drawinglayer::attribute::StrokeAttribute
+    EMFPPen::GetStrokeAttribute(const double aTransformation) const
+    {
+        if (penDataFlags & EmfPlusPenDataLineStyle // pen has a predefined 
line style
+            && dashStyle != EmfPlusLineStyleCustom)
+        {
+            const double pw = aTransformation * penWidth;
+            switch (dashStyle)
+            {
+                case EmfPlusLineStyleDash:
+                    return drawinglayer::attribute::StrokeAttribute({ 3 * pw, 
pw });
+                case EmfPlusLineStyleDot:
+                    return drawinglayer::attribute::StrokeAttribute({ pw, pw 
});
+                case EmfPlusLineStyleDashDot:
+                    return drawinglayer::attribute::StrokeAttribute({ 3 * pw, 
pw, pw, pw });
+                case EmfPlusLineStyleDashDotDot:
+                    return drawinglayer::attribute::StrokeAttribute({ 3 * pw, 
pw, pw, pw, pw, pw });
+            }
+        }
+        else if (penDataFlags & EmfPlusPenDataDashedLine) // pen has a custom 
dash line
+        {
+            const double pw = aTransformation * penWidth;
+            // StrokeAttribute needs a double vector while the pen provides a 
float vector
+            std::vector<double> aPattern(dashPattern.size());
+            for (size_t i = 0; i < aPattern.size(); i++)
+            {
+                // convert from float to double and multiply with the adjusted 
pen width
+                aPattern[i] = pw * dashPattern[i];
+            }
+            return 
drawinglayer::attribute::StrokeAttribute(std::move(aPattern));
+        }
+        //  EmfPlusLineStyleSolid: - do nothing special, use default stroke 
attribute
+        return drawinglayer::attribute::StrokeAttribute();
     }
 
     void EMFPPen::Read(SvStream& s, EmfPlusHelperData const & rR)
@@ -249,7 +291,7 @@ namespace emfplushelper
         if (penDataFlags & PenDataJoin)
         {
             s.ReadInt32(lineJoin);
-            SAL_WARN("drawinglayer.emf", "EMF+\t\tTODO PenDataJoin: " << 
LineJoinTypeToString(lineJoin) << " (0x" << std::hex << lineJoin << ")");
+            SAL_WARN("drawinglayer.emf", "EMF+\t\t LineJoin: " << 
LineJoinTypeToString(lineJoin) << " (0x" << std::hex << lineJoin << ")");
         }
         else
         {
diff --git a/drawinglayer/source/tools/emfppen.hxx 
b/drawinglayer/source/tools/emfppen.hxx
index 05b2fc376d7d..29ece63ecf5d 100644
--- a/drawinglayer/source/tools/emfppen.hxx
+++ b/drawinglayer/source/tools/emfppen.hxx
@@ -19,6 +19,7 @@
 
 #pragma once
 
+#include <drawinglayer/attribute/strokeattribute.hxx>
 #include "emfpbrush.hxx"
 #include <vector>
 
@@ -26,6 +27,7 @@ namespace emfplushelper
 {
     const sal_uInt32 EmfPlusLineCapTypeSquare = 0x00000001;
     const sal_uInt32 EmfPlusLineCapTypeRound = 0x00000002;
+    const sal_uInt32 EmfPlusLineCapTypeTriangle = 0x00000003;
 
     const sal_uInt32 EmfPlusLineJoinTypeMiter = 0x00000000;
     const sal_uInt32 EmfPlusLineJoinTypeBevel = 0x00000001;
@@ -122,7 +124,8 @@ namespace emfplushelper
         void Read(SvStream& s, EmfPlusHelperData const & rR);
 
         static sal_Int8 lcl_convertStrokeCap(sal_uInt32 nEmfStroke);
-        static sal_Int8 lcl_convertLineJoinType(sal_uInt32 nEmfLineJoin);
+        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 2e2bb887a3d4..a1fddf900543 100644
--- a/drawinglayer/source/tools/primitive2dxmldump.cxx
+++ b/drawinglayer/source/tools/primitive2dxmldump.cxx
@@ -13,6 +13,7 @@
 #include <tools/stream.hxx>
 #include <tools/XmlWriter.hxx>
 
+#include <math.h>
 #include <memory>
 #include <sal/log.hxx>
 
@@ -132,6 +133,24 @@ void writePolyPolygon(::tools::XmlWriter& rWriter, const 
basegfx::B2DPolyPolygon
     rWriter.endElement();
 }
 
+void writeStrokeAttribute(::tools::XmlWriter& rWriter,
+                          const drawinglayer::attribute::StrokeAttribute& 
rStrokeAttribute)
+{
+    if (!rStrokeAttribute.getDotDashArray().empty())
+    {
+        rWriter.startElement("stroke");
+
+        OUString sDotDash;
+        for (double fDotDash : rStrokeAttribute.getDotDashArray())
+        {
+            sDotDash += OUString::number(round(100.0 * fDotDash)) + " ";
+        }
+        rWriter.attribute("dotDashArray", sDotDash);
+        rWriter.attribute("fullDotDashLength", 
rStrokeAttribute.getFullDotDashLen());
+        rWriter.endElement();
+    }
+}
+
 void writeLineAttribute(::tools::XmlWriter& rWriter,
                         const drawinglayer::attribute::LineAttribute& 
rLineAttribute)
 {
@@ -718,14 +737,7 @@ void Primitive2dXmlDump::decomposeAndWrite(
                 rWriter.endElement();
 
                 writeLineAttribute(rWriter, 
rPolygonStrokePrimitive2D.getLineAttribute());
-
-                rWriter.startElement("stroke");
-                const drawinglayer::attribute::StrokeAttribute& 
aStrokeAttribute
-                    = rPolygonStrokePrimitive2D.getStrokeAttribute();
-                rWriter.attribute("fulldotdashlen", 
aStrokeAttribute.getFullDotDashLen());
-                //rWriter.attribute("dotdasharray", 
aStrokeAttribute.getDotDashArray());
-                rWriter.endElement();
-
+                writeStrokeAttribute(rWriter, 
rPolygonStrokePrimitive2D.getStrokeAttribute());
                 rWriter.endElement();
             }
             break;
@@ -736,9 +748,7 @@ void Primitive2dXmlDump::decomposeAndWrite(
                 rWriter.startElement("polypolygonstroke");
 
                 writeLineAttribute(rWriter, 
rPolyPolygonStrokePrimitive2D.getLineAttribute());
-
-                //getStrokeAttribute()
-
+                writeStrokeAttribute(rWriter, 
rPolyPolygonStrokePrimitive2D.getStrokeAttribute());
                 writePolyPolygon(rWriter, 
rPolyPolygonStrokePrimitive2D.getB2DPolyPolygon());
 
                 rWriter.endElement();
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx 
b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index 799f8eef9c46..63661c9c73c2 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -52,6 +52,7 @@ class Test : public test::BootstrapFixture, public 
XmlTestTools, public unotest:
     void TestDrawStringTransparent();
     void TestDrawStringWithBrush();
     void TestDrawLine();
+    void TestDrawLineWithDash();
     void TestLinearGradient();
     void TestTextMapMode();
     void TestEnglishMapMode();
@@ -95,6 +96,7 @@ public:
     CPPUNIT_TEST(TestDrawStringTransparent);
     CPPUNIT_TEST(TestDrawStringWithBrush);
     CPPUNIT_TEST(TestDrawLine);
+    CPPUNIT_TEST(TestDrawLineWithDash);
     CPPUNIT_TEST(TestLinearGradient);
     CPPUNIT_TEST(TestTextMapMode);
     CPPUNIT_TEST(TestEnglishMapMode);
@@ -390,6 +392,38 @@ void Test::TestDrawLine()
     assertXPath(pDocument, aXPathPrefix + "polypolygonstroke/line", "width", 
"33");
 }
 
+void Test::TestDrawLineWithDash()
+{
+    // EMF+ with records: DrawLine
+    // The lines with different dash styles
+    Primitive2DSequence aSequence
+        = 
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(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence));
+    CPPUNIT_ASSERT(pDocument);
+
+    // check correct import of the DrawLine: color and width of the line
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke", 10);
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", 
"color", "#000000");
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/line", 
"width", "132");
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[1]/stroke", 0);
+
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/line", 
"width", "132");
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[2]/stroke", 
"dotDashArray",
+                "13225 13225 ");
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[3]/stroke", 
"dotDashArray",
+                "39674 13225 ");
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[4]/stroke", 
"dotDashArray",
+                "39674 13225 13225 13225 ");
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[5]/stroke", 
"dotDashArray",
+                "39674 13225 13225 13225 13225 13225 ");
+    //TODO polypolygonstroke[6-9]/stroke add support for 
PenDataDashedLineOffset
+    assertXPath(pDocument, aXPathPrefix + "polypolygonstroke[10]/stroke", 
"dotDashArray",
+                "66124 26450 198372 52899 ");
+}
+
 void Test::TestLinearGradient()
 {
     // EMF+ file with LinearGradient brush
diff --git a/emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithDash.emf 
b/emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithDash.emf
new file mode 100644
index 000000000000..dc5af59e3f66
Binary files /dev/null and 
b/emfio/qa/cppunit/emf/data/TestEmfPlusDrawLineWithDash.emf differ
diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx
index cab6b56b0ae7..ae673af298b3 100644
--- a/svx/qa/unit/svdraw.cxx
+++ b/svx/qa/unit/svdraw.cxx
@@ -338,7 +338,8 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testRectangleObject)
 
     assertXPathContent(pXmlDoc, aBasePath + "/polygon", "49.5,99 0,99 0,0 99,0 
99,99");
 
-    assertXPath(pXmlDoc, aBasePath + "/stroke", "fulldotdashlen", "0");
+    // If solid line, then there is no line stroke information
+    assertXPath(pXmlDoc, aBasePath + "/stroke", 0);
 
     pPage->RemoveObject(0);
 

Reply via email to