summaryrefslogtreecommitdiff
path: root/basegfx
diff options
context:
space:
mode:
authorArmin Le Grand <Armin.Le.Grand@me.com>2020-02-14 16:47:14 +0100
committerArmin Le Grand <Armin.Le.Grand@me.com>2020-02-14 19:19:49 +0100
commit62ac8333999c661432adb0a18245a399daa89dcb (patch)
tree9199e1e920765cc343646f472d7491f63d438a37 /basegfx
parentfd7749fddc5a767461dfced55369af48e5a6d561 (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.cxx36
-rw-r--r--basegfx/source/polygon/b3dpolygontools.cxx255
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)