vcl/headless/CairoCommon.cxx        |  249 ++++++++++++++++++++++++++
 vcl/headless/SvpGraphicsBackend.cxx |   52 ++++-
 vcl/headless/svpgdi.cxx             |  337 ------------------------------------
 vcl/inc/headless/CairoCommon.hxx    |   15 +
 vcl/inc/headless/svpgdi.hxx         |   29 ---
 vcl/unx/generic/gdi/salgdi.cxx      |    2 
 6 files changed, 307 insertions(+), 377 deletions(-)

New commits:
commit 8d6343e6b29fc6162d88b25dfa3a165e0d1b063d
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Wed Dec 15 11:56:09 2021 +0900
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Sat Jan 1 16:04:27 2022 +0100

    vcl: move drawPolyLine (+legacy) to SvpGraphicsBackend
    
    Also moves drawPolyLine with cairo context param. to CairoCommon
    as it is also needed in X11SalGraphics::drawPolyLine.
    
    Change-Id: I49b24bc31ecf3f6ab3cebca4eaab351c91564db5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127740
    Tested-by: Tomaž Vajngerl <qui...@gmail.com>
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx
index 40115a90db1f..7161feb7f29f 100644
--- a/vcl/headless/CairoCommon.cxx
+++ b/vcl/headless/CairoCommon.cxx
@@ -22,6 +22,10 @@
 #include <vcl/BitmapTools.hxx>
 #include <svdata.hxx>
 #include <basegfx/utils/canvastools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
 void dl_cairo_surface_set_device_scale(cairo_surface_t* surface, double 
x_scale, double y_scale)
 {
 #ifdef ANDROID
@@ -584,4 +588,249 @@ void CairoCommon::clipRegion(cairo_t* cr, const 
vcl::Region& rClipRegion)
 
 void CairoCommon::clipRegion(cairo_t* cr) { CairoCommon::clipRegion(cr, 
m_aClipRegion); }
 
+bool CairoCommon::drawPolyLine(cairo_t* cr, basegfx::B2DRange* pExtents, const 
Color& rLineColor,
+                               bool bAntiAlias, const basegfx::B2DHomMatrix& 
rObjectToDevice,
+                               const basegfx::B2DPolygon& rPolyLine, double 
fTransparency,
+                               double fLineWidth, const std::vector<double>* 
pStroke,
+                               basegfx::B2DLineJoin eLineJoin, 
css::drawing::LineCap eLineCap,
+                               double fMiterMinimumAngle, bool 
bPixelSnapHairline)
+{
+    // short circuit if there is nothing to do
+    if (0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0)
+    {
+        return true;
+    }
+
+    // need to check/handle LineWidth when ObjectToDevice transformation is 
used
+    const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity());
+
+    // tdf#124848 calculate-back logical LineWidth for a hairline
+    // since this implementation hands over the transformation to
+    // the graphic sub-system
+    if (fLineWidth == 0)
+    {
+        fLineWidth = 1.0;
+
+        if (!bObjectToDeviceIsIdentity)
+        {
+            basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice);
+            aObjectToDeviceInv.invert();
+            fLineWidth = (aObjectToDeviceInv * basegfx::B2DVector(fLineWidth, 
0)).getLength();
+        }
+    }
+
+    // PixelOffset used: Need to reflect in linear transformation
+    cairo_matrix_t aMatrix;
+    basegfx::B2DHomMatrix 
aDamageMatrix(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5));
+
+    if (bObjectToDeviceIsIdentity)
+    {
+        // Set PixelOffset as requested
+        cairo_matrix_init_translate(&aMatrix, 0.5, 0.5);
+    }
+    else
+    {
+        // Prepare ObjectToDevice transformation. Take PixelOffset for Lines 
into
+        // account: Multiply from left to act in DeviceCoordinates
+        aDamageMatrix = aDamageMatrix * rObjectToDevice;
+        cairo_matrix_init(&aMatrix, aDamageMatrix.get(0, 0), 
aDamageMatrix.get(1, 0),
+                          aDamageMatrix.get(0, 1), aDamageMatrix.get(1, 1), 
aDamageMatrix.get(0, 2),
+                          aDamageMatrix.get(1, 2));
+    }
+
+    // set linear transformation
+    cairo_set_matrix(cr, &aMatrix);
+
+    // setup line attributes
+    cairo_line_join_t eCairoLineJoin = CAIRO_LINE_JOIN_MITER;
+    switch (eLineJoin)
+    {
+        case basegfx::B2DLineJoin::Bevel:
+            eCairoLineJoin = CAIRO_LINE_JOIN_BEVEL;
+            break;
+        case basegfx::B2DLineJoin::Round:
+            eCairoLineJoin = CAIRO_LINE_JOIN_ROUND;
+            break;
+        case basegfx::B2DLineJoin::NONE:
+        case basegfx::B2DLineJoin::Miter:
+            eCairoLineJoin = CAIRO_LINE_JOIN_MITER;
+            break;
+    }
+
+    // convert miter minimum angle to miter limit
+    double fMiterLimit = 1.0 / sin(fMiterMinimumAngle / 2.0);
+
+    // setup cap attribute
+    cairo_line_cap_t eCairoLineCap(CAIRO_LINE_CAP_BUTT);
+
+    switch (eLineCap)
+    {
+        default: // css::drawing::LineCap_BUTT:
+        {
+            eCairoLineCap = CAIRO_LINE_CAP_BUTT;
+            break;
+        }
+        case css::drawing::LineCap_ROUND:
+        {
+            eCairoLineCap = CAIRO_LINE_CAP_ROUND;
+            break;
+        }
+        case css::drawing::LineCap_SQUARE:
+        {
+            eCairoLineCap = CAIRO_LINE_CAP_SQUARE;
+            break;
+        }
+    }
+
+    cairo_set_source_rgba(cr, rLineColor.GetRed() / 255.0, 
rLineColor.GetGreen() / 255.0,
+                          rLineColor.GetBlue() / 255.0, 1.0 - fTransparency);
+
+    cairo_set_line_join(cr, eCairoLineJoin);
+    cairo_set_line_cap(cr, eCairoLineCap);
+    cairo_set_line_width(cr, fLineWidth);
+    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);
+    assert(!bStrokeUsed || (bStrokeUsed && pStroke));
+
+    // MM01 decide if to stroke directly
+    static const bool bDoDirectCairoStroke(true);
+
+    // MM01 activate to stroke directly
+    if (bDoDirectCairoStroke && bStrokeUsed)
+    {
+        cairo_set_dash(cr, pStroke->data(), pStroke->size(), 0.0);
+    }
+
+    if (!bDoDirectCairoStroke && 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(fLineWidth, 0.0)));
+
+    if (pSystemDependentData_CairoPath)
+    {
+        // check data validity
+        if (nullptr == pSystemDependentData_CairoPath->getCairoPath()
+            || pSystemDependentData_CairoPath->getNoJoin() != bNoJoin
+            || pSystemDependentData_CairoPath->getAntiAlias() != bAntiAlias
+            || bPixelSnapHairline /*tdf#124700*/)
+        {
+            // data invalid, forget
+            pSystemDependentData_CairoPath.reset();
+        }
+    }
+
+    if (pSystemDependentData_CairoPath)
+    {
+        // re-use data
+        cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath());
+    }
+    else
+    {
+        // create data
+        size_t nSizeMeasure(0);
+
+        // MM01 need to do line dashing as fallback stuff here now
+        basegfx::B2DPolyPolygon aPolyPolygonLine;
+
+        if (!bDoDirectCairoStroke && bStrokeUsed)
+        {
+            // apply LineStyle
+            basegfx::utils::applyLineDashing(rPolyLine, // source
+                                             *pStroke, // pattern
+                                             &aPolyPolygonLine, // target for 
lines
+                                             nullptr, // target for gaps
+                                             fDotDashLength); // full length 
if available
+        }
+        else
+        {
+            // no line dashing or direct stroke, just copy
+            aPolyPolygonLine.append(rPolyLine);
+        }
+
+        // MM01 checked/verified for Cairo
+        for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
+        {
+            const basegfx::B2DPolygon 
aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
+
+            if (!bNoJoin)
+            {
+                // PixelOffset now reflected in linear transformation used
+                nSizeMeasure
+                    += AddPolygonToPath(cr, aPolyLine,
+                                        rObjectToDevice, // ObjectToDevice 
*without* LineDraw-Offset
+                                        !bAntiAlias, 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));
+
+                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
+                        !bAntiAlias, bPixelSnapHairline);
+
+                    // prepare next step
+                    aEdge.setB2DPoint(0, aEdge.getB2DPoint(1));
+                }
+            }
+        }
+
+        // copy and add to buffering mechanism
+        if (!bPixelSnapHairline /*tdf#124700*/)
+        {
+            pSystemDependentData_CairoPath
+                = 
rPolyLine.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>(
+                    ImplGetSystemDependentDataManager(), nSizeMeasure, cr, 
bNoJoin, bAntiAlias,
+                    pStroke);
+        }
+    }
+
+    // extract extents
+    if (pExtents)
+    {
+        *pExtents = getClippedStrokeDamage(cr);
+        // transform also extents (ranges) of damage so they can be correctly 
redrawn
+        pExtents->transform(aDamageMatrix);
+    }
+
+    // draw and consume
+    cairo_stroke(cr);
+
+    return true;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/headless/SvpGraphicsBackend.cxx 
b/vcl/headless/SvpGraphicsBackend.cxx
index f19749196cab..e955790bd247 100644
--- a/vcl/headless/SvpGraphicsBackend.cxx
+++ b/vcl/headless/SvpGraphicsBackend.cxx
@@ -187,7 +187,19 @@ void SvpGraphicsBackend::drawRect(tools::Long nX, 
tools::Long nY, tools::Long nW
     m_rCairoCommon.m_aLineColor = aOrigLineColor;
 }
 
-void SvpGraphicsBackend::drawPolyLine(sal_uInt32 /*nPoints*/, const Point* 
/*pPtAry*/) {}
+void SvpGraphicsBackend::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry)
+{
+    basegfx::B2DPolygon aPoly;
+    aPoly.append(basegfx::B2DPoint(pPtAry->getX(), pPtAry->getY()), nPoints);
+    for (sal_uInt32 i = 1; i < nPoints; ++i)
+        aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].getX(), 
pPtAry[i].getY()));
+    aPoly.setClosed(false);
+
+    drawPolyLine(basegfx::B2DHomMatrix(), aPoly, 0.0, 1.0,
+                 nullptr, // MM01
+                 basegfx::B2DLineJoin::Miter, css::drawing::LineCap_BUTT,
+                 basegfx::deg2rad(15.0) /*default*/, false);
+}
 
 void SvpGraphicsBackend::drawPolygon(sal_uInt32 /*nPoints*/, const Point* 
/*pPtAry*/) {}
 
@@ -281,15 +293,37 @@ bool SvpGraphicsBackend::drawPolyPolygon(const 
basegfx::B2DHomMatrix& rObjectToD
     return true;
 }
 
-bool SvpGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& 
/*rObjectToDevice*/,
-                                      const basegfx::B2DPolygon& /*rPolyLine*/,
-                                      double /*fTransparency*/, double 
/*fLineWidth*/,
-                                      const std::vector<double>* /*pStroke*/,
-                                      basegfx::B2DLineJoin /*eLineJoin*/,
-                                      css::drawing::LineCap /*eLineCap*/,
-                                      double /*fMiterMinimumAngle*/, bool 
/*bPixelSnapHairline*/)
+bool SvpGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& 
rObjectToDevice,
+                                      const basegfx::B2DPolygon& rPolyLine, 
double fTransparency,
+                                      double fLineWidth, const 
std::vector<double>* pStroke,
+                                      basegfx::B2DLineJoin eLineJoin,
+                                      css::drawing::LineCap eLineCap, double 
fMiterMinimumAngle,
+                                      bool bPixelSnapHairline)
 {
-    return false;
+    // short circuit if there is nothing to do
+    if (0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0)
+    {
+        return true;
+    }
+
+    // Wrap call to static version of ::drawPolyLine by
+    // preparing/getting some local data and parameters
+    // due to usage in vcl/unx/generic/gdi/salgdi.cxx.
+    // This is mainly about extended handling of extents
+    // and the way destruction of CairoContext is handled
+    // due to current XOR stuff
+    cairo_t* cr = m_rCairoCommon.getCairoContext(false, getAntiAlias());
+    basegfx::B2DRange aExtents;
+    m_rCairoCommon.clipRegion(cr);
+
+    bool bRetval(CairoCommon::drawPolyLine(cr, &aExtents, 
m_rCairoCommon.m_aLineColor,
+                                           getAntiAlias(), rObjectToDevice, 
rPolyLine,
+                                           fTransparency, fLineWidth, pStroke, 
eLineJoin, eLineCap,
+                                           fMiterMinimumAngle, 
bPixelSnapHairline));
+
+    m_rCairoCommon.releaseCairoContext(cr, false, aExtents);
+
+    return bRetval;
 }
 
 bool SvpGraphicsBackend::drawPolyLineBezier(sal_uInt32, const Point*, const 
PolyFlags*)
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index c4f0810c8b83..ce9f7928a1bb 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -852,26 +852,6 @@ void SvpSalGraphics::GetResolution( sal_Int32& rDPIX, 
sal_Int32& rDPIY )
     rDPIX = rDPIY = 96;
 }
 
-void SvpSalGraphics::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry)
-{
-    basegfx::B2DPolygon aPoly;
-    aPoly.append(basegfx::B2DPoint(pPtAry->getX(), pPtAry->getY()), nPoints);
-    for (sal_uInt32 i = 1; i < nPoints; ++i)
-        aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].getX(), 
pPtAry[i].getY()));
-    aPoly.setClosed(false);
-
-    drawPolyLine(
-        basegfx::B2DHomMatrix(),
-        aPoly,
-        0.0,
-        1.0,
-        nullptr, // MM01
-        basegfx::B2DLineJoin::Miter,
-        css::drawing::LineCap_BUTT,
-        basegfx::deg2rad(15.0) /*default*/,
-        false);
-}
-
 void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry)
 {
     basegfx::B2DPolygon aPoly;
@@ -885,323 +865,6 @@ void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, 
const Point* pPtAry)
         0.0);
 }
 
-bool SvpSalGraphics::drawPolyLine(
-    const basegfx::B2DHomMatrix& rObjectToDevice,
-    const basegfx::B2DPolygon& rPolyLine,
-    double fTransparency,
-    double fLineWidth,
-    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() || fTransparency < 0.0 || fTransparency >= 1.0)
-    {
-        return true;
-    }
-
-    // Wrap call to static version of ::drawPolyLine by
-    // preparing/getting some local data and parameters
-    // due to usage in vcl/unx/generic/gdi/salgdi.cxx.
-    // This is mainly about extended handling of extents
-    // and the way destruction of CairoContext is handled
-    // due to current XOR stuff
-    cairo_t* cr = m_aCairoCommon.getCairoContext(false, getAntiAlias());
-    basegfx::B2DRange aExtents;
-    clipRegion(cr);
-
-    bool bRetval(
-        drawPolyLine(
-            cr,
-            &aExtents,
-            m_aCairoCommon.m_aLineColor,
-            getAntiAlias(),
-            rObjectToDevice,
-            rPolyLine,
-            fTransparency,
-            fLineWidth,
-            pStroke, // MM01
-            eLineJoin,
-            eLineCap,
-            fMiterMinimumAngle,
-            bPixelSnapHairline));
-
-    m_aCairoCommon.releaseCairoContext(cr, false, aExtents);
-
-    return bRetval;
-}
-
-bool SvpSalGraphics::drawPolyLine(
-    cairo_t* cr,
-    basegfx::B2DRange* pExtents,
-    const Color& rLineColor,
-    bool bAntiAlias,
-    const basegfx::B2DHomMatrix& rObjectToDevice,
-    const basegfx::B2DPolygon& rPolyLine,
-    double fTransparency,
-    double fLineWidth,
-    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() || fTransparency < 0.0 || fTransparency >= 1.0)
-    {
-        return true;
-    }
-
-    // need to check/handle LineWidth when ObjectToDevice transformation is 
used
-    const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity());
-
-    // tdf#124848 calculate-back logical LineWidth for a hairline
-    // since this implementation hands over the transformation to
-    // the graphic sub-system
-    if(fLineWidth == 0)
-    {
-        fLineWidth = 1.0;
-
-        if(!bObjectToDeviceIsIdentity)
-        {
-            basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice);
-            aObjectToDeviceInv.invert();
-            fLineWidth = (aObjectToDeviceInv * basegfx::B2DVector(fLineWidth, 
0)).getLength();
-        }
-    }
-
-    // PixelOffset used: Need to reflect in linear transformation
-    cairo_matrix_t aMatrix;
-    basegfx::B2DHomMatrix 
aDamageMatrix(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5));
-
-    if (bObjectToDeviceIsIdentity)
-    {
-        // Set PixelOffset as requested
-        cairo_matrix_init_translate(&aMatrix, 0.5, 0.5);
-    }
-    else
-    {
-        // Prepare ObjectToDevice transformation. Take PixelOffset for Lines 
into
-        // account: Multiply from left to act in DeviceCoordinates
-        aDamageMatrix = aDamageMatrix * rObjectToDevice;
-        cairo_matrix_init(
-            &aMatrix,
-            aDamageMatrix.get( 0, 0 ),
-            aDamageMatrix.get( 1, 0 ),
-            aDamageMatrix.get( 0, 1 ),
-            aDamageMatrix.get( 1, 1 ),
-            aDamageMatrix.get( 0, 2 ),
-            aDamageMatrix.get( 1, 2 ));
-    }
-
-    // set linear transformation
-    cairo_set_matrix(cr, &aMatrix);
-
-    // setup line attributes
-    cairo_line_join_t eCairoLineJoin = CAIRO_LINE_JOIN_MITER;
-    switch (eLineJoin)
-    {
-        case basegfx::B2DLineJoin::Bevel:
-            eCairoLineJoin = CAIRO_LINE_JOIN_BEVEL;
-            break;
-        case basegfx::B2DLineJoin::Round:
-            eCairoLineJoin = CAIRO_LINE_JOIN_ROUND;
-            break;
-        case basegfx::B2DLineJoin::NONE:
-        case basegfx::B2DLineJoin::Miter:
-            eCairoLineJoin = CAIRO_LINE_JOIN_MITER;
-            break;
-    }
-
-    // convert miter minimum angle to miter limit
-    double fMiterLimit = 1.0 / sin( fMiterMinimumAngle / 2.0);
-
-    // setup cap attribute
-    cairo_line_cap_t eCairoLineCap(CAIRO_LINE_CAP_BUTT);
-
-    switch (eLineCap)
-    {
-        default: // css::drawing::LineCap_BUTT:
-        {
-            eCairoLineCap = CAIRO_LINE_CAP_BUTT;
-            break;
-        }
-        case css::drawing::LineCap_ROUND:
-        {
-            eCairoLineCap = CAIRO_LINE_CAP_ROUND;
-            break;
-        }
-        case css::drawing::LineCap_SQUARE:
-        {
-            eCairoLineCap = CAIRO_LINE_CAP_SQUARE;
-            break;
-        }
-    }
-
-    cairo_set_source_rgba(
-        cr,
-        rLineColor.GetRed()/255.0,
-        rLineColor.GetGreen()/255.0,
-        rLineColor.GetBlue()/255.0,
-        1.0-fTransparency);
-
-    cairo_set_line_join(cr, eCairoLineJoin);
-    cairo_set_line_cap(cr, eCairoLineCap);
-    cairo_set_line_width(cr, fLineWidth);
-    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);
-    assert(!bStrokeUsed || (bStrokeUsed && pStroke));
-
-    // MM01 decide if to stroke directly
-    static const bool bDoDirectCairoStroke(true);
-
-    // MM01 activate to stroke directly
-    if(bDoDirectCairoStroke && bStrokeUsed)
-    {
-        cairo_set_dash(cr, pStroke->data(), pStroke->size(), 0.0);
-    }
-
-    if(!bDoDirectCairoStroke && 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(fLineWidth, 0.0)));
-
-    if(pSystemDependentData_CairoPath)
-    {
-        // check data validity
-        if(nullptr == pSystemDependentData_CairoPath->getCairoPath()
-            || pSystemDependentData_CairoPath->getNoJoin() != bNoJoin
-            || pSystemDependentData_CairoPath->getAntiAlias() != bAntiAlias
-            || bPixelSnapHairline /*tdf#124700*/ )
-        {
-            // data invalid, forget
-            pSystemDependentData_CairoPath.reset();
-        }
-    }
-
-    if(pSystemDependentData_CairoPath)
-    {
-        // re-use data
-        cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath());
-    }
-    else
-    {
-        // create data
-        size_t nSizeMeasure(0);
-
-        // MM01 need to do line dashing as fallback stuff here now
-        basegfx::B2DPolyPolygon aPolyPolygonLine;
-
-        if(!bDoDirectCairoStroke && bStrokeUsed)
-        {
-            // apply LineStyle
-            basegfx::utils::applyLineDashing(
-                rPolyLine, // source
-                *pStroke, // pattern
-                &aPolyPolygonLine, // target for lines
-                nullptr, // target for gaps
-                fDotDashLength); // full length if available
-        }
-        else
-        {
-            // no line dashing or direct stroke, just copy
-            aPolyPolygonLine.append(rPolyLine);
-        }
-
-        // MM01 checked/verified for Cairo
-        for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
-        {
-            const basegfx::B2DPolygon 
aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
-
-            if (!bNoJoin)
-            {
-                // PixelOffset now reflected in linear transformation used
-                nSizeMeasure += AddPolygonToPath(
-                    cr,
-                    aPolyLine,
-                    rObjectToDevice, // ObjectToDevice *without* 
LineDraw-Offset
-                    !bAntiAlias,
-                    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));
-
-                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
-                        !bAntiAlias,
-                        bPixelSnapHairline);
-
-                    // prepare next step
-                    aEdge.setB2DPoint(0, aEdge.getB2DPoint(1));
-                }
-            }
-        }
-
-        // copy and add to buffering mechanism
-        if (!bPixelSnapHairline /*tdf#124700*/)
-        {
-            pSystemDependentData_CairoPath = 
rPolyLine.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>(
-                ImplGetSystemDependentDataManager(),
-                nSizeMeasure,
-                cr,
-                bNoJoin,
-                bAntiAlias,
-                pStroke);
-        }
-    }
-
-    // extract extents
-    if (pExtents)
-    {
-        *pExtents = getClippedStrokeDamage(cr);
-        // transform also extents (ranges) of damage so they can be correctly 
redrawn
-        pExtents->transform(aDamageMatrix);
-    }
-
-    // draw and consume
-    cairo_stroke(cr);
-
-    return true;
-}
-
 bool SvpSalGraphics::drawGradient(const tools::PolyPolygon& rPolyPolygon, 
const Gradient& rGradient)
 {
     if (rGradient.GetStyle() != GradientStyle::Linear
diff --git a/vcl/inc/headless/CairoCommon.hxx b/vcl/inc/headless/CairoCommon.hxx
index 2f3cc16badfa..038bd3a42c35 100644
--- a/vcl/inc/headless/CairoCommon.hxx
+++ b/vcl/inc/headless/CairoCommon.hxx
@@ -28,11 +28,14 @@
 #include <vcl/region.hxx>
 #include <vcl/salgtype.hxx>
 
-#include <basegfx/utils/systemdependentdata.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
 
+#include <basegfx/utils/systemdependentdata.hxx>
 #include <basegfx/range/b2drange.hxx>
 #include <basegfx/range/b2irange.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
 
 //Using formats that match cairo's formats. For android we patch cairo,
 //which is internal in that case, to swap the rgb components so that
@@ -162,6 +165,16 @@ struct VCL_DLLPUBLIC CairoCommon
     void applyColor(cairo_t* cr, Color rColor, double fTransparency = 0.0);
     void clipRegion(cairo_t* cr);
     static void clipRegion(cairo_t* cr, const vcl::Region& rClipRegion);
+
+    // need this static version of ::drawPolyLine for usage from
+    // vcl/unx/generic/gdi/salgdi.cxx. It gets wrapped by
+    // ::drawPolyLine with some added parameters (see there)
+    static bool drawPolyLine(cairo_t* cr, basegfx::B2DRange* pExtents, const 
Color& rLineColor,
+                             bool bAntiAlias, const basegfx::B2DHomMatrix& 
rObjectToDevice,
+                             const basegfx::B2DPolygon& rPolyLine, double 
fTransparency,
+                             double fLineWidth, const std::vector<double>* 
pStroke,
+                             basegfx::B2DLineJoin eLineJoin, 
css::drawing::LineCap eLineCap,
+                             double fMiterMinimumAngle, bool 
bPixelSnapHairline);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index b9ece62a2267..e38aa3be55a4 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -54,24 +54,6 @@ public:
         return CairoCommon::getDamageKey();
     }
 
-    // need this static version of ::drawPolyLine for usage from
-    // vcl/unx/generic/gdi/salgdi.cxx. It gets wrapped by
-    // ::drawPolyLine with some added parameters (see there)
-    static bool drawPolyLine(
-        cairo_t* cr,
-        basegfx::B2DRange* pExtents,
-        const Color& rLineColor,
-        bool bAntiAlias,
-        const basegfx::B2DHomMatrix& rObjectToDevice,
-        const basegfx::B2DPolygon& rPolyLine,
-        double fTransparency,
-        double fLineWidth,
-        const std::vector< double >* pStroke, // MM01
-        basegfx::B2DLineJoin eLineJoin,
-        css::drawing::LineCap eLineCap,
-        double fMiterMinimumAngle,
-        bool bPixelSnapHairline);
-
     void copySource(const SalTwoRect& rTR, cairo_surface_t* source);
     void copyWithOperator(const SalTwoRect& rTR, cairo_surface_t* source,
                           cairo_operator_t eOp = CAIRO_OPERATOR_SOURCE);
@@ -137,17 +119,6 @@ public:
     virtual void            DrawTextLayout( const GenericSalLayout& ) override;
     virtual bool            supportsOperation( OutDevSupportType ) const 
override;
 
-    virtual bool            drawPolyLine(
-                                const basegfx::B2DHomMatrix& rObjectToDevice,
-                                const basegfx::B2DPolygon&,
-                                double fTransparency,
-                                double fLineWidth,
-                                const std::vector< double >* pStroke, // MM01
-                                basegfx::B2DLineJoin,
-                                css::drawing::LineCap,
-                                double fMiterMinimumAngle,
-                                bool bPixelSnapHairline) override;
-    virtual void            drawPolyLine( sal_uInt32 nPoints, const Point* 
pPtAry ) override;
     virtual void            drawPolygon( sal_uInt32 nPoints, const Point* 
pPtAry ) override;
 
     virtual bool drawGradient(tools::PolyPolygon const & rPolyPolygon, 
Gradient const & rGradient) override;
diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx
index 3b2946e2f18c..b5e1432764e6 100644
--- a/vcl/unx/generic/gdi/salgdi.cxx
+++ b/vcl/unx/generic/gdi/salgdi.cxx
@@ -733,7 +733,7 @@ bool X11SalGraphics::drawPolyLine(
         // Use the now available static drawPolyLine from the 
Cairo-Headless-Fallback
         // that will take care of all needed stuff
         const bool bRetval(
-            SvpSalGraphics::drawPolyLine(
+            CairoCommon::drawPolyLine(
                 cr,
                 nullptr,
                 mnPenColor,

Reply via email to