diff options
author | Armin Le Grand <Armin.Le.Grand@me.com> | 2020-02-14 16:47:14 +0100 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2020-02-14 19:19:49 +0100 |
commit | 62ac8333999c661432adb0a18245a399daa89dcb (patch) | |
tree | 9199e1e920765cc343646f472d7491f63d438a37 /basegfx | |
parent | fd7749fddc5a767461dfced55369af48e5a6d561 (diff) |
tdf#130655 callback interface for 3D and secure dash
Added same interface for 3D but just for lines, it uses no
gaps. Added the security mechanism mentioned in the task
in comment (2) to 2D and 3D
Change-Id: I5da303c01562088682d95ee4f294c99e1f17bf6b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88728
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'basegfx')
-rw-r--r-- | basegfx/source/polygon/b2dpolygontools.cxx | 36 | ||||
-rw-r--r-- | basegfx/source/polygon/b3dpolygontools.cxx | 255 |
2 files changed, 205 insertions, 86 deletions
diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx index 68d1120bc2cb..c194a38dc9d2 100644 --- a/basegfx/source/polygon/b2dpolygontools.cxx +++ b/basegfx/source/polygon/b2dpolygontools.cxx @@ -16,6 +16,8 @@ * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <numeric> +#include <algorithm> #include <basegfx/numeric/ftools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> @@ -32,8 +34,6 @@ #include <basegfx/curve/b2dbeziertools.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> -#include <numeric> - // #i37443# #define ANGLE_BOUND_START_VALUE (2.25) #define ANGLE_BOUND_MINIMUM_VALUE (0.1) @@ -1231,6 +1231,32 @@ namespace basegfx::utils return; } + // 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); + + 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 (!)"); + + // 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; + } + // prepare current edge's start B2DCubicBezier aCurrentEdge; const bool bIsClosed(rCandidate.isClosed()); @@ -1240,7 +1266,7 @@ namespace basegfx::utils // prepare DotDashArray iteration and the line/gap switching bool sal_uInt32 nDotDashIndex(0); bool bIsLine(true); - double fDotDashMovingLength(rDotDashArray[0]); + double fDotDashMovingLength(aDotDashArray[0]); B2DPolygon aSnippet; // remember 1st and last snippets to try to merge after execution @@ -1303,7 +1329,7 @@ namespace basegfx::utils // prepare next DotDashArray step and flip line/gap flag fLastDotDashMovingLength = fDotDashMovingLength; - fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount]; + fDotDashMovingLength += aDotDashArray[(++nDotDashIndex) % nDotDashCount]; bIsLine = !bIsLine; } @@ -1367,7 +1393,7 @@ namespace basegfx::utils // prepare next DotDashArray step and flip line/gap flag fLastDotDashMovingLength = fDotDashMovingLength; - fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount]; + fDotDashMovingLength += aDotDashArray[(++nDotDashIndex) % nDotDashCount]; bIsLine = !bIsLine; } diff --git a/basegfx/source/polygon/b3dpolygontools.cxx b/basegfx/source/polygon/b3dpolygontools.cxx index 1d97d4d43f0e..a0349a156626 100644 --- a/basegfx/source/polygon/b3dpolygontools.cxx +++ b/basegfx/source/polygon/b3dpolygontools.cxx @@ -90,7 +90,90 @@ namespace basegfx::utils return fRetval; } - void applyLineDashing(const B3DPolygon& rCandidate, const std::vector<double>& rDotDashArray, B3DPolyPolygon* pLineTarget, double fDotDashLength) + void applyLineDashing( + const B3DPolygon& rCandidate, + const std::vector<double>& rDotDashArray, + B3DPolyPolygon* pLineTarget, + double fDotDashLength) + { + // clear targets in any case + if(pLineTarget) + { + pLineTarget->clear(); + } + + // provide callback as lambda + auto aLineCallback( + nullptr == pLineTarget + ? std::function<void(const basegfx::B3DPolygon&)>() + : [&pLineTarget](const basegfx::B3DPolygon& rSnippet){ pLineTarget->append(rSnippet); }); + + // call version that uses callbacks + applyLineDashing( + rCandidate, + rDotDashArray, + aLineCallback, + fDotDashLength); + } + + static void implHandleSnippet( + const B3DPolygon& rSnippet, + std::function<void(const basegfx::B3DPolygon& rSnippet)>& rTargetCallback, + B3DPolygon& rFirst, + B3DPolygon& 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::B3DPolygon& rSnippet)>& rTargetCallback, + B3DPolygon& rFirst, + B3DPolygon& rLast) + { + if(rFirst.count() && rLast.count() + && rFirst.getB3DPoint(0).equal(rLast.getB3DPoint(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 B3DPolygon& rCandidate, + const std::vector<double>& rDotDashArray, + std::function<void(const basegfx::B3DPolygon& rSnippet)> aLineTargetCallback, + double fDotDashLength) { const sal_uInt32 nPointCount(rCandidate.count()); const sal_uInt32 nDotDashCount(rDotDashArray.size()); @@ -100,62 +183,74 @@ namespace basegfx::utils fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0); } - if(fTools::more(fDotDashLength, 0.0) && pLineTarget && nPointCount) + if(fTools::lessOrEqual(fDotDashLength, 0.0) || !aLineTargetCallback || !nPointCount) { - // clear targets - if(pLineTarget) + // parameters make no sense, just add source to targets + if(aLineTargetCallback) { - pLineTarget->clear(); + aLineTargetCallback(rCandidate); } - // prepare current edge's start - B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0)); - const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1); - - // prepare DotDashArray iteration and the line/gap switching bool - sal_uInt32 nDotDashIndex(0); - bool bIsLine(true); - double fDotDashMovingLength(rDotDashArray[0]); - B3DPolygon aSnippet; - - // iterate over all edges - for(sal_uInt32 a(0); a < nEdgeCount; a++) - { - // update current edge - const sal_uInt32 nNextIndex((a + 1) % nPointCount); - const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); - const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength()); + return; + } - if(!fTools::equalZero(fEdgeLength)) - { - double fLastDotDashMovingLength(0.0); - while(fTools::less(fDotDashMovingLength, fEdgeLength)) - { - // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength] - const bool bHandleLine(bIsLine && pLineTarget); + // precalculate maximal acceptable length of candidate polygon assuming + // we want to create a maximum of fNumberOfAllowedSnippets. In 3D + // use less for fNumberOfAllowedSnippets, ca. 6553.6, double due to line & gap. + // Less in 3D due to potentially blowing up to rounded line segments. + static double fNumberOfAllowedSnippets(6553.5 * 2.0); + const double fAllowedLength((fNumberOfAllowedSnippets * fDotDashLength) / double(rDotDashArray.size())); + const double fCandidateLength(basegfx::utils::getLength(rCandidate)); + std::vector<double> aDotDashArray(rDotDashArray); - if(bHandleLine) - { - if(!aSnippet.count()) - { - aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength)); - } + 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 (!)"); + + // 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; + } - aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength)); + // prepare current edge's start + B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0)); + const bool bIsClosed(rCandidate.isClosed()); + const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : nPointCount - 1); - pLineTarget->append(aSnippet); + // prepare DotDashArray iteration and the line/gap switching bool + sal_uInt32 nDotDashIndex(0); + bool bIsLine(true); + double fDotDashMovingLength(aDotDashArray[0]); + B3DPolygon aSnippet; - aSnippet.clear(); - } + // remember 1st and last snippets to try to merge after execution + // is complete and hand to callback + B3DPolygon aFirstLine, aLastLine; - // prepare next DotDashArray step and flip line/gap flag - fLastDotDashMovingLength = fDotDashMovingLength; - fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount]; - bIsLine = !bIsLine; - } + // iterate over all edges + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + // update current edge + const sal_uInt32 nNextIndex((a + 1) % nPointCount); + const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); + const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength()); - // append snippet [fLastDotDashMovingLength, fEdgeLength] - const bool bHandleLine(bIsLine && pLineTarget); + if(!fTools::equalZero(fEdgeLength)) + { + double fLastDotDashMovingLength(0.0); + while(fTools::less(fDotDashMovingLength, fEdgeLength)) + { + // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength] + const bool bHandleLine(bIsLine && aLineTargetCallback); if(bHandleLine) { @@ -164,57 +259,55 @@ namespace basegfx::utils aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength)); } - aSnippet.append(aNextPoint); - } + aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength)); - // prepare move to next edge - fDotDashMovingLength -= fEdgeLength; - } + implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine); - // prepare next edge step (end point gets new start point) - aCurrentPoint = aNextPoint; - } + aSnippet.clear(); + } - // append last intermediate results (if exists) - if(aSnippet.count()) - { - if(bIsLine && pLineTarget) - { - pLineTarget->append(aSnippet); + // prepare next DotDashArray step and flip line/gap flag + fLastDotDashMovingLength = fDotDashMovingLength; + fDotDashMovingLength += aDotDashArray[(++nDotDashIndex) % nDotDashCount]; + bIsLine = !bIsLine; } - } - // check if start and end polygon may be merged - if(pLineTarget) - { - const sal_uInt32 nCount(pLineTarget->count()); + // append snippet [fLastDotDashMovingLength, fEdgeLength] + const bool bHandleLine(bIsLine && aLineTargetCallback); - if(nCount > 1) + if(bHandleLine) { - // these polygons were created above, there exists none with less than two points, - // thus direct point access below is allowed - const B3DPolygon aFirst(pLineTarget->getB3DPolygon(0)); - B3DPolygon aLast(pLineTarget->getB3DPolygon(nCount - 1)); - - if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1))) + if(!aSnippet.count()) { - // start of first and end of last are the same -> merge them - aLast.append(aFirst); - aLast.removeDoublePoints(); - pLineTarget->setB3DPolygon(0, aLast); - pLineTarget->remove(nCount - 1); + aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength)); } + + aSnippet.append(aNextPoint); } + + // prepare move to next edge + fDotDashMovingLength -= fEdgeLength; } + + // prepare next edge step (end point gets new start point) + aCurrentPoint = aNextPoint; } - 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); + + if(bHandleLine) { - pLineTarget->append(rCandidate); + implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine); } } + + if(bIsClosed && aLineTargetCallback) + { + implHandleFirstLast(aLineTargetCallback, aFirstLine, aLastLine); + } } B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter) |