[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.4' - basegfx/source include/basegfx

Armin Le Grand (Collabora) (via logerrit) logerrit at kemper.freedesktop.org
Thu May 14 07:07:17 UTC 2020


 basegfx/source/polygon/b2dpolygontools.cxx  |  419 ++++++++++++++++------------
 include/basegfx/polygon/b2dpolygontools.hxx |   24 +
 2 files changed, 263 insertions(+), 180 deletions(-)

New commits:
commit d892e03f7dcbb7b8a6cc6a78dd758bab95ddded1
Author:     Armin Le Grand (Collabora) <Armin.Le.Grand at me.com>
AuthorDate: Fri Feb 14 12:32:42 2020 +0100
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Thu May 14 09:06:32 2020 +0200

    tdf#130655 added callback interface to ::applyLineDashing
    
    This version of the tooling method allows to avoid collecting line
    snippets in a return value PolyPolygon. Instead, offer lambda
    functions to get callbacks for created snippets. The original
    method using a B2DPolyPolygon return value is adapted to already
    use this, so serves as example of usage and ensures that only
    one identical algorithm is used.
    
    (cherry picked from commit 0dc4fddb9c76a3f4682eca4059b42a079e74e735)
    
    [ Fixes the cui/ build. ]
    
    Change-Id: Ie306968a895ad280fc2425fb40b3244769216ba0

diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx
index cbc18ee74203..245ed957fac3 100644
--- a/basegfx/source/polygon/b2dpolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolygontools.cxx
@@ -1113,7 +1113,102 @@ namespace basegfx
             return false;
         }
 
-        void applyLineDashing(const B2DPolygon& rCandidate, const std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fDotDashLength)
+        void applyLineDashing(
+            const B2DPolygon& rCandidate,
+            const std::vector<double>& rDotDashArray,
+            B2DPolyPolygon* pLineTarget,
+            B2DPolyPolygon* pGapTarget,
+            double fDotDashLength)
+        {
+            // clear targets in any case
+            if(pLineTarget)
+            {
+                pLineTarget->clear();
+            }
+
+            if(pGapTarget)
+            {
+                pGapTarget->clear();
+            }
+
+            // provide callbacks as lambdas
+            auto aLineCallback(
+                nullptr == pLineTarget
+                ? std::function<void(const basegfx::B2DPolygon&)>()
+                : [&pLineTarget](const basegfx::B2DPolygon& rSnippet){ pLineTarget->append(rSnippet); });
+            auto aGapCallback(
+                nullptr == pGapTarget
+                ? std::function<void(const basegfx::B2DPolygon&)>()
+                : [&pGapTarget](const basegfx::B2DPolygon& rSnippet){ pGapTarget->append(rSnippet); });
+
+            // call version that uses callbacks
+            applyLineDashing(
+                rCandidate,
+                rDotDashArray,
+                aLineCallback,
+                aGapCallback,
+                fDotDashLength);
+        }
+
+        static void implHandleSnippet(
+            const B2DPolygon& rSnippet,
+            std::function<void(const basegfx::B2DPolygon& rSnippet)>& rTargetCallback,
+            B2DPolygon& rFirst,
+            B2DPolygon& rLast)
+        {
+            if(rSnippet.isClosed())
+            {
+                if(!rFirst.count())
+                {
+                    rFirst = rSnippet;
+                }
+                else
+                {
+                    if(rLast.count())
+                    {
+                        rTargetCallback(rLast);
+                    }
+
+                    rLast = rSnippet;
+                }
+            }
+            else
+            {
+                rTargetCallback(rSnippet);
+            }
+        }
+
+        static void implHandleFirstLast(
+            std::function<void(const basegfx::B2DPolygon& rSnippet)>& rTargetCallback,
+            B2DPolygon& rFirst,
+            B2DPolygon& rLast)
+        {
+            if(rFirst.count() && rLast.count()
+                && rFirst.getB2DPoint(0).equal(rLast.getB2DPoint(rLast.count() - 1)))
+            {
+                // start of first and end of last are the same -> merge them
+                rLast.append(rFirst);
+                rLast.removeDoublePoints();
+                rFirst.clear();
+            }
+
+            if(rLast.count())
+            {
+                rTargetCallback(rLast);
+            }
+
+            if(rFirst.count())
+            {
+                rTargetCallback(rFirst);
+            }
+        }
+
+        void applyLineDashing(
+            const B2DPolygon& rCandidate,
+            const std::vector<double>& rDotDashArray,
+            std::function<void(const basegfx::B2DPolygon& rSnippet)> aLineTargetCallback,
+            std::function<void(const basegfx::B2DPolygon& rSnippet)> aGapTargetCallback,
+            double fDotDashLength)
         {
             const sal_uInt32 nPointCount(rCandidate.count());
             const sal_uInt32 nDotDashCount(rDotDashArray.size());
@@ -1123,244 +1218,210 @@ namespace basegfx
                 fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
             }
 
-            if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount)
+            if(fTools::lessOrEqual(fDotDashLength, 0.0) || (!aLineTargetCallback && !aGapTargetCallback) || !nPointCount)
             {
-                // clear targets
-                if(pLineTarget)
+                // parameters make no sense, just add source to targets
+                if(aLineTargetCallback)
                 {
-                    pLineTarget->clear();
+                    aLineTargetCallback(rCandidate);
                 }
 
-                if(pGapTarget)
+                if(aGapTargetCallback)
                 {
-                    pGapTarget->clear();
+                    aGapTargetCallback(rCandidate);
                 }
 
-                // prepare current edge's start
-                B2DCubicBezier aCurrentEdge;
-                const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
-                aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
+                return;
+            }
 
-                // prepare DotDashArray iteration and the line/gap switching bool
-                sal_uInt32 nDotDashIndex(0);
-                bool bIsLine(true);
-                double fDotDashMovingLength(rDotDashArray[0]);
-                B2DPolygon aSnippet;
+            // prepare current edge's start
+            B2DCubicBezier aCurrentEdge;
+            const bool bIsClosed(rCandidate.isClosed());
+            const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : nPointCount - 1);
+            aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
 
-                // iterate over all edges
-                for(sal_uInt32 a(0); a < nEdgeCount; a++)
-                {
-                    // update current edge (fill in C1, C2 and end point)
-                    double fLastDotDashMovingLength(0.0);
-                    const sal_uInt32 nNextIndex((a + 1) % nPointCount);
-                    aCurrentEdge.setControlPointA(rCandidate.getNextControlPoint(a));
-                    aCurrentEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
-                    aCurrentEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
+            // prepare DotDashArray iteration and the line/gap switching bool
+            sal_uInt32 nDotDashIndex(0);
+            bool bIsLine(true);
+            double fDotDashMovingLength(rDotDashArray[0]);
+            B2DPolygon aSnippet;
 
-                    // check if we have a trivial bezier segment -> possible fallback to edge
-                    aCurrentEdge.testAndSolveTrivialBezier();
+            // remember 1st and last snippets to try to merge after execution
+            // is complete and hand to callback
+            B2DPolygon aFirstLine, aLastLine;
+            B2DPolygon aFirstGap, aLastGap;
 
-                    if(aCurrentEdge.isBezier())
-                    {
-                        // bezier segment
-                        const B2DCubicBezierHelper aCubicBezierHelper(aCurrentEdge);
-                        const double fEdgeLength(aCubicBezierHelper.getLength());
+            // iterate over all edges
+            for(sal_uInt32 a(0); a < nEdgeCount; a++)
+            {
+                // update current edge (fill in C1, C2 and end point)
+                double fLastDotDashMovingLength(0.0);
+                const sal_uInt32 nNextIndex((a + 1) % nPointCount);
+                aCurrentEdge.setControlPointA(rCandidate.getNextControlPoint(a));
+                aCurrentEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
+                aCurrentEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
 
-                        if(!fTools::equalZero(fEdgeLength))
+                // check if we have a trivial bezier segment -> possible fallback to edge
+                aCurrentEdge.testAndSolveTrivialBezier();
+
+                if(aCurrentEdge.isBezier())
+                {
+                    // bezier segment
+                    const B2DCubicBezierHelper aCubicBezierHelper(aCurrentEdge);
+                    const double fEdgeLength(aCubicBezierHelper.getLength());
+
+                    if(!fTools::equalZero(fEdgeLength))
+                    {
+                        while(fTools::less(fDotDashMovingLength, fEdgeLength))
                         {
-                            while(fTools::less(fDotDashMovingLength, fEdgeLength))
+                            // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
+                            const bool bHandleLine(bIsLine && aLineTargetCallback);
+                            const bool bHandleGap(!bIsLine && aGapTargetCallback);
+
+                            if(bHandleLine || bHandleGap)
                             {
-                                // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
-                                const bool bHandleLine(bIsLine && pLineTarget);
-                                const bool bHandleGap(!bIsLine && pGapTarget);
+                                const double fBezierSplitStart(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
+                                const double fBezierSplitEnd(aCubicBezierHelper.distanceToRelative(fDotDashMovingLength));
+                                B2DCubicBezier aBezierSnippet(aCurrentEdge.snippet(fBezierSplitStart, fBezierSplitEnd));
 
-                                if(bHandleLine || bHandleGap)
+                                if(!aSnippet.count())
                                 {
-                                    const double fBezierSplitStart(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
-                                    const double fBezierSplitEnd(aCubicBezierHelper.distanceToRelative(fDotDashMovingLength));
-                                    B2DCubicBezier aBezierSnippet(aCurrentEdge.snippet(fBezierSplitStart, fBezierSplitEnd));
-
-                                    if(!aSnippet.count())
-                                    {
-                                        aSnippet.append(aBezierSnippet.getStartPoint());
-                                    }
+                                    aSnippet.append(aBezierSnippet.getStartPoint());
+                                }
 
-                                    aSnippet.appendBezierSegment(aBezierSnippet.getControlPointA(), aBezierSnippet.getControlPointB(), aBezierSnippet.getEndPoint());
+                                aSnippet.appendBezierSegment(aBezierSnippet.getControlPointA(), aBezierSnippet.getControlPointB(), aBezierSnippet.getEndPoint());
 
-                                    if(bHandleLine)
-                                    {
-                                        pLineTarget->append(aSnippet);
-                                    }
-                                    else
-                                    {
-                                        pGapTarget->append(aSnippet);
-                                    }
+                                if(bHandleLine)
+                                {
+                                    implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
+                                }
 
-                                    aSnippet.clear();
+                                if(bHandleGap)
+                                {
+                                    implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
                                 }
 
-                                // prepare next DotDashArray step and flip line/gap flag
-                                fLastDotDashMovingLength = fDotDashMovingLength;
-                                fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
-                                bIsLine = !bIsLine;
+                                aSnippet.clear();
                             }
 
-                            // append closing snippet [fLastDotDashMovingLength, fEdgeLength]
-                            const bool bHandleLine(bIsLine && pLineTarget);
-                            const bool bHandleGap(!bIsLine && pGapTarget);
+                            // prepare next DotDashArray step and flip line/gap flag
+                            fLastDotDashMovingLength = fDotDashMovingLength;
+                            fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
+                            bIsLine = !bIsLine;
+                        }
 
-                            if(bHandleLine || bHandleGap)
-                            {
-                                B2DCubicBezier aRight;
-                                const double fBezierSplit(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
+                        // append closing snippet [fLastDotDashMovingLength, fEdgeLength]
+                        const bool bHandleLine(bIsLine && aLineTargetCallback);
+                        const bool bHandleGap(!bIsLine && aGapTargetCallback);
 
-                                aCurrentEdge.split(fBezierSplit, nullptr, &aRight);
+                        if(bHandleLine || bHandleGap)
+                        {
+                            B2DCubicBezier aRight;
+                            const double fBezierSplit(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
 
-                                if(!aSnippet.count())
-                                {
-                                    aSnippet.append(aRight.getStartPoint());
-                                }
+                            aCurrentEdge.split(fBezierSplit, nullptr, &aRight);
 
-                                aSnippet.appendBezierSegment(aRight.getControlPointA(), aRight.getControlPointB(), aRight.getEndPoint());
+                            if(!aSnippet.count())
+                            {
+                                aSnippet.append(aRight.getStartPoint());
                             }
 
-                            // prepare move to next edge
-                            fDotDashMovingLength -= fEdgeLength;
+                            aSnippet.appendBezierSegment(aRight.getControlPointA(), aRight.getControlPointB(), aRight.getEndPoint());
                         }
+
+                        // prepare move to next edge
+                        fDotDashMovingLength -= fEdgeLength;
                     }
-                    else
-                    {
-                        // simple edge
-                        const double fEdgeLength(aCurrentEdge.getEdgeLength());
+                }
+                else
+                {
+                    // simple edge
+                    const double fEdgeLength(aCurrentEdge.getEdgeLength());
 
-                        if(!fTools::equalZero(fEdgeLength))
+                    if(!fTools::equalZero(fEdgeLength))
+                    {
+                        while(fTools::less(fDotDashMovingLength, fEdgeLength))
                         {
-                            while(fTools::less(fDotDashMovingLength, fEdgeLength))
-                            {
-                                // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
-                                const bool bHandleLine(bIsLine && pLineTarget);
-                                const bool bHandleGap(!bIsLine && pGapTarget);
+                            // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
+                            const bool bHandleLine(bIsLine && aLineTargetCallback);
+                            const bool bHandleGap(!bIsLine && aGapTargetCallback);
 
-                                if(bHandleLine || bHandleGap)
+                            if(bHandleLine || bHandleGap)
+                            {
+                                if(!aSnippet.count())
                                 {
-                                    if(!aSnippet.count())
-                                    {
-                                        aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
-                                    }
+                                    aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
+                                }
 
-                                    aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fDotDashMovingLength / fEdgeLength));
+                                aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fDotDashMovingLength / fEdgeLength));
 
-                                    if(bHandleLine)
-                                    {
-                                        pLineTarget->append(aSnippet);
-                                    }
-                                    else
-                                    {
-                                        pGapTarget->append(aSnippet);
-                                    }
+                                if(bHandleLine)
+                                {
+                                    implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
+                                }
 
-                                    aSnippet.clear();
+                                if(bHandleGap)
+                                {
+                                    implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
                                 }
 
-                                // prepare next DotDashArray step and flip line/gap flag
-                                fLastDotDashMovingLength = fDotDashMovingLength;
-                                fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
-                                bIsLine = !bIsLine;
+                                aSnippet.clear();
                             }
 
-                            // append snippet [fLastDotDashMovingLength, fEdgeLength]
-                            const bool bHandleLine(bIsLine && pLineTarget);
-                            const bool bHandleGap(!bIsLine && pGapTarget);
+                            // prepare next DotDashArray step and flip line/gap flag
+                            fLastDotDashMovingLength = fDotDashMovingLength;
+                            fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
+                            bIsLine = !bIsLine;
+                        }
 
-                            if(bHandleLine || bHandleGap)
-                            {
-                                if(!aSnippet.count())
-                                {
-                                    aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
-                                }
+                        // append snippet [fLastDotDashMovingLength, fEdgeLength]
+                        const bool bHandleLine(bIsLine && aLineTargetCallback);
+                        const bool bHandleGap(!bIsLine && aGapTargetCallback);
 
-                                aSnippet.append(aCurrentEdge.getEndPoint());
+                        if(bHandleLine || bHandleGap)
+                        {
+                            if(!aSnippet.count())
+                            {
+                                aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
                             }
 
-                            // prepare move to next edge
-                            fDotDashMovingLength -= fEdgeLength;
+                            aSnippet.append(aCurrentEdge.getEndPoint());
                         }
-                    }
 
-                    // prepare next edge step (end point gets new start point)
-                    aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
-                }
-
-                // append last intermediate results (if exists)
-                if(aSnippet.count())
-                {
-                    if(bIsLine && pLineTarget)
-                    {
-                        pLineTarget->append(aSnippet);
-                    }
-                    else if(!bIsLine && pGapTarget)
-                    {
-                        pGapTarget->append(aSnippet);
+                        // prepare move to next edge
+                        fDotDashMovingLength -= fEdgeLength;
                     }
                 }
 
-                // check if start and end polygon may be merged
-                if(pLineTarget)
-                {
-                    const sal_uInt32 nCount(pLineTarget->count());
+                // prepare next edge step (end point gets new start point)
+                aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
+            }
 
-                    if(nCount > 1)
-                    {
-                        // these polygons were created above, there exists none with less than two points,
-                        // thus direct point access below is allowed
-                        const B2DPolygon aFirst(pLineTarget->getB2DPolygon(0));
-                        B2DPolygon aLast(pLineTarget->getB2DPolygon(nCount - 1));
+            // append last intermediate results (if exists)
+            if(aSnippet.count())
+            {
+                const bool bHandleLine(bIsLine && aLineTargetCallback);
+                const bool bHandleGap(!bIsLine && aGapTargetCallback);
 
-                        if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
-                        {
-                            // start of first and end of last are the same -> merge them
-                            aLast.append(aFirst);
-                            aLast.removeDoublePoints();
-                            pLineTarget->setB2DPolygon(0, aLast);
-                            pLineTarget->remove(nCount - 1);
-                        }
-                    }
+                if(bHandleLine)
+                {
+                    implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
                 }
 
-                if(pGapTarget)
+                if(bHandleGap)
                 {
-                    const sal_uInt32 nCount(pGapTarget->count());
-
-                    if(nCount > 1)
-                    {
-                        // these polygons were created above, there exists none with less than two points,
-                        // thus direct point access below is allowed
-                        const B2DPolygon aFirst(pGapTarget->getB2DPolygon(0));
-                        B2DPolygon aLast(pGapTarget->getB2DPolygon(nCount - 1));
-
-                        if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
-                        {
-                            // start of first and end of last are the same -> merge them
-                            aLast.append(aFirst);
-                            aLast.removeDoublePoints();
-                            pGapTarget->setB2DPolygon(0, aLast);
-                            pGapTarget->remove(nCount - 1);
-                        }
-                    }
+                    implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
                 }
             }
-            else
+
+            if(bIsClosed && aLineTargetCallback)
             {
-                // parameters make no sense, just add source to targets
-                if(pLineTarget)
-                {
-                    pLineTarget->append(rCandidate);
-                }
+                implHandleFirstLast(aLineTargetCallback, aFirstLine, aLastLine);
+            }
 
-                if(pGapTarget)
-                {
-                    pGapTarget->append(rCandidate);
-                }
+            if(bIsClosed && aGapTargetCallback)
+            {
+                implHandleFirstLast(aGapTargetCallback, aFirstGap, aLastGap);
             }
         }
 
diff --git a/include/basegfx/polygon/b2dpolygontools.hxx b/include/basegfx/polygon/b2dpolygontools.hxx
index 565f8013ffe9..2ec15714088b 100644
--- a/include/basegfx/polygon/b2dpolygontools.hxx
+++ b/include/basegfx/polygon/b2dpolygontools.hxx
@@ -20,6 +20,9 @@
 #ifndef INCLUDED_BASEGFX_POLYGON_B2DPOLYGONTOOLS_HXX
 #define INCLUDED_BASEGFX_POLYGON_B2DPOLYGONTOOLS_HXX
 
+#include <vector>
+#include <functional>
+
 #include <basegfx/point/b2dpoint.hxx>
 #include <basegfx/vector/b2dvector.hxx>
 #include <basegfx/range/b2drectangle.hxx>
@@ -27,7 +30,6 @@
 #include <basegfx/polygon/b2dpolygontriangulator.hxx>
 #include <com/sun/star/drawing/PointSequence.hpp>
 #include <com/sun/star/drawing/FlagSequence.hpp>
-#include <vector>
 #include <basegfx/basegfxdllapi.h>
 #include <o3tl/typed_flags_set.hxx>
 
@@ -188,7 +190,27 @@ namespace basegfx
             @param fFullDashDotLen
             The summed-up length of the rDotDashArray. If zero, it will
             be calculated internally.
+
+            There is now a 2nd version that allows to provide callback
+            functions that get called when a snippet of a line/gap is
+            produced and needs to be added. This allows to use it like
+            a 'pipeline'. When using this (e.g. the 1st version uses
+            this internally to guarantee the same algorithm is used)
+            it is not needed to accumulate a potentially huge number
+            of polygons in the result-polyPolygons, but e.g. consume
+            them directly in the caller. Example is renderinmg a
+            dashed line but without creating the potentially huge amount
+            of polygons.
+            The 2nd version will also merge first/last line/gap snippets
+            if the input polygon is closed and the start/end-points match
+            accordingly - at the cost that this will be delivered last.
         */
+        BASEGFX_DLLPUBLIC void applyLineDashing(
+            const B2DPolygon& rCandidate,
+            const std::vector<double>& rDotDashArray,
+            std::function<void(const basegfx::B2DPolygon& rSnippet)> aLineTargetCallback,
+            std::function<void(const basegfx::B2DPolygon& rSnippet)> aGapTargetCallback = std::function<void(const basegfx::B2DPolygon&)>(),
+            double fDotDashLength = 0.0);
         BASEGFX_DLLPUBLIC void applyLineDashing(
             const B2DPolygon& rCandidate,
             const ::std::vector<double>& rDotDashArray,


More information about the Libreoffice-commits mailing list