basegfx/source/polygon/b2dpolygontools.cxx  |  443 ++++++++++++++++------------
 distro-configs/CPLinux-LOKit.conf           |    1 
 include/basegfx/polygon/b2dpolygontools.hxx |   24 +
 3 files changed, 289 insertions(+), 179 deletions(-)

New commits:
commit ddc81265192f27047f363db0a0ff7dcd493fa4b1
Author:     Andras Timar <andras.ti...@collabora.com>
AuthorDate: Tue Apr 28 22:50:34 2020 +0200
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Apr 28 22:50:34 2020 +0200

    add --enable-sal-log to CPLinux-LOKit.conf to help debugging release 
packages
    
    Change-Id: Ia724186ae93038eddb9e11c6678e6d8522846f85

diff --git a/distro-configs/CPLinux-LOKit.conf 
b/distro-configs/CPLinux-LOKit.conf
index 75ad26fc2045..9d5518b66897 100644
--- a/distro-configs/CPLinux-LOKit.conf
+++ b/distro-configs/CPLinux-LOKit.conf
@@ -62,3 +62,4 @@
 --disable-lotuswordpro
 --disable-lpsolve
 --enable-symbols
+--enable-sal-log
commit 55c1016740d901668ae2766a5191b24bddb2d2f5
Author:     Armin Le Grand (Collabora) <armin.le.gr...@me.com>
AuthorDate: Fri Feb 14 12:32:42 2020 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Tue Apr 28 22:42:40 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.
    
    Change-Id: Ie306968a895ad280fc2425fb40b3244769216ba0

diff --git a/basegfx/source/polygon/b2dpolygontools.cxx 
b/basegfx/source/polygon/b2dpolygontools.cxx
index e0cfcdba1933..a4fd8378de4d 100644
--- a/basegfx/source/polygon/b2dpolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolygontools.cxx
@@ -1122,7 +1122,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());
@@ -1132,154 +1227,159 @@ 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;
+            // precalculate maximal acceptable length of candidate polygon 
assuming
+            // we want to create a maximum of fNumberOfAllowedSnippets. For
+            // fNumberOfAllowedSnippets use ca. 65536, double due to line & 
gap.
+            static double fNumberOfAllowedSnippets(65535.0 * 2.0);
+            const double fAllowedLength((fNumberOfAllowedSnippets * 
fDotDashLength) / double(rDotDashArray.size()));
+            const double 
fCandidateLength(basegfx::utils::getLength(rCandidate));
+            std::vector<double> aDotDashArray(rDotDashArray);
 
-                // 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(fCandidateLength > fAllowedLength)
+            {
+                // we would produce more than fNumberOfAllowedSnippets, so
+                // adapt aDotDashArray to exactly produce assumed number. Also
+                // assert this to let the caller know about it.
+                // If this asserts: Please think about checking your 
DotDashArray
+                // before calling this function or evtl. use the callback 
version
+                // to *not* produce that much of data. Even then, you may still
+                // think about producing too much runtime (!)
+                assert(true && "applyLineDashing: potentially too expensive to 
do the requested dismantle - please consider stretched LineDash pattern (!)");
 
-                    // check if we have a trivial bezier segment -> possible 
fallback to edge
-                    aCurrentEdge.testAndSolveTrivialBezier();
+                // calculate correcting factor, apply to aDotDashArray and 
fDotDashLength
+                // to enlarge these as needed
+                const double fFactor(fCandidateLength / fAllowedLength);
+                std::for_each(aDotDashArray.begin(), aDotDashArray.end(), 
[&fFactor](double &f){ f *= fFactor; });
+                fDotDashLength *= fFactor;
+            }
 
-                    if(aCurrentEdge.isBezier())
-                    {
-                        // bezier segment
-                        const B2DCubicBezierHelper 
aCubicBezierHelper(aCurrentEdge);
-                        const double 
fEdgeLength(aCubicBezierHelper.getLength());
+            // 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));
 
-                        if(!fTools::equalZero(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);
+            // prepare DotDashArray iteration and the line/gap switching bool
+            sal_uInt32 nDotDashIndex(0);
+            bool bIsLine(true);
+            double fDotDashMovingLength(aDotDashArray[0]);
+            B2DPolygon aSnippet;
 
-                                if(bHandleLine || bHandleGap)
-                                {
-                                    const double 
fBezierSplitStart(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
-                                    const double 
fBezierSplitEnd(aCubicBezierHelper.distanceToRelative(fDotDashMovingLength));
-                                    B2DCubicBezier 
aBezierSnippet(aCurrentEdge.snippet(fBezierSplitStart, fBezierSplitEnd));
+            // remember 1st and last snippets to try to merge after execution
+            // is complete and hand to callback
+            B2DPolygon aFirstLine, aLastLine;
+            B2DPolygon aFirstGap, aLastGap;
 
-                                    if(!aSnippet.count())
-                                    {
-                                        
aSnippet.append(aBezierSnippet.getStartPoint());
-                                    }
-
-                                    
aSnippet.appendBezierSegment(aBezierSnippet.getControlPointA(), 
aBezierSnippet.getControlPointB(), aBezierSnippet.getEndPoint());
-
-                                    if(bHandleLine)
-                                    {
-                                        pLineTarget->append(aSnippet);
-                                    }
-                                    else
-                                    {
-                                        pGapTarget->append(aSnippet);
-                                    }
+            // 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));
 
-                                    aSnippet.clear();
-                                }
+                // check if we have a trivial bezier segment -> possible 
fallback to edge
+                aCurrentEdge.testAndSolveTrivialBezier();
 
-                                // prepare next DotDashArray step and flip 
line/gap flag
-                                fLastDotDashMovingLength = 
fDotDashMovingLength;
-                                fDotDashMovingLength += 
rDotDashArray[(++nDotDashIndex) % nDotDashCount];
-                                bIsLine = !bIsLine;
-                            }
+                if(aCurrentEdge.isBezier())
+                {
+                    // bezier segment
+                    const B2DCubicBezierHelper 
aCubicBezierHelper(aCurrentEdge);
+                    const double fEdgeLength(aCubicBezierHelper.getLength());
 
-                            // append closing snippet 
[fLastDotDashMovingLength, fEdgeLength]
-                            const bool bHandleLine(bIsLine && pLineTarget);
-                            const bool bHandleGap(!bIsLine && pGapTarget);
+                    if(!fTools::equalZero(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)
                             {
-                                B2DCubicBezier aRight;
-                                const double 
fBezierSplit(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
-
-                                aCurrentEdge.split(fBezierSplit, nullptr, 
&aRight);
+                                const double 
fBezierSplitStart(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
+                                const double 
fBezierSplitEnd(aCubicBezierHelper.distanceToRelative(fDotDashMovingLength));
+                                B2DCubicBezier 
aBezierSnippet(aCurrentEdge.snippet(fBezierSplitStart, fBezierSplitEnd));
 
                                 if(!aSnippet.count())
                                 {
-                                    aSnippet.append(aRight.getStartPoint());
+                                    
aSnippet.append(aBezierSnippet.getStartPoint());
                                 }
 
-                                
aSnippet.appendBezierSegment(aRight.getControlPointA(), 
aRight.getControlPointB(), aRight.getEndPoint());
+                                
aSnippet.appendBezierSegment(aBezierSnippet.getControlPointA(), 
aBezierSnippet.getControlPointB(), aBezierSnippet.getEndPoint());
+
+                                if(bHandleLine)
+                                {
+                                    implHandleSnippet(aSnippet, 
aLineTargetCallback, aFirstLine, aLastLine);
+                                }
+
+                                if(bHandleGap)
+                                {
+                                    implHandleSnippet(aSnippet, 
aGapTargetCallback, aFirstGap, aLastGap);
+                                }
+
+                                aSnippet.clear();
                             }
 
-                            // prepare move to next edge
-                            fDotDashMovingLength -= fEdgeLength;
+                            // prepare next DotDashArray step and flip 
line/gap flag
+                            fLastDotDashMovingLength = fDotDashMovingLength;
+                            fDotDashMovingLength += 
aDotDashArray[(++nDotDashIndex) % nDotDashCount];
+                            bIsLine = !bIsLine;
                         }
-                    }
-                    else
-                    {
-                        // simple edge
-                        const double fEdgeLength(aCurrentEdge.getEdgeLength());
 
-                        if(!fTools::equalZero(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);
+                        // append closing snippet [fLastDotDashMovingLength, 
fEdgeLength]
+                        const bool bHandleLine(bIsLine && aLineTargetCallback);
+                        const bool bHandleGap(!bIsLine && aGapTargetCallback);
 
-                                if(bHandleLine || bHandleGap)
-                                {
-                                    if(!aSnippet.count())
-                                    {
-                                        
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), 
aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
-                                    }
+                        if(bHandleLine || bHandleGap)
+                        {
+                            B2DCubicBezier aRight;
+                            const double 
fBezierSplit(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
 
-                                    
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), 
aCurrentEdge.getEndPoint(), fDotDashMovingLength / fEdgeLength));
+                            aCurrentEdge.split(fBezierSplit, nullptr, &aRight);
 
-                                    if(bHandleLine)
-                                    {
-                                        pLineTarget->append(aSnippet);
-                                    }
-                                    else
-                                    {
-                                        pGapTarget->append(aSnippet);
-                                    }
+                            if(!aSnippet.count())
+                            {
+                                aSnippet.append(aRight.getStartPoint());
+                            }
 
-                                    aSnippet.clear();
-                                }
+                            
aSnippet.appendBezierSegment(aRight.getControlPointA(), 
aRight.getControlPointB(), aRight.getEndPoint());
+                        }
 
-                                // prepare next DotDashArray step and flip 
line/gap flag
-                                fLastDotDashMovingLength = 
fDotDashMovingLength;
-                                fDotDashMovingLength += 
rDotDashArray[(++nDotDashIndex) % nDotDashCount];
-                                bIsLine = !bIsLine;
-                            }
+                        // prepare move to next edge
+                        fDotDashMovingLength -= fEdgeLength;
+                    }
+                }
+                else
+                {
+                    // simple edge
+                    const double fEdgeLength(aCurrentEdge.getEdgeLength());
 
-                            // append snippet [fLastDotDashMovingLength, 
fEdgeLength]
-                            const bool bHandleLine(bIsLine && pLineTarget);
-                            const bool bHandleGap(!bIsLine && pGapTarget);
+                    if(!fTools::equalZero(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)
                             {
@@ -1288,89 +1388,76 @@ namespace basegfx
                                     
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), 
aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
                                 }
 
-                                aSnippet.append(aCurrentEdge.getEndPoint());
-                            }
-
-                            // prepare move to next edge
-                            fDotDashMovingLength -= fEdgeLength;
-                        }
-                    }
-
-                    // prepare next edge step (end point gets new start point)
-                    aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
-                }
+                                
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), 
aCurrentEdge.getEndPoint(), fDotDashMovingLength / fEdgeLength));
 
-                // append last intermediate results (if exists)
-                if(aSnippet.count())
-                {
-                    if(bIsLine && pLineTarget)
-                    {
-                        pLineTarget->append(aSnippet);
-                    }
-                    else if(!bIsLine && pGapTarget)
-                    {
-                        pGapTarget->append(aSnippet);
-                    }
-                }
+                                if(bHandleLine)
+                                {
+                                    implHandleSnippet(aSnippet, 
aLineTargetCallback, aFirstLine, aLastLine);
+                                }
 
-                // check if start and end polygon may be merged
-                if(pLineTarget)
-                {
-                    const sal_uInt32 nCount(pLineTarget->count());
+                                if(bHandleGap)
+                                {
+                                    implHandleSnippet(aSnippet, 
aGapTargetCallback, aFirstGap, aLastGap);
+                                }
 
-                    if(nCount > 1)
-                    {
-                        // these polygons were created above, there exists 
none with less than two points,
-                        // thus dircet point access below is allowed
-                        const B2DPolygon aFirst(pLineTarget->getB2DPolygon(0));
-                        B2DPolygon aLast(pLineTarget->getB2DPolygon(nCount - 
1));
+                                aSnippet.clear();
+                            }
 
-                        
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);
+                            // prepare next DotDashArray step and flip 
line/gap flag
+                            fLastDotDashMovingLength = fDotDashMovingLength;
+                            fDotDashMovingLength += 
aDotDashArray[(++nDotDashIndex) % nDotDashCount];
+                            bIsLine = !bIsLine;
                         }
-                    }
-                }
-
-                if(pGapTarget)
-                {
-                    const sal_uInt32 nCount(pGapTarget->count());
 
-                    if(nCount > 1)
-                    {
-                        // these polygons were created above, there exists 
none with less than two points,
-                        // thus dircet point access below is allowed
-                        const B2DPolygon aFirst(pGapTarget->getB2DPolygon(0));
-                        B2DPolygon aLast(pGapTarget->getB2DPolygon(nCount - 
1));
+                        // append snippet [fLastDotDashMovingLength, 
fEdgeLength]
+                        const bool bHandleLine(bIsLine && aLineTargetCallback);
+                        const bool bHandleGap(!bIsLine && aGapTargetCallback);
 
-                        
if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
+                        if(bHandleLine || bHandleGap)
                         {
-                            // 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);
+                            if(!aSnippet.count())
+                            {
+                                
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), 
aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
+                            }
+
+                            aSnippet.append(aCurrentEdge.getEndPoint());
                         }
+
+                        // prepare move to next edge
+                        fDotDashMovingLength -= fEdgeLength;
                     }
                 }
+
+                // prepare next edge step (end point gets new start point)
+                aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
             }
-            else
+
+            // append last intermediate results (if exists)
+            if(aSnippet.count())
             {
-                // parameters make no sense, just add source to targets
-                if(pLineTarget)
+                const bool bHandleLine(bIsLine && aLineTargetCallback);
+                const bool bHandleGap(!bIsLine && aGapTargetCallback);
+
+                if(bHandleLine)
                 {
-                    pLineTarget->append(rCandidate);
+                    implHandleSnippet(aSnippet, aLineTargetCallback, 
aFirstLine, aLastLine);
                 }
 
-                if(pGapTarget)
+                if(bHandleGap)
                 {
-                    pGapTarget->append(rCandidate);
+                    implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, 
aLastGap);
                 }
             }
+
+            if(bIsClosed && aLineTargetCallback)
+            {
+                implHandleFirstLast(aLineTargetCallback, aFirstLine, 
aLastLine);
+            }
+
+            if(bIsClosed && aGapTargetCallback)
+            {
+                implHandleFirstLast(aGapTargetCallback, aFirstGap, aLastGap);
+            }
         }
 
         // test if point is inside epsilon-range around an edge defined
diff --git a/include/basegfx/polygon/b2dpolygontools.hxx 
b/include/basegfx/polygon/b2dpolygontools.hxx
index 57b9130b4399..9defd76ef548 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,
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to