[Libreoffice-commits] core.git: basegfx/source cui/source drawinglayer/source include/basegfx include/vcl vcl/headless vcl/inc vcl/opengl vcl/qt5 vcl/quartz vcl/skia vcl/source vcl/unx vcl/win

Armin Le Grand (Collabora) (via logerrit) logerrit at kemper.freedesktop.org
Fri Feb 7 17:49:52 UTC 2020


 basegfx/source/polygon/b2dlinegeometry.cxx              |   23 +-
 cui/source/dialogs/screenshotannotationdlg.cxx          |    1 
 drawinglayer/source/primitive2d/polygonprimitive2d.cxx  |    2 
 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx |   92 +++-------
 include/basegfx/polygon/b2dlinegeometry.hxx             |   10 +
 include/vcl/outdev.hxx                                  |    1 
 vcl/headless/svpgdi.cxx                                 |  139 +++++++++++-----
 vcl/inc/headless/svpgdi.hxx                             |    2 
 vcl/inc/opengl/gdiimpl.hxx                              |    1 
 vcl/inc/qt5/Qt5Graphics.hxx                             |    7 
 vcl/inc/quartz/salgdi.h                                 |    1 
 vcl/inc/salgdi.hxx                                      |    2 
 vcl/inc/salgdiimpl.hxx                                  |    1 
 vcl/inc/skia/gdiimpl.hxx                                |    7 
 vcl/inc/unx/genpspgraphics.h                            |    1 
 vcl/inc/unx/salgdi.h                                    |    1 
 vcl/inc/win/salgdi.h                                    |    1 
 vcl/opengl/gdiimpl.cxx                                  |   70 ++++++--
 vcl/qt5/Qt5Graphics_GDI.cxx                             |   50 ++++-
 vcl/quartz/salgdicommon.cxx                             |   67 +++++--
 vcl/skia/gdiimpl.cxx                                    |   58 +++++-
 vcl/source/gdi/FileDefinitionWidgetDraw.cxx             |    4 
 vcl/source/gdi/salgdilayout.cxx                         |    4 
 vcl/source/outdev/line.cxx                              |    2 
 vcl/source/outdev/polygon.cxx                           |    3 
 vcl/source/outdev/polyline.cxx                          |    5 
 vcl/source/outdev/textline.cxx                          |   13 +
 vcl/source/outdev/transparent.cxx                       |    2 
 vcl/unx/generic/gdi/gdiimpl.cxx                         |   88 +++++++++-
 vcl/unx/generic/gdi/gdiimpl.hxx                         |    1 
 vcl/unx/generic/gdi/salgdi.cxx                          |    3 
 vcl/unx/generic/print/genpspgraphics.cxx                |    1 
 vcl/win/gdi/gdiimpl.cxx                                 |   99 +++++++++--
 vcl/win/gdi/gdiimpl.hxx                                 |    1 
 vcl/win/gdi/salgdi_gdiplus.cxx                          |    2 
 35 files changed, 564 insertions(+), 201 deletions(-)

New commits:
commit 5f61c9fe99ac93087b898adddbb4d4733f1fcd07
Author:     Armin Le Grand (Collabora) <Armin.Le.Grand at me.com>
AuthorDate: Thu Feb 6 18:53:12 2020 +0100
Commit:     Armin Le Grand <Armin.Le.Grand at me.com>
CommitDate: Fri Feb 7 18:49:18 2020 +0100

    tdf#130478 Enhance Dashed line drawing on all systems
    
    For more info and explanation including state of process
    information and discussion(s) see task please.
    
    Adding corrections for gerrit build
    
    Change-Id: Ie10fb8093a86459dee80db5ab4355b47e46c1f8c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88130
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <Armin.Le.Grand at me.com>

diff --git a/basegfx/source/polygon/b2dlinegeometry.cxx b/basegfx/source/polygon/b2dlinegeometry.cxx
index 0f602eb6241e..72c25f0c0593 100644
--- a/basegfx/source/polygon/b2dlinegeometry.cxx
+++ b/basegfx/source/polygon/b2dlinegeometry.cxx
@@ -848,7 +848,8 @@ namespace basegfx
             css::drawing::LineCap eCap,
             double fMaxAllowedAngle,
             double fMaxPartOfEdge,
-            double fMiterMinimumAngle)
+            double fMiterMinimumAngle,
+            basegfx::triangulator::B2DTriangleVector* pTriangles)
         {
             if(fMaxAllowedAngle > F_PI2)
             {
@@ -958,7 +959,7 @@ namespace basegfx
                                         fHalfLineWidth,
                                         eJoin,
                                         fMiterMinimumAngle,
-                                        nullptr));
+                                        pTriangles));
                             }
                             else if(aOrientation == B2VectorOrientation::Negative)
                             {
@@ -975,7 +976,7 @@ namespace basegfx
                                         fHalfLineWidth,
                                         eJoin,
                                         fMiterMinimumAngle,
-                                        nullptr));
+                                        pTriangles));
                             }
                         }
 
@@ -994,7 +995,7 @@ namespace basegfx
                                     bLast && eCap == css::drawing::LineCap_ROUND,
                                     bFirst && eCap == css::drawing::LineCap_SQUARE,
                                     bLast && eCap == css::drawing::LineCap_SQUARE,
-                                    nullptr));
+                                    pTriangles));
                         }
                         else
                         {
@@ -1006,7 +1007,7 @@ namespace basegfx
                                     false,
                                     false,
                                     false,
-                                    nullptr));
+                                    pTriangles));
                         }
 
                         // prepare next step
@@ -1029,7 +1030,17 @@ namespace basegfx
                             aCandidate.getB2DPoint(0),
                             fHalfLineWidth));
 
-                    aRetval.append(aCircle);
+                    if(nullptr != pTriangles)
+                    {
+                        const basegfx::triangulator::B2DTriangleVector aResult(
+                            basegfx::triangulator::triangulate(
+                                aCircle));
+                        pTriangles->insert(pTriangles->end(), aResult.begin(), aResult.end());
+                    }
+                    else
+                    {
+                        aRetval.append(aCircle);
+                    }
                 }
 
                 return aRetval;
diff --git a/cui/source/dialogs/screenshotannotationdlg.cxx b/cui/source/dialogs/screenshotannotationdlg.cxx
index dca914c1517c..c9a93d21d9c5 100644
--- a/cui/source/dialogs/screenshotannotationdlg.cxx
+++ b/cui/source/dialogs/screenshotannotationdlg.cxx
@@ -406,6 +406,7 @@ void ScreenshotAnnotationDlg_Impl::PaintScreenShotEntry(
             aPolygon,
             fLineWidth,
             fTransparency,
+            nullptr, // MM01
             basegfx::B2DLineJoin::Round))
         {
             // no transparency, draw without
diff --git a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx
index 2410f2158555..cdcc843a8b17 100644
--- a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx
@@ -278,6 +278,7 @@ namespace drawinglayer
             maLineAttribute(rLineAttribute),
             maStrokeAttribute(rStrokeAttribute)
         {
+            // MM01: keep these - these are no curve-decompposers but just checks
             // simplify curve segments: moved here to not need to use it
             // at VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect
             maPolygon = basegfx::utils::simplifyCurveSegments(maPolygon);
@@ -291,6 +292,7 @@ namespace drawinglayer
             maLineAttribute(rLineAttribute),
             maStrokeAttribute()
         {
+            // MM01: keep these - these are no curve-decompposers but just checks
             // simplify curve segments: moved here to not need to use it
             // at VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect
             maPolygon = basegfx::utils::simplifyCurveSegments(maPolygon);
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index e9642dd410fb..2fa5a7d47a44 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -96,7 +96,7 @@ namespace drawinglayer::processor2d
 
         void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency)
         {
-            if(!rSource.getB2DPolyPolygon().count())
+            if(!rSource.getB2DPolyPolygon().count() || fTransparency < 0.0 || fTransparency >= 1.0)
             {
                 // no geometry, done
                 return;
@@ -116,7 +116,7 @@ namespace drawinglayer::processor2d
         {
             const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
 
-            if(!rLocalPolygon.count())
+            if(!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
             {
                 // no geometry, done
                 return true;
@@ -138,41 +138,28 @@ namespace drawinglayer::processor2d
 
         bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency)
         {
-            if(!rSource.getB2DPolygon().count())
+            const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
+
+            if(!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
             {
                 // no geometry, done
                 return true;
             }
 
-            // get geometry data, prepare hairline data
-            const basegfx::B2DPolygon& aLocalPolygon(rSource.getB2DPolygon());
-            basegfx::B2DPolyPolygon aHairLinePolyPolygon;
-
-            // simplify curve segments
-            // moved to PolygonStrokePrimitive2D::PolygonStrokePrimitive2D
-            // aLocalPolygon = basegfx::utils::simplifyCurveSegments(aLocalPolygon);
-
-            if(rSource.getStrokeAttribute().isDefault() || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen())
-            {
-                // no line dashing, just copy
-                aHairLinePolyPolygon.append(aLocalPolygon);
-            }
-            else
+            if (basegfx::B2DLineJoin::NONE == rSource.getLineAttribute().getLineJoin()
+                && css::drawing::LineCap_BUTT != rSource.getLineAttribute().getLineCap())
             {
-                // apply LineStyle
-                basegfx::utils::applyLineDashing(
-                    aLocalPolygon,
-                    rSource.getStrokeAttribute().getDotDashArray(),
-                    &aHairLinePolyPolygon,
-                    nullptr,
-                    rSource.getStrokeAttribute().getFullDotDashLen());
+                // better use decompose to get that combination done for now, see discussion
+                // at https://bugs.documentfoundation.org/show_bug.cgi?id=130478#c17 and ff
+                return false;
             }
 
-            if(!aHairLinePolyPolygon.count())
-            {
-                // no geometry, done
-                return true;
-            }
+            // MM01: Radically change here - no dismantle/applyLineDashing,
+            // let that happen low-level at DrawPolyLineDirect implementations
+            // to open up for buffering and evtl. direct draw with sys-dep
+            // graphic systems. Check for stroke is in use
+            const bool bStrokeAttributeNotUsed(rSource.getStrokeAttribute().isDefault()
+                || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen());
 
             // check if LineWidth can be simplified in world coordinates
             double fLineWidth(rSource.getLineAttribute().getWidth());
@@ -201,42 +188,17 @@ namespace drawinglayer::processor2d
             mpOutputDevice->SetFillColor();
             mpOutputDevice->SetLineColor(Color(aLineColor));
 
-            // do not transform self
-            // aHairLinePolyPolygon.transform(maCurrentTransformation);
-
-            bool bHasPoints(false);
-            bool bTryWorked(false);
-
-            for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
-            {
-                const basegfx::B2DPolygon& aSingle(aHairLinePolyPolygon.getB2DPolygon(a));
-
-                if(aSingle.count())
-                {
-                    bHasPoints = true;
-
-                    if(mpOutputDevice->DrawPolyLineDirect(
-                        maCurrentTransformation,
-                        aSingle,
-                        fLineWidth,
-                        fTransparency,
-                        rSource.getLineAttribute().getLineJoin(),
-                        rSource.getLineAttribute().getLineCap(),
-                        rSource.getLineAttribute().getMiterMinimumAngle()
-                        /* false bBypassAACheck, default*/))
-                    {
-                        bTryWorked = true;
-                    }
-                }
-            }
-
-            if(!bTryWorked && !bHasPoints)
-            {
-                // no geometry despite try
-                bTryWorked = true;
-            }
-
-            return bTryWorked;
+            // MM01 draw direct, hand over dash data if available
+            return mpOutputDevice->DrawPolyLineDirect(
+                maCurrentTransformation,
+                rLocalPolygon,
+                fLineWidth,
+                fTransparency,
+                bStrokeAttributeNotUsed ? nullptr : &rSource.getStrokeAttribute().getDotDashArray(),
+                rSource.getLineAttribute().getLineJoin(),
+                rSource.getLineAttribute().getLineCap(),
+                rSource.getLineAttribute().getMiterMinimumAngle()
+                /* false bBypassAACheck, default*/);
         }
 
         void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
diff --git a/include/basegfx/polygon/b2dlinegeometry.hxx b/include/basegfx/polygon/b2dlinegeometry.hxx
index c6973c6f161c..6a98d6189394 100644
--- a/include/basegfx/polygon/b2dlinegeometry.hxx
+++ b/include/basegfx/polygon/b2dlinegeometry.hxx
@@ -123,6 +123,13 @@ namespace basegfx
             the usual fallback to bevel is used. Allowed range is cropped
             to [F_PI .. 0.01 * F_PI].
 
+            Commit 51b5b93092d6231615de470c62494c24e54828a1 needs
+            revert, we need the triangulation for X11 fat line drawing
+
+            @param pTriangles
+            If given, the method will additionally add the created geometry as
+            B2DTriangle's
+
             @return
             The tools::PolyPolygon containing the geometry of the extended line by
             it's line width. Contains bezier segments and edge roundings as
@@ -135,7 +142,8 @@ namespace basegfx
             css::drawing::LineCap eCap,
             double fMaxAllowedAngle = basegfx::deg2rad(12.5),
             double fMaxPartOfEdge = 0.4,
-            double fMiterMinimumAngle = basegfx::deg2rad(15.0));
+            double fMiterMinimumAngle = basegfx::deg2rad(15.0),
+            basegfx::triangulator::B2DTriangleVector* pTriangles = nullptr);
 
     } // end of namespace utils
 } // end of namespace basegfx
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index c991867495ea..687b9a1c207a 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -799,6 +799,7 @@ public:
                                     const basegfx::B2DPolygon& rB2DPolygon,
                                     double fLineWidth = 0.0,
                                     double fTransparency = 0.0,
+                                    const std::vector< double >* = nullptr, // MM01
                                     basegfx::B2DLineJoin eLineJoin = basegfx::B2DLineJoin::NONE,
                                     css::drawing::LineCap eLineCap = css::drawing::LineCap_BUTT,
                                     double fMiterMinimumAngle = basegfx::deg2rad(15.0),
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 0d4a366fc4f1..80a24fad54f9 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -20,6 +20,8 @@
 #include <config_features.h>
 
 #include <memory>
+#include <numeric>
+
 #ifndef IOS
 #include <headless/svpgdi.hxx>
 #endif
@@ -783,6 +785,7 @@ void SvpSalGraphics::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry)
         aPoly,
         0.0,
         basegfx::B2DVector(1.0, 1.0),
+        nullptr, // MM01
         basegfx::B2DLineJoin::Miter,
         css::drawing::LineCap_BUTT,
         basegfx::deg2rad(15.0) /*default*/,
@@ -1064,6 +1067,7 @@ private:
     // need to be compared with to check for data validity
     bool                mbNoJoin;
     bool                mbAntiAliasB2DDraw;
+    std::vector< double >                       maStroke;
 
 public:
     SystemDependentData_CairoPath(
@@ -1071,12 +1075,15 @@ public:
         size_t nSizeMeasure,
         cairo_t* cr,
         bool bNoJoin,
-        bool bAntiAliasB2DDraw);
+        bool bAntiAliasB2DDraw,
+        const std::vector< double >* pStroke); // MM01
     virtual ~SystemDependentData_CairoPath() override;
 
+    // read access
     cairo_path_t* getCairoPath() { return mpCairoPath; }
     bool getNoJoin() const { return mbNoJoin; }
     bool getAntiAliasB2DDraw() const { return mbAntiAliasB2DDraw; }
+    const std::vector< double >& getStroke() const { return maStroke; }
 
     virtual sal_Int64 estimateUsageInBytes() const override;
 };
@@ -1088,17 +1095,24 @@ SystemDependentData_CairoPath::SystemDependentData_CairoPath(
     size_t nSizeMeasure,
     cairo_t* cr,
     bool bNoJoin,
-    bool bAntiAliasB2DDraw)
+    bool bAntiAliasB2DDraw,
+    const std::vector< double >* pStroke)
 :   basegfx::SystemDependentData(rSystemDependentDataManager),
     mpCairoPath(nullptr),
     mbNoJoin(bNoJoin),
-    mbAntiAliasB2DDraw(bAntiAliasB2DDraw)
+    mbAntiAliasB2DDraw(bAntiAliasB2DDraw),
+    maStroke()
 {
     // tdf#129845 only create a copy of the path when nSizeMeasure is
     // bigger than some decent threshold
     if(nSizeMeasure > 50)
     {
         mpCairoPath = cairo_copy_path(cr);
+
+        if(nullptr != pStroke)
+        {
+            maStroke = *pStroke;
+        }
     }
 }
 
@@ -1134,7 +1148,8 @@ bool SvpSalGraphics::drawPolyLine(
     const basegfx::B2DHomMatrix& rObjectToDevice,
     const basegfx::B2DPolygon& rPolyLine,
     double fTransparency,
-    const basegfx::B2DVector& rLineWidths,
+    const basegfx::B2DVector& rLineWidth,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
@@ -1165,7 +1180,8 @@ bool SvpSalGraphics::drawPolyLine(
             rObjectToDevice,
             rPolyLine,
             fTransparency,
-            rLineWidths,
+            rLineWidth,
+            pStroke, // MM01
             eLineJoin,
             eLineCap,
             fMiterMinimumAngle,
@@ -1184,7 +1200,8 @@ bool SvpSalGraphics::drawPolyLine(
     const basegfx::B2DHomMatrix& rObjectToDevice,
     const basegfx::B2DPolygon& rPolyLine,
     double fTransparency,
-    const basegfx::B2DVector& rLineWidths,
+    const basegfx::B2DVector& rLineWidth,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
@@ -1197,10 +1214,10 @@ bool SvpSalGraphics::drawPolyLine(
     }
 
     // need to check/handle LineWidth when ObjectToDevice transformation is used
-    basegfx::B2DVector aLineWidths(rLineWidths);
+    basegfx::B2DVector aLineWidth(rLineWidth);
     const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity());
-    const basegfx::B2DVector aDeviceLineWidths(bObjectToDeviceIsIdentity ? rLineWidths : rObjectToDevice * rLineWidths);
-    const bool bCorrectLineWidth(!bObjectToDeviceIsIdentity && aDeviceLineWidths.getX() < 1.0 && aLineWidths.getX() >= 1.0);
+    const basegfx::B2DVector aDeviceLineWidth(bObjectToDeviceIsIdentity ? rLineWidth : rObjectToDevice * rLineWidth);
+    const bool bCorrectLineWidth(!bObjectToDeviceIsIdentity && aDeviceLineWidth.getX() < 1.0 && aLineWidth.getX() >= 1.0);
 
     // on-demand inverse of ObjectToDevice transformation
     basegfx::B2DHomMatrix aObjectToDeviceInv;
@@ -1214,12 +1231,11 @@ bool SvpSalGraphics::drawPolyLine(
         }
 
         // calculate-back logical LineWidth for a hairline
-        aLineWidths = aObjectToDeviceInv * basegfx::B2DVector(1.0, 1.0);
+        aLineWidth = aObjectToDeviceInv * basegfx::B2DVector(1.0, 1.0);
     }
 
     // PixelOffset used: Need to reflect in linear transformation
     cairo_matrix_t aMatrix;
-
     basegfx::B2DHomMatrix aDamageMatrix(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5));
 
     if (bObjectToDeviceIsIdentity)
@@ -1245,8 +1261,6 @@ bool SvpSalGraphics::drawPolyLine(
     // set linear transformation
     cairo_set_matrix(cr, &aMatrix);
 
-    const bool bNoJoin((basegfx::B2DLineJoin::NONE == eLineJoin && basegfx::fTools::more(aLineWidths.getX(), 0.0)));
-
     // setup line attributes
     cairo_line_join_t eCairoLineJoin = CAIRO_LINE_JOIN_MITER;
     switch (eLineJoin)
@@ -1297,13 +1311,35 @@ bool SvpSalGraphics::drawPolyLine(
 
     cairo_set_line_join(cr, eCairoLineJoin);
     cairo_set_line_cap(cr, eCairoLineCap);
-    cairo_set_line_width(cr, aLineWidths.getX());
+    cairo_set_line_width(cr, aLineWidth.getX());
     cairo_set_miter_limit(cr, fMiterLimit);
 
     // try to access buffered data
     std::shared_ptr<SystemDependentData_CairoPath> pSystemDependentData_CairoPath(
         rPolyLine.getSystemDependentData<SystemDependentData_CairoPath>());
 
+    // MM01 need to do line dashing as fallback stuff here now
+    const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
+    const bool bStrokeUsed(0.0 != fDotDashLength);
+
+    if(pSystemDependentData_CairoPath)
+    {
+        // MM01 - check on stroke change. Used against not used, or if both used,
+        // equal or different?
+        const bool bStrokeWasUsed(!pSystemDependentData_CairoPath->getStroke().empty());
+
+        if(bStrokeWasUsed != bStrokeUsed
+        || (bStrokeUsed && *pStroke != pSystemDependentData_CairoPath->getStroke()))
+        {
+            // data invalid, forget
+            pSystemDependentData_CairoPath.reset();
+        }
+    }
+
+    // check for basegfx::B2DLineJoin::NONE to react accordingly
+    const bool bNoJoin((basegfx::B2DLineJoin::NONE == eLineJoin
+        && basegfx::fTools::more(aLineWidth.getX(), 0.0)));
+
     if(pSystemDependentData_CairoPath)
     {
         // check data validity
@@ -1327,42 +1363,67 @@ bool SvpSalGraphics::drawPolyLine(
         // create data
         size_t nSizeMeasure(0);
 
-        if (!bNoJoin)
+        // MM01 need to do line dashing as fallback stuff here now
+        basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+        if(bStrokeUsed)
         {
-            // PixelOffset now reflected in linear transformation used
-            nSizeMeasure += AddPolygonToPath(
-                cr,
-                rPolyLine,
-                rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset
-                !bAntiAliasB2DDraw,
-                bPixelSnapHairline);
+            // apply LineStyle
+            basegfx::utils::applyLineDashing(
+                rPolyLine, // source
+                *pStroke, // pattern
+                &aPolyPolygonLine, // traget for lines
+                nullptr, // target for gaps
+                fDotDashLength); // full length if available
         }
         else
         {
-            const sal_uInt32 nPointCount(rPolyLine.count());
-            const sal_uInt32 nEdgeCount(rPolyLine.isClosed() ? nPointCount : nPointCount - 1);
-            basegfx::B2DPolygon aEdge;
+            // no line dashing, just copy
+            aPolyPolygonLine.append(rPolyLine);
+        }
 
-            aEdge.append(rPolyLine.getB2DPoint(0));
-            aEdge.append(basegfx::B2DPoint(0.0, 0.0));
+        // MM01 checked/verified for Cairo
+        for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+        {
+            const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
 
-            for (sal_uInt32 i(0); i < nEdgeCount; i++)
+            if (!bNoJoin)
             {
-                const sal_uInt32 nNextIndex((i + 1) % nPointCount);
-                aEdge.setB2DPoint(1, rPolyLine.getB2DPoint(nNextIndex));
-                aEdge.setNextControlPoint(0, rPolyLine.getNextControlPoint(i));
-                aEdge.setPrevControlPoint(1, rPolyLine.getPrevControlPoint(nNextIndex));
-
                 // PixelOffset now reflected in linear transformation used
                 nSizeMeasure += AddPolygonToPath(
                     cr,
-                    aEdge,
+                    aPolyLine,
                     rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset
                     !bAntiAliasB2DDraw,
                     bPixelSnapHairline);
+            }
+            else
+            {
+                const sal_uInt32 nPointCount(aPolyLine.count());
+                const sal_uInt32 nEdgeCount(aPolyLine.isClosed() ? nPointCount : nPointCount - 1);
+                basegfx::B2DPolygon aEdge;
+
+                aEdge.append(aPolyLine.getB2DPoint(0));
+                aEdge.append(basegfx::B2DPoint(0.0, 0.0));
 
-                // prepare next step
-                aEdge.setB2DPoint(0, aEdge.getB2DPoint(1));
+                for (sal_uInt32 i(0); i < nEdgeCount; i++)
+                {
+                    const sal_uInt32 nNextIndex((i + 1) % nPointCount);
+                    aEdge.setB2DPoint(1, aPolyLine.getB2DPoint(nNextIndex));
+                    aEdge.setNextControlPoint(0, aPolyLine.getNextControlPoint(i));
+                    aEdge.setPrevControlPoint(1, aPolyLine.getPrevControlPoint(nNextIndex));
+
+                    // PixelOffset now reflected in linear transformation used
+                    nSizeMeasure += AddPolygonToPath(
+                        cr,
+                        aEdge,
+                        rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset
+                        !bAntiAliasB2DDraw,
+                        bPixelSnapHairline);
+
+                    // prepare next step
+                    aEdge.setB2DPoint(0, aEdge.getB2DPoint(1));
+                }
             }
         }
 
@@ -1374,7 +1435,8 @@ bool SvpSalGraphics::drawPolyLine(
                 nSizeMeasure,
                 cr,
                 bNoJoin,
-                bAntiAliasB2DDraw);
+                bAntiAliasB2DDraw,
+                pStroke);
         }
     }
 
@@ -1454,7 +1516,8 @@ namespace
                 nSizeMeasure,
                 cr,
                 false,
-                false);
+                false,
+                nullptr);
         }
     }
 }
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index bb0d3d5f4233..99300ed03a53 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -114,6 +114,7 @@ public:
         const basegfx::B2DPolygon& rPolyLine,
         double fTransparency,
         const basegfx::B2DVector& rLineWidths,
+        const std::vector< double >* pStroke, // MM01
         basegfx::B2DLineJoin eLineJoin,
         css::drawing::LineCap eLineCap,
         double fMiterMinimumAngle,
@@ -211,6 +212,7 @@ public:
                                 const basegfx::B2DPolygon&,
                                 double fTransparency,
                                 const basegfx::B2DVector& rLineWidths,
+                                const std::vector< double >* pStroke, // MM01
                                 basegfx::B2DLineJoin,
                                 css::drawing::LineCap,
                                 double fMiterMinimumAngle,
diff --git a/vcl/inc/opengl/gdiimpl.hxx b/vcl/inc/opengl/gdiimpl.hxx
index 2deba40eba53..ac488a28116e 100644
--- a/vcl/inc/opengl/gdiimpl.hxx
+++ b/vcl/inc/opengl/gdiimpl.hxx
@@ -260,6 +260,7 @@ public:
                 const basegfx::B2DPolygon&,
                 double fTransparency,
                 const basegfx::B2DVector& rLineWidths,
+                const std::vector< double >* pStroke, // MM01
                 basegfx::B2DLineJoin,
                 css::drawing::LineCap,
                 double fMiterMinimumAngle,
diff --git a/vcl/inc/qt5/Qt5Graphics.hxx b/vcl/inc/qt5/Qt5Graphics.hxx
old mode 100644
new mode 100755
index 51a4a452930e..a17421b2f65d
--- a/vcl/inc/qt5/Qt5Graphics.hxx
+++ b/vcl/inc/qt5/Qt5Graphics.hxx
@@ -119,9 +119,10 @@ public:
                                        const PolyFlags* const* pFlgAry) override;
     virtual bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
                               const basegfx::B2DPolygon&, double fTransparency,
-                              const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin,
-                              css::drawing::LineCap eLineCap, double fMiterMinimumAngle,
-                              bool bPixelSnapHairline) override;
+                              const basegfx::B2DVector& rLineWidths,
+                              const std::vector<double>* pStroke, // MM01
+                              basegfx::B2DLineJoin, css::drawing::LineCap eLineCap,
+                              double fMiterMinimumAngle, bool bPixelSnapHairline) override;
     virtual bool drawGradient(const tools::PolyPolygon&, const Gradient&) override;
 
     virtual void copyArea(long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index 48ae50e2c68c..3fa3a0e38e77 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -241,6 +241,7 @@ public:
                                 const basegfx::B2DPolygon&,
                                 double fTransparency,
                                 const basegfx::B2DVector& rLineWidths,
+                                const std::vector< double >* pStroke, // MM01
                                 basegfx::B2DLineJoin,
                                 css::drawing::LineCap eLineCap,
                                 double fMiterMinimumAngle,
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index 6fa87ec5aadc..8ae88aba161a 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -247,6 +247,7 @@ public:
                                     const basegfx::B2DPolygon& i_rPolygon,
                                     double i_fTransparency,
                                     const basegfx::B2DVector& i_rLineWidth,
+                                    const std::vector< double >* i_pStroke, // MM01
                                     basegfx::B2DLineJoin i_eLineJoin,
                                     css::drawing::LineCap i_eLineCap,
                                     double i_fMiterMinimumAngle,
@@ -466,6 +467,7 @@ protected:
                                     const basegfx::B2DPolygon&,
                                     double fTransparency,
                                     const basegfx::B2DVector& rLineWidths,
+                                    const std::vector< double >* pStroke, // MM01
                                     basegfx::B2DLineJoin,
                                     css::drawing::LineCap,
                                     double fMiterMinimumAngle,
diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx
index 432dbdb7ec0d..3b179a7131ad 100644
--- a/vcl/inc/salgdiimpl.hxx
+++ b/vcl/inc/salgdiimpl.hxx
@@ -110,6 +110,7 @@ public:
                 const basegfx::B2DPolygon&,
                 double fTransparency,
                 const basegfx::B2DVector& rLineWidths,
+                const std::vector< double >* pStroke, // MM01
                 basegfx::B2DLineJoin,
                 css::drawing::LineCap,
                 double fMiterMinimumAngle,
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
old mode 100644
new mode 100755
index 10b6371b4dcd..46b3f7bcd334
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -101,9 +101,10 @@ public:
 
     virtual bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
                               const basegfx::B2DPolygon&, double fTransparency,
-                              const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin,
-                              css::drawing::LineCap, double fMiterMinimumAngle,
-                              bool bPixelSnapHairline) override;
+                              const basegfx::B2DVector& rLineWidths,
+                              const std::vector<double>* pStroke, // MM01
+                              basegfx::B2DLineJoin, css::drawing::LineCap,
+                              double fMiterMinimumAngle, bool bPixelSnapHairline) override;
 
     virtual bool drawPolyLineBezier(sal_uInt32 nPoints, const SalPoint* pPtAry,
                                     const PolyFlags* pFlgAry) override;
diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h
index cce727baa8f6..6dfca7548f4b 100644
--- a/vcl/inc/unx/genpspgraphics.h
+++ b/vcl/inc/unx/genpspgraphics.h
@@ -132,6 +132,7 @@ public:
                                 const basegfx::B2DPolygon&,
                                 double fTransparency,
                                 const basegfx::B2DVector& rLineWidths,
+                                const std::vector< double >* pStroke, // MM01
                                 basegfx::B2DLineJoin,
                                 css::drawing::LineCap,
                                 double fMiterMinimumAngle,
diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h
index 111702c1881e..01e5fffaf66a 100644
--- a/vcl/inc/unx/salgdi.h
+++ b/vcl/inc/unx/salgdi.h
@@ -170,6 +170,7 @@ public:
                                         const basegfx::B2DPolygon&,
                                         double fTransparency,
                                         const basegfx::B2DVector& rLineWidth,
+                                        const std::vector< double >* pStroke, // MM01
                                         basegfx::B2DLineJoin,
                                         css::drawing::LineCap,
                                         double fMiterMinimumAngle,
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 15866800b8f4..06365cd1657b 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -245,6 +245,7 @@ protected:
         const basegfx::B2DPolygon&,
         double fTransparency,
         const basegfx::B2DVector& rLineWidth,
+        const std::vector< double >* pStroke, // MM01
         basegfx::B2DLineJoin,
         css::drawing::LineCap,
         double fMiterMinimumAngle,
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 5c26a6d55b6d..ab4b1632b40b 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -27,6 +27,7 @@
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
 #include <basegfx/polygon/b2dlinegeometry.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
 #include <basegfx/polygon/b2dtrapezoid.hxx>
@@ -43,6 +44,7 @@
 
 #include <cmath>
 #include <vector>
+#include <numeric>
 
 #include <glm/gtc/type_ptr.hpp>
 #include <glm/gtx/norm.hpp>
@@ -1559,6 +1561,7 @@ void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pP
         aPoly,
         0.0,
         basegfx::B2DVector(1.0, 1.0),
+        nullptr, // MM01
         basegfx::B2DLineJoin::Miter,
         css::drawing::LineCap_BUTT,
         basegfx::deg2rad(15.0) /*default*/,
@@ -1636,6 +1639,7 @@ bool OpenGLSalGraphicsImpl::drawPolyLine(
     const basegfx::B2DPolygon& rPolygon,
     double fTransparency,
     const basegfx::B2DVector& rLineWidth,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
@@ -1643,28 +1647,60 @@ bool OpenGLSalGraphicsImpl::drawPolyLine(
 {
     VCL_GL_INFO("::drawPolyLine " << rPolygon.getB2DRange());
 
+    // MM01 check done for simple reasons
+    if(!rPolygon.count() || fTransparency < 0.0 || fTransparency > 1.0)
+    {
+        return true;
+    }
+
+    // MM01 need to do line dashing as fallback stuff here now
+    const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
+    const bool bStrokeUsed(0.0 != fDotDashLength);
+    basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+    if(bStrokeUsed)
+    {
+        // apply LineStyle
+        basegfx::utils::applyLineDashing(
+            rPolygon, // source
+            *pStroke, // pattern
+            &aPolyPolygonLine, // traget for lines
+            nullptr, // target for gaps
+            fDotDashLength); // full length if available
+    }
+    else
+    {
+        // no line dashing, just copy
+        aPolyPolygonLine.append(rPolygon);
+    }
+
     // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
-    basegfx::B2DPolygon aPolyLine(rPolygon);
-    aPolyLine.transform(rObjectToDevice);
-    if(bPixelSnapHairline) { aPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyLine); }
+    aPolyPolygonLine.transform(rObjectToDevice);
+    if(bPixelSnapHairline) { aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); }
     const basegfx::B2DVector aLineWidth(rObjectToDevice * rLineWidth);
 
-    // addDrawPolyLine() assumes that there are no duplicate points in the
-    // polygon.
-    // basegfx::B2DPolygon aPolygon(rPolygon);
-    aPolyLine.removeDoublePoints();
+    for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+    {
+        // addDrawPolyLine() assumes that there are no duplicate points in the polygon
+        basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
+        basegfx::utils::simplifyCurveSegments(aPolyLine);
+        aPolyLine.removeDoublePoints();
 
-    mpRenderList->addDrawPolyLine(
-        aPolyLine,
-        fTransparency,
-        aLineWidth,
-        eLineJoin,
-        eLineCap,
-        fMiterMinimumAngle,
-        mnLineColor,
-        mrParent.getAntiAliasB2DDraw());
+        mpRenderList->addDrawPolyLine(
+            aPolyLine,
+            fTransparency,
+            aLineWidth,
+            eLineJoin,
+            eLineCap,
+            fMiterMinimumAngle,
+            mnLineColor,
+            mrParent.getAntiAliasB2DDraw());
+
+        // MM01: not sure - maybe this can be moved out of this loop, but to
+        // keep on the safe side for now, do not relly change something for now
+        PostBatchDraw();
+    }
 
-    PostBatchDraw();
     return true;
 }
 
diff --git a/vcl/qt5/Qt5Graphics_GDI.cxx b/vcl/qt5/Qt5Graphics_GDI.cxx
old mode 100644
new mode 100755
index 2aa70949dc32..102c84900c08
--- a/vcl/qt5/Qt5Graphics_GDI.cxx
+++ b/vcl/qt5/Qt5Graphics_GDI.cxx
@@ -29,7 +29,9 @@
 #include <QtGui/QWindow>
 #include <QtWidgets/QWidget>
 
+#include <numeric>
 #include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
 
 static const basegfx::B2DPoint aHalfPointOfs(0.5, 0.5);
 
@@ -323,37 +325,67 @@ bool Qt5Graphics::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32*
 
 bool Qt5Graphics::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
                                const basegfx::B2DPolygon& rPolyLine, double fTransparency,
-                               const basegfx::B2DVector& rLineWidths,
+                               const basegfx::B2DVector& rLineWidth,
+                               const std::vector<double>* pStroke, // MM01
                                basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap,
                                double fMiterMinimumAngle, bool bPixelSnapHairline)
 {
     if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor)
+    {
         return true;
+    }
 
-    // short circuit if there is nothing to do
-    if (0 == rPolyLine.count())
+    // MM01 check done for simple reasons
+    if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0)
     {
         return true;
     }
 
+    // MM01 need to do line dashing as fallback stuff here now
+    const double fDotDashLength(
+        nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
+    const bool bStrokeUsed(0.0 != fDotDashLength);
+    basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+    if (bStrokeUsed)
+    {
+        // apply LineStyle
+        basegfx::utils::applyLineDashing(rPolyLine, // source
+                                         *pStroke, // pattern
+                                         &aPolyPolygonLine, // traget for lines
+                                         nullptr, // target for gaps
+                                         fDotDashLength); // full length if available
+    }
+    else
+    {
+        // no line dashing, just copy
+        aPolyPolygonLine.append(rPolyLine);
+    }
+
     // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
-    basegfx::B2DPolygon aPolyLine(rPolyLine);
-    aPolyLine.transform(rObjectToDevice);
+    aPolyPolygonLine.transform(rObjectToDevice);
     if (bPixelSnapHairline)
     {
-        aPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyLine);
+        aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
     }
-    const basegfx::B2DVector aLineWidths(rObjectToDevice * rLineWidths);
+    const basegfx::B2DVector aLineWidth(rObjectToDevice * rLineWidth);
 
     // setup poly-polygon path
     QPainterPath aPath;
-    AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAliasB2DDraw(), true);
+
+    // MM01 todo - I assume that this is OKAY to be done in one run for Qt5,
+    // but this NEEDS to be checked/verified
+    for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+    {
+        const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
+        AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAliasB2DDraw(), true);
+    }
 
     Qt5Painter aPainter(*this, false, 255 * (1.0 - fTransparency));
 
     // setup line attributes
     QPen aPen = aPainter.pen();
-    aPen.setWidth(aLineWidths.getX());
+    aPen.setWidth(aLineWidth.getX());
 
     switch (eLineJoin)
     {
diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx
index f5f1aba8b41a..2f0ea1a061c2 100644
--- a/vcl/quartz/salgdicommon.cxx
+++ b/vcl/quartz/salgdicommon.cxx
@@ -22,9 +22,11 @@
 
 #include <cassert>
 #include <cstring>
+#include <numeric>
 
 #include <basegfx/polygon/b2dpolygon.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
 #include <osl/endian.h>
 #include <osl/file.hxx>
 #include <sal/types.h>
@@ -815,15 +817,18 @@ bool AquaSalGraphics::drawPolyLine(
     const basegfx::B2DHomMatrix& rObjectToDevice,
     const basegfx::B2DPolygon& rPolyLine,
     double fTransparency,
-    const basegfx::B2DVector& rLineWidths,
+    const basegfx::B2DVector& rLineWidth,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
     bool bPixelSnapHairline)
 {
-    // short circuit if there is nothing to do
-    if(0 == rPolyLine.count())
+    // MM01 check done for simple reasons
+    if(!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0)
+    {
         return true;
+    }
 
 #ifdef IOS
     if( !CheckContext() )
@@ -831,21 +836,40 @@ bool AquaSalGraphics::drawPolyLine(
 #endif
 
     // need to check/handle LineWidth when ObjectToDevice transformation is used
-    const basegfx::B2DVector aDeviceLineWidths(rObjectToDevice * rLineWidths);
-    const bool bCorrectLineWidth(aDeviceLineWidths.getX() < 1.0 && rLineWidths.getX() >= 1.0);
-    const basegfx::B2DVector aLineWidths(bCorrectLineWidth ? rLineWidths : aDeviceLineWidths);
+    const basegfx::B2DVector aDeviceLineWidth(rObjectToDevice * rLineWidth);
+    const bool bCorrectLineWidth(aDeviceLineWidth.getX() < 1.0 && rLineWidth.getX() >= 1.0);
+    const basegfx::B2DVector aLineWidth(bCorrectLineWidth ? rLineWidth : aDeviceLineWidth);
 
     // #i101491# Aqua does not support B2DLineJoin::NONE; return false to use
     // the fallback (own geometry preparation)
     // #i104886# linejoin-mode and thus the above only applies to "fat" lines
-    if( (basegfx::B2DLineJoin::NONE == eLineJoin) && (aLineWidths.getX() > 1.3) )
+    if( (basegfx::B2DLineJoin::NONE == eLineJoin) && (aLineWidth.getX() > 1.3) )
         return false;
 
+    // MM01 need to do line dashing as fallback stuff here now
+    const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
+    const bool bStrokeUsed(0.0 != fDotDashLength);
+    basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+    if(bStrokeUsed)
+    {
+        // apply LineStyle
+        basegfx::utils::applyLineDashing(
+            rPolyLine, // source
+            *pStroke, // pattern
+            &aPolyPolygonLine, // traget for lines
+            nullptr, // target for gaps
+            fDotDashLength); // full length if available
+    }
+    else
+    {
+        // no line dashing, just copy
+        aPolyPolygonLine.append(rPolyLine);
+    }
+
     // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
-    basegfx::B2DPolygon aPolyLine(rPolyLine);
-    aPolyLine.transform(rObjectToDevice);
-    if(bPixelSnapHairline)
-        aPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyLine);
+    aPolyPolygonLine.transform(rObjectToDevice);
+    if(bPixelSnapHairline) { aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); }
 
     // setup line attributes
     CGLineJoin aCGLineJoin = kCGLineJoinMiter;
@@ -882,12 +906,19 @@ bool AquaSalGraphics::drawPolyLine(
 
     // setup poly-polygon path
     CGMutablePathRef xPath = CGPathCreateMutable();
-    AddPolygonToPath(
-        xPath,
-        aPolyLine,
-        aPolyLine.isClosed(),
-        !getAntiAliasB2DDraw(),
-        true);
+
+    // MM01 todo - I assume that this is OKAY to be done in one run for quartz
+    // but this NEEDS to be checked/verified
+    for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+    {
+        const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
+        AddPolygonToPath(
+            xPath,
+            aPolyLine,
+            aPolyLine.isClosed(),
+            !getAntiAliasB2DDraw(),
+            true);
+    }
 
     const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
     // #i97317# workaround for Quartz having problems with drawing small polygons
@@ -902,7 +933,7 @@ bool AquaSalGraphics::drawPolyLine(
         CGContextSetAlpha( maContextHolder.get(), 1.0 - fTransparency );
         CGContextSetLineJoin( maContextHolder.get(), aCGLineJoin );
         CGContextSetLineCap( maContextHolder.get(), aCGLineCap );
-        CGContextSetLineWidth( maContextHolder.get(), aLineWidths.getX() );
+        CGContextSetLineWidth( maContextHolder.get(), aLineWidth.getX() );
         CGContextSetMiterLimit(maContextHolder.get(), fCGMiterLimit);
         CGContextDrawPath( maContextHolder.get(), kCGPathStroke );
         maContextHolder.restoreState();
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
old mode 100644
new mode 100755
index a1d8c00674d8..a4ca9f0aeb55
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -34,7 +34,9 @@
 #include <SkDashPathEffect.h>
 #include <GrBackendSurface.h>
 
+#include <numeric>
 #include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
 
 namespace
 {
@@ -622,6 +624,7 @@ void SkiaSalGraphicsImpl::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAr
     aPolygon.setClosed(false);
 
     drawPolyLine(basegfx::B2DHomMatrix(), aPolygon, 0.0, basegfx::B2DVector(1.0, 1.0),
+                 nullptr, // MM01
                  basegfx::B2DLineJoin::Miter, css::drawing::LineCap_BUTT,
                  basegfx::deg2rad(15.0) /*default*/, false);
 }
@@ -706,34 +709,60 @@ bool SkiaSalGraphicsImpl::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectTo
 
 bool SkiaSalGraphicsImpl::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
                                        const basegfx::B2DPolygon& rPolyLine, double fTransparency,
-                                       const basegfx::B2DVector& rLineWidths,
+                                       const basegfx::B2DVector& rLineWidth,
+                                       const std::vector<double>* pStroke, // MM01
                                        basegfx::B2DLineJoin eLineJoin,
                                        css::drawing::LineCap eLineCap, double fMiterMinimumAngle,
                                        bool bPixelSnapHairline)
 {
-    if (rPolyLine.count() == 0 || fTransparency < 0.0 || fTransparency >= 1.0
+    // MM01 check done for simple reasons
+    if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0
         || mLineColor == SALCOLOR_NONE)
+    {
         return true;
+    }
 
     preDraw();
     SAL_INFO("vcl.skia", "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor);
 
     // need to check/handle LineWidth when ObjectToDevice transformation is used
-    const basegfx::B2DVector aDeviceLineWidths(rObjectToDevice * rLineWidths);
-    const bool bCorrectLineWidth(aDeviceLineWidths.getX() < 1.0 && rLineWidths.getX() >= 1.0);
-    const basegfx::B2DVector aLineWidths(bCorrectLineWidth ? rLineWidths : aDeviceLineWidths);
+    const basegfx::B2DVector aDeviceLineWidth(rObjectToDevice * rLineWidth);
+    const bool bCorrectLineWidth(aDeviceLineWidth.getX() < 1.0 && rLineWidth.getX() >= 1.0);
+    const basegfx::B2DVector aLineWidth(bCorrectLineWidth ? rLineWidth : aDeviceLineWidth);
 
     // Skia does not support B2DLineJoin::NONE; return false to use
     // the fallback (own geometry preparation),
     // linejoin-mode and thus the above only applies to "fat" lines.
-    if ((basegfx::B2DLineJoin::NONE == eLineJoin) && (aLineWidths.getX() > 1.3))
+    if ((basegfx::B2DLineJoin::NONE == eLineJoin) && (aLineWidth.getX() > 1.3))
         return false;
 
+    // MM01 need to do line dashing as fallback stuff here now
+    const double fDotDashLength(
+        nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
+    const bool bStrokeUsed(0.0 != fDotDashLength);
+    basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+    if (bStrokeUsed)
+    {
+        // apply LineStyle
+        basegfx::utils::applyLineDashing(rPolyLine, // source
+                                         *pStroke, // pattern
+                                         &aPolyPolygonLine, // traget for lines
+                                         nullptr, // target for gaps
+                                         fDotDashLength); // full length if available
+    }
+    else
+    {
+        // no line dashing, just copy
+        aPolyPolygonLine.append(rPolyLine);
+    }
+
     // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
-    basegfx::B2DPolygon aPolyLine(rPolyLine);
-    aPolyLine.transform(rObjectToDevice);
+    aPolyPolygonLine.transform(rObjectToDevice);
     if (bPixelSnapHairline)
-        aPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyLine);
+    {
+        aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
+    }
 
     // Setup Line Join
     SkPaint::Join eSkLineJoin = SkPaint::kMiter_Join;
@@ -776,11 +805,18 @@ bool SkiaSalGraphicsImpl::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDev
     aPaint.setStrokeJoin(eSkLineJoin);
     aPaint.setColor(toSkColorWithTransparency(mLineColor, fTransparency));
     aPaint.setStrokeMiter(fMiterLimit);
-    aPaint.setStrokeWidth(aLineWidths.getX());
+    aPaint.setStrokeWidth(aLineWidth.getX());
     aPaint.setAntiAlias(mParent.getAntiAliasB2DDraw());
 
     SkPath aPath;
-    addPolygonToPath(aPolyLine, aPath);
+
+    // MM01 checked/verified for Skia (on Win)
+    for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+    {
+        const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
+        addPolygonToPath(aPolyLine, aPath);
+    }
+
     aPath.setFillType(SkPathFillType::kEvenOdd);
     // Apply the same adjustment as toSkX()/toSkY() do. Do it here even in the non-GPU
     // case as it seems to produce better results.
diff --git a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx
old mode 100644
new mode 100755
index 4133c3c46a25..747c0543c20e
--- a/vcl/source/gdi/FileDefinitionWidgetDraw.cxx
+++ b/vcl/source/gdi/FileDefinitionWidgetDraw.cxx
@@ -298,6 +298,7 @@ void drawFromDrawCommands(gfx::DrawRoot const& rDrawRoot, SalGraphics& rGraphics
                     rGraphics.DrawPolyLine(
                         basegfx::B2DHomMatrix(), aB2DPolygon, 1.0 - rRectangle.mnOpacity,
                         basegfx::B2DVector(rRectangle.mnStrokeWidth, rRectangle.mnStrokeWidth),
+                        nullptr, // MM01
                         basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false,
                         nullptr);
                 }
@@ -345,6 +346,7 @@ void drawFromDrawCommands(gfx::DrawRoot const& rDrawRoot, SalGraphics& rGraphics
                         rGraphics.DrawPolyLine(
                             basegfx::B2DHomMatrix(), rPolygon, 1.0 - rPath.mnOpacity,
                             basegfx::B2DVector(rPath.mnStrokeWidth, rPath.mnStrokeWidth),
+                            nullptr, // MM01
                             basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false,
                             nullptr);
                     }
@@ -387,6 +389,7 @@ void munchDrawCommands(std::vector<std::shared_ptr<WidgetDrawAction>> const& rDr
                 rGraphics.DrawPolyLine(
                     basegfx::B2DHomMatrix(), aB2DPolygon, 0.0f,
                     basegfx::B2DVector(rWidgetDraw.mnStrokeWidth, rWidgetDraw.mnStrokeWidth),
+                    nullptr, // MM01
                     basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false, nullptr);
             }
             break;
@@ -410,6 +413,7 @@ void munchDrawCommands(std::vector<std::shared_ptr<WidgetDrawAction>> const& rDr
                 rGraphics.DrawPolyLine(
                     basegfx::B2DHomMatrix(), aB2DPolygon, 0.0f,
                     basegfx::B2DVector(rWidgetDraw.mnStrokeWidth, rWidgetDraw.mnStrokeWidth),
+                    nullptr, // MM01
                     basegfx::B2DLineJoin::Round, css::drawing::LineCap_ROUND, 0.0f, false, nullptr);
             }
             break;
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
index cb8b8a8e8fbe..fa5656b2f682 100644
--- a/vcl/source/gdi/salgdilayout.cxx
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -573,6 +573,7 @@ bool SalGraphics::DrawPolyLine(
     const basegfx::B2DPolygon& i_rPolygon,
     double i_fTransparency,
     const basegfx::B2DVector& i_rLineWidth,
+    const std::vector< double >* i_pStroke, // MM01
     basegfx::B2DLineJoin i_eLineJoin,
     css::drawing::LineCap i_eLineCap,
     double i_fMiterMinimumAngle,
@@ -601,6 +602,7 @@ bool SalGraphics::DrawPolyLine(
                     i_rPolygon,
                     i_fTransparency,
                     i_rLineWidth,
+                    i_pStroke, // MM01
                     i_eLineJoin,
                     i_eLineCap,
                     i_fMiterMinimumAngle,
@@ -628,6 +630,7 @@ bool SalGraphics::DrawPolyLine(
                     i_rPolygon,
                     i_fTransparency,
                     i_rLineWidth,
+                    i_pStroke, // MM01
                     i_eLineJoin,
                     i_eLineCap,
                     i_fMiterMinimumAngle,
@@ -642,6 +645,7 @@ bool SalGraphics::DrawPolyLine(
         i_rPolygon,
         i_fTransparency,
         i_rLineWidth,
+        i_pStroke, // MM01
         i_eLineJoin,
         i_eLineCap,
         i_fMiterMinimumAngle,
diff --git a/vcl/source/outdev/line.cxx b/vcl/source/outdev/line.cxx
index a9bdffb7b8e5..3332ab711a24 100644
--- a/vcl/source/outdev/line.cxx
+++ b/vcl/source/outdev/line.cxx
@@ -130,6 +130,7 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt )
             aB2DPolyLine,
             0.0,
             aB2DLineWidth,
+            nullptr, // MM01
             basegfx::B2DLineJoin::NONE,
             css::drawing::LineCap_BUTT,
             basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
@@ -241,6 +242,7 @@ void OutputDevice::drawLine( basegfx::B2DPolyPolygon aLinePolyPolygon, const Lin
                     rB2DPolygon,
                     0.0,
                     basegfx::B2DVector(1.0,1.0),
+                    nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
                     basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx
index 9b0cb3819cc7..c33374f3a408 100644
--- a/vcl/source/outdev/polygon.cxx
+++ b/vcl/source/outdev/polygon.cxx
@@ -98,6 +98,7 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly )
                     rPolygon,
                     0.0,
                     aB2DLineWidth,
+                    nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
                     basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
@@ -216,6 +217,7 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly )
                 aB2DPolygon,
                 0.0,
                 aB2DLineWidth,
+                nullptr, // MM01
                 basegfx::B2DLineJoin::NONE,
                 css::drawing::LineCap_BUTT,
                 basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
@@ -326,6 +328,7 @@ void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP
                     rPolygon,
                     0.0,
                     aB2DLineWidth,
+                    nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
                     basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
diff --git a/vcl/source/outdev/polyline.cxx b/vcl/source/outdev/polyline.cxx
index f070ebe690c2..161bf5fb4e52 100644
--- a/vcl/source/outdev/polyline.cxx
+++ b/vcl/source/outdev/polyline.cxx
@@ -73,6 +73,7 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly )
         aB2DPolyLine,
         0.0,
         aB2DLineWidth,
+        nullptr, // MM01
         basegfx::B2DLineJoin::NONE,
         css::drawing::LineCap_BUTT,
         basegfx::deg2rad(15.0) /*default fMiterMinimumAngle, not used*/,
@@ -176,6 +177,7 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon,
         rB2DPolygon,
         fLineWidth,
         0.0,
+        nullptr, // MM01
         eLineJoin,
         eLineCap,
         fMiterMinimumAngle))
@@ -232,6 +234,7 @@ void OutputDevice::DrawPolyLine( const basegfx::B2DPolygon& rB2DPolygon,
                 rPolygon,
                 0.0,
                 0.0,
+                nullptr, // MM01
                 basegfx::B2DLineJoin::NONE,
                 css::drawing::LineCap_BUTT,
                 basegfx::deg2rad(15.0) /*default, not used*/,
@@ -303,6 +306,7 @@ bool OutputDevice::DrawPolyLineDirect(
     const basegfx::B2DPolygon& rB2DPolygon,
     double fLineWidth,
     double fTransparency,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
@@ -347,6 +351,7 @@ bool OutputDevice::DrawPolyLineDirect(
             rB2DPolygon,
             fTransparency,
             aB2DLineWidth,
+            pStroke, // MM01
             eLineJoin,
             eLineCap,
             fMiterMinimumAngle,
diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx
index 571855dde2b5..e52b02410ebd 100644
--- a/vcl/source/outdev/textline.cxx
+++ b/vcl/source/outdev/textline.cxx
@@ -1008,9 +1008,16 @@ void OutputDevice::DrawWaveLine(const Point& rStartPos, const Point& rEndPos, lo
 
     mpGraphics->SetLineColor(GetLineColor());
     mpGraphics->DrawPolyLine(
-            aRotationMatrix, aWaveLinePolygon, 0.0, aLineWidth,
-            basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT,
-            basegfx::deg2rad(15.0), bPixelSnapHairline, this);
+            aRotationMatrix,
+            aWaveLinePolygon,
+            0.0,
+            aLineWidth,
+            nullptr, // MM01
+            basegfx::B2DLineJoin::NONE,
+            css::drawing::LineCap_BUTT,
+            basegfx::deg2rad(15.0),
+            bPixelSnapHairline,
+            this);
 
     if( mpAlphaVDev )
         mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nLineWidth );
diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx
index 78ea40bbd683..3c4a6fb2a1c0 100644
--- a/vcl/source/outdev/transparent.cxx
+++ b/vcl/source/outdev/transparent.cxx
@@ -270,6 +270,7 @@ void OutputDevice::DrawTransparent(
                     rPolygon,
                     fTransparency,
                     aHairlineWidth,
+                    nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
                     basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
@@ -392,6 +393,7 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly
                     rPolygon,
                     fTransparency,
                     aLineWidths,
+                    nullptr, // MM01
                     basegfx::B2DLineJoin::NONE,
                     css::drawing::LineCap_BUTT,
                     basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx
index f738591f6b28..12ac59808e4b 100644
--- a/vcl/unx/generic/gdi/gdiimpl.cxx
+++ b/vcl/unx/generic/gdi/gdiimpl.cxx
@@ -18,6 +18,8 @@
  */
 
 #include <memory>
+#include <numeric>
+
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/extensions/Xrender.h>
@@ -1584,6 +1586,7 @@ private:
     basegfx::B2DLineJoin                        meJoin;
     css::drawing::LineCap                       meCap;
     double                                      mfMiterMinimumAngle;
+    std::vector< double >                       maStroke;
 
 public:
     SystemDependentData_Triangulation(
@@ -1592,13 +1595,16 @@ public:
         const basegfx::B2DVector& rLineWidth,
         basegfx::B2DLineJoin eJoin,
         css::drawing::LineCap eCap,
-        double fMiterMinimumAngle);
+        double fMiterMinimumAngle,
+        const std::vector< double >* pStroke); // MM01
 
+    // read access
     const basegfx::triangulator::B2DTriangleVector& getTriangles() const { return maTriangles; }
     const basegfx::B2DVector& getLineWidth() const { return maLineWidth; }
     const basegfx::B2DLineJoin& getJoin() const { return meJoin; }
     const css::drawing::LineCap& getCap() const { return meCap; }
     double getMiterMinimumAngle() const { return mfMiterMinimumAngle; }
+    const std::vector< double >& getStroke() const { return maStroke; }
 
     virtual sal_Int64 estimateUsageInBytes() const override;
 };
@@ -1611,14 +1617,20 @@ SystemDependentData_Triangulation::SystemDependentData_Triangulation(
     const basegfx::B2DVector& rLineWidth,
     basegfx::B2DLineJoin eJoin,
     css::drawing::LineCap eCap,
-    double fMiterMinimumAngle)
+    double fMiterMinimumAngle,
+    const std::vector< double >* pStroke)
 :   basegfx::SystemDependentData(rSystemDependentDataManager),
     maTriangles(rTriangles),
     maLineWidth(rLineWidth),
     meJoin(eJoin),
     meCap(eCap),
-    mfMiterMinimumAngle(fMiterMinimumAngle)
+    mfMiterMinimumAngle(fMiterMinimumAngle),
+    maStroke()
 {
+    if(nullptr != pStroke)
+    {
+        maStroke = *pStroke;
+    }
 }
 
 sal_Int64 SystemDependentData_Triangulation::estimateUsageInBytes() const
@@ -1638,6 +1650,7 @@ bool X11SalGraphicsImpl::drawPolyLine(
     const basegfx::B2DPolygon& rPolygon,
     double fTransparency,
     const basegfx::B2DVector& rLineWidth,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
@@ -1655,7 +1668,6 @@ bool X11SalGraphicsImpl::drawPolyLine(
     const basegfx::B2DVector aDeviceLineWidths(bObjectToDeviceIsIdentity ? rLineWidth : rObjectToDevice * rLineWidth);
     const bool bCorrectLineWidth(!bObjectToDeviceIsIdentity && aDeviceLineWidths.getX() < 1.0 && aLineWidth.getX() >= 1.0);
     basegfx::B2DHomMatrix aObjectToDeviceInv;
-    basegfx::B2DPolygon aPolygon(rPolygon);
 
     if(bCorrectLineWidth)
     {
@@ -1673,6 +1685,25 @@ bool X11SalGraphicsImpl::drawPolyLine(
     std::shared_ptr<SystemDependentData_Triangulation> pSystemDependentData_Triangulation(
         rPolygon.getSystemDependentData<SystemDependentData_Triangulation>());
 
+    // MM01 need to do line dashing as fallback stuff here now
+    const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
+    const bool bStrokeUsed(0.0 != fDotDashLength);
+
+    if(pSystemDependentData_Triangulation)
+    {
+        // MM01 - check on stroke change. Used against not used, or if oth used,
+        // equal or different? Triangulation geometry creation depends heavily
+        // on stroke, independent of being transformation independent
+        const bool bStrokeWasUsed(!pSystemDependentData_Triangulation->getStroke().empty());
+
+        if(bStrokeWasUsed != bStrokeUsed
+        || (bStrokeUsed && *pStroke != pSystemDependentData_Triangulation->getStroke()))
+        {
+            // data invalid, forget
+            pSystemDependentData_Triangulation.reset();
+        }
+    }
+
     if(pSystemDependentData_Triangulation)
     {
         // check data validity (I)
@@ -1709,15 +1740,36 @@ bool X11SalGraphicsImpl::drawPolyLine(
 
     if(!pSystemDependentData_Triangulation)
     {
+        // MM01 need to do line dashing as fallback stuff here now
+        basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+        if(bStrokeUsed)
+        {
+            // apply LineStyle
+            basegfx::utils::applyLineDashing(
+                rPolygon, // source
+                *pStroke, // pattern
+                &aPolyPolygonLine, // traget for lines
+                nullptr, // target for gaps
+                fDotDashLength); // full length if available
+        }
+        else
+        {
+            // no line dashing, just copy
+            aPolyPolygonLine.append(rPolygon);
+        }
+
         // try to create data
         if(bPixelSnapHairline)
         {
+            // Do NOT transform, but keep device-independent. To
+            // do so, transform to device for snap, but back again after
             if(!bObjectToDeviceIsIdentity)
             {
-                aPolygon.transform(rObjectToDevice);
+                aPolyPolygonLine.transform(rObjectToDevice);
             }
 
-            aPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolygon);
+            aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
 
             if(!bObjectToDeviceIsIdentity)
             {
@@ -1727,12 +1779,31 @@ bool X11SalGraphicsImpl::drawPolyLine(
                     aObjectToDeviceInv.invert();
                 }
 
-                aPolygon.transform(aObjectToDeviceInv);
+                aPolyPolygonLine.transform(aObjectToDeviceInv);
             }
         }
 
         basegfx::triangulator::B2DTriangleVector aTriangles;
 
+        // MM01 checked/verified for X11 (linux)
+        for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+        {
+            const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
+            // MM01 upps - commit 51b5b93092d6231615de470c62494c24e54828a1 removed
+            // this *central* geometry-creating lines (!) probably due to aAreaPolyPoly
+            // *not* being used - that's true, but the work is inside of filling
+            // aTriangles data (!)
+            basegfx::utils::createAreaGeometry(
+                aPolyLine,
+                0.5 * aLineWidth.getX(),
+                eLineJoin,
+                eLineCap,
+                basegfx::deg2rad(12.5),
+                0.4,
+                fMiterMinimumAngle,
+                &aTriangles); // CAUTION! This is *needed* since it creates the data!
+        }
+
         if(!aTriangles.empty())
         {
             // Add to buffering mechanism
@@ -1744,7 +1815,8 @@ bool X11SalGraphicsImpl::drawPolyLine(
                 aLineWidth,
                 eLineJoin,
                 eLineCap,
-                fMiterMinimumAngle);
+                fMiterMinimumAngle,
+                pStroke);
         }
     }
 
diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx
index 6660e191342d..9a4940eab7d0 100644
--- a/vcl/unx/generic/gdi/gdiimpl.hxx
+++ b/vcl/unx/generic/gdi/gdiimpl.hxx
@@ -172,6 +172,7 @@ public:
                 const basegfx::B2DPolygon&,
                 double fTransparency,
                 const basegfx::B2DVector& rLineWidths,
+                const std::vector< double >* pStroke, // MM01
                 basegfx::B2DLineJoin,
                 css::drawing::LineCap,
                 double fMiterMinimumAngle,
diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx
index 864d3fdb8bd7..d5b6281bed3b 100644
--- a/vcl/unx/generic/gdi/salgdi.cxx
+++ b/vcl/unx/generic/gdi/salgdi.cxx
@@ -699,6 +699,7 @@ bool X11SalGraphics::drawPolyLine(
     const basegfx::B2DPolygon& rPolygon,
     double fTransparency,
     const basegfx::B2DVector& rLineWidth,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
@@ -735,6 +736,7 @@ bool X11SalGraphics::drawPolyLine(
                 rPolygon,
                 fTransparency,
                 rLineWidth,
+                pStroke, // MM01
                 eLineJoin,
                 eLineCap,
                 fMiterMinimumAngle,
@@ -754,6 +756,7 @@ bool X11SalGraphics::drawPolyLine(
         rPolygon,
         fTransparency,
         rLineWidth,
+        pStroke, // MM01
         eLineJoin,
         eLineCap,
         fMiterMinimumAngle,
diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx
index 901edb5c0f49..e0a6778f76ba 100644
--- a/vcl/unx/generic/print/genpspgraphics.cxx
+++ b/vcl/unx/generic/print/genpspgraphics.cxx
@@ -433,6 +433,7 @@ bool GenPspGraphics::drawPolyLine(
     const basegfx::B2DPolygon&,
     double /*fTransparency*/,
     const basegfx::B2DVector& /*rLineWidths*/,
+    const std::vector< double >* /*pStroke*/, // MM01
     basegfx::B2DLineJoin /*eJoin*/,
     css::drawing::LineCap /*eLineCap*/,
     double /*fMiterMinimumAngle*/,
diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx
index 875f4924fbf4..919395f48304 100644
--- a/vcl/win/gdi/gdiimpl.cxx
+++ b/vcl/win/gdi/gdiimpl.cxx
@@ -20,6 +20,7 @@
 #include <sal/config.h>
 
 #include <memory>
+#include <numeric>
 
 #include <svsys.h>
 
@@ -1987,18 +1988,19 @@ private:
     // all other values the triangulation is based on and
     // need to be compared with to check for data validity
     bool                                    mbNoLineJoin;
+    std::vector< double >                       maStroke;
 
 public:
     SystemDependentData_GraphicsPath(
         basegfx::SystemDependentDataManager& rSystemDependentDataManager,
         std::shared_ptr<Gdiplus::GraphicsPath>& rpGraphicsPath,
-        bool bNoLineJoin);
+        bool bNoLineJoin,
+        const std::vector< double >* pStroke); // MM01
 
-    // read access to Gdiplus::GraphicsPath
+    // read access
     std::shared_ptr<Gdiplus::GraphicsPath>& getGraphicsPath() { return mpGraphicsPath; }
-
-    // other data-validity access
     bool getNoLineJoin() const { return mbNoLineJoin; }
+    const std::vector< double >& getStroke() const { return maStroke; }
 
     virtual sal_Int64 estimateUsageInBytes() const override;
 };
@@ -2008,11 +2010,17 @@ public:
 SystemDependentData_GraphicsPath::SystemDependentData_GraphicsPath(
     basegfx::SystemDependentDataManager& rSystemDependentDataManager,
     std::shared_ptr<Gdiplus::GraphicsPath>& rpGraphicsPath,
-    bool bNoLineJoin)
+    bool bNoLineJoin,
+    const std::vector< double >* pStroke)
 :   basegfx::SystemDependentData(rSystemDependentDataManager),
     mpGraphicsPath(rpGraphicsPath),
-    mbNoLineJoin(bNoLineJoin)
+    mbNoLineJoin(bNoLineJoin),
+    maStroke()
 {
+    if(nullptr != pStroke)
+    {
+        maStroke = *pStroke;
+    }
 }
 
 sal_Int64 SystemDependentData_GraphicsPath::estimateUsageInBytes() const
@@ -2136,7 +2144,8 @@ bool WinSalGraphicsImpl::drawPolyPolygon(
         rPolyPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>(
             ImplGetSystemDependentDataManager(),
             pGraphicsPath,
-            false);
+            false,
+            nullptr);
     }
 
     if(mrParent.getAntiAliasB2DDraw())
@@ -2196,12 +2205,14 @@ bool WinSalGraphicsImpl::drawPolyLine(
     const basegfx::B2DPolygon& rPolygon,
     double fTransparency,
     const basegfx::B2DVector& rLineWidths,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
     bool bPixelSnapHairline)
 {
-    if(!mbPen || 0 == rPolygon.count())
+    // MM01 check done for simple reasons
+    if(!mbPen || !rPolygon.count() || fTransparency < 0.0 || fTransparency > 1.0)
     {
         return true;
     }
@@ -2293,6 +2304,25 @@ bool WinSalGraphicsImpl::drawPolyLine(
     std::shared_ptr<SystemDependentData_GraphicsPath> pSystemDependentData_GraphicsPath(
         rPolygon.getSystemDependentData<SystemDependentData_GraphicsPath>());
 
+    // MM01 need to do line dashing as fallback stuff here now
+    const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
+    const bool bStrokeUsed(0.0 != fDotDashLength);
+
+    if(pSystemDependentData_GraphicsPath)
+    {
+        // MM01 - check on stroke change. Used against not used, or if oth used,
+        // equal or different? Triangulation geometry creation depends heavily
+        // on stroke, independent of being transformation independent
+        const bool bStrokeWasUsed(!pSystemDependentData_GraphicsPath->getStroke().empty());
+
+        if(bStrokeWasUsed != bStrokeUsed
+        || (bStrokeUsed && *pStroke != pSystemDependentData_GraphicsPath->getStroke()))
+        {
+            // data invalid, forget
+            pSystemDependentData_GraphicsPath.reset();
+        }
+    }
+
     if(pSystemDependentData_GraphicsPath)
     {
         // check data validity
@@ -2314,17 +2344,47 @@ bool WinSalGraphicsImpl::drawPolyLine(
         // fill data of buffered data
         pGraphicsPath = std::make_shared<Gdiplus::GraphicsPath>();
 
-        impAddB2DPolygonToGDIPlusGraphicsPathReal(
-            *pGraphicsPath,
-            rPolygon,
-            rObjectToDevice,
-            bNoLineJoin,
-            bPixelSnapHairline);
-
-        if(rPolygon.isClosed() && !bNoLineJoin)
+        if(bStrokeUsed)
         {
-            // #i101491# needed to create the correct line joins
-            pGraphicsPath->CloseFigure();
+            // MM01 need to do line dashing as fallback stuff here now
+            basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+            // apply LineStyle
+            basegfx::utils::applyLineDashing(
+                rPolygon, // source
+                *pStroke, // pattern
+                &aPolyPolygonLine, // traget for lines
+                nullptr, // target for gaps
+                fDotDashLength); // full length if available
+
+            // MM01 checked/verified, ok
+            for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+            {
+                const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
+                pGraphicsPath->StartFigure();
+                impAddB2DPolygonToGDIPlusGraphicsPathReal(
+                    *pGraphicsPath,
+                    aPolyLine,
+                    rObjectToDevice,
+                    bNoLineJoin,
+                    bPixelSnapHairline);
+            }
+        }
+        else
+        {
+            // no line dashing, just copy
+            impAddB2DPolygonToGDIPlusGraphicsPathReal(
+                *pGraphicsPath,
+                rPolygon,
+                rObjectToDevice,
+                bNoLineJoin,
+                bPixelSnapHairline);
+
+            if(rPolygon.isClosed() && !bNoLineJoin)
+            {
+                // #i101491# needed to create the correct line joins
+                pGraphicsPath->CloseFigure();
+            }
         }
 
         // add to buffering mechanism
@@ -2333,7 +2393,8 @@ bool WinSalGraphicsImpl::drawPolyLine(
             rPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>(
                 ImplGetSystemDependentDataManager(),
                 pGraphicsPath,
-                bNoLineJoin);
+                bNoLineJoin,
+                pStroke);
         }
     }
 
diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx
index 3b3b1837b930..eb56388ff42d 100644
--- a/vcl/win/gdi/gdiimpl.hxx
+++ b/vcl/win/gdi/gdiimpl.hxx
@@ -130,6 +130,7 @@ public:
                 const basegfx::B2DPolygon&,
                 double fTransparency,
                 const basegfx::B2DVector& rLineWidths,
+                const std::vector< double >* pStroke, // MM01
                 basegfx::B2DLineJoin,
                 css::drawing::LineCap,
                 double fMiterMinimumAngle,
diff --git a/vcl/win/gdi/salgdi_gdiplus.cxx b/vcl/win/gdi/salgdi_gdiplus.cxx
index 99c7d0e506e9..ce2f2cc69c20 100644
--- a/vcl/win/gdi/salgdi_gdiplus.cxx
+++ b/vcl/win/gdi/salgdi_gdiplus.cxx
@@ -42,6 +42,7 @@ bool WinSalGraphics::drawPolyLine(
     const basegfx::B2DPolygon& rPolygon,
     double fTransparency,
     const basegfx::B2DVector& rLineWidths,
+    const std::vector< double >* pStroke, // MM01
     basegfx::B2DLineJoin eLineJoin,
     css::drawing::LineCap eLineCap,
     double fMiterMinimumAngle,
@@ -52,6 +53,7 @@ bool WinSalGraphics::drawPolyLine(
         rPolygon,
         fTransparency,
         rLineWidths,
+        pStroke, // MM01
         eLineJoin,
         eLineCap,
         fMiterMinimumAngle,


More information about the Libreoffice-commits mailing list