diff options
author | Caolán McNamara <caolanm@redhat.com> | 2022-03-21 15:33:06 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2022-03-21 17:35:37 +0100 |
commit | f4474b2967f9c7b3b82239c6e9c66850964c6e8b (patch) | |
tree | e99d6724ebb93015ced117e7c134a2028c5b9b47 | |
parent | 79b5ff92b17fde902c2f9db3e806f1c77a387dff (diff) |
ofz#45878 add a way to set some limit on hugely complex clips
Change-Id: I6bbf7c6068560e3bb656560fb5c6cc2ed72cecd4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131907
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r-- | basegfx/source/polygon/b2dpolygonclipper.cxx | 13 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolygoncutandtouch.cxx | 35 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolypolygoncutter.cxx | 8 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolygonclipper.hxx | 3 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolygoncutandtouch.hxx | 4 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolypolygoncutter.hxx | 3 | ||||
-rw-r--r-- | vcl/source/gdi/region.cxx | 5 |
7 files changed, 54 insertions, 17 deletions
diff --git a/basegfx/source/polygon/b2dpolygonclipper.cxx b/basegfx/source/polygon/b2dpolygonclipper.cxx index 246d5a10ab84..69eba2c84fa7 100644 --- a/basegfx/source/polygon/b2dpolygonclipper.cxx +++ b/basegfx/source/polygon/b2dpolygonclipper.cxx @@ -25,6 +25,7 @@ #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/curve/b2dcubicbezier.hxx> #include <basegfx/utils/rectcliptools.hxx> +#include <sal/log.hxx> namespace basegfx::utils { @@ -330,7 +331,8 @@ namespace basegfx::utils return aRetval; } - B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rClip, bool bInside, bool bStroke) + B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rClip, + bool bInside, bool bStroke, size_t* pPointLimit) { B2DPolyPolygon aRetval; @@ -471,7 +473,14 @@ namespace basegfx::utils // prepare 2nd source polygon in same way - B2DPolyPolygon aMergePolyPolygonB = solveCrossovers(rCandidate); + B2DPolyPolygon aMergePolyPolygonB = solveCrossovers(rCandidate, pPointLimit); + + if (pPointLimit && !*pPointLimit) + { + SAL_WARN("basegfx", "clipPolyPolygonOnPolyPolygon hit point limit"); + return aRetval; + } + aMergePolyPolygonB = stripNeutralPolygons(aMergePolyPolygonB); aMergePolyPolygonB = correctOrientations(aMergePolyPolygonB); diff --git a/basegfx/source/polygon/b2dpolygoncutandtouch.cxx b/basegfx/source/polygon/b2dpolygoncutandtouch.cxx index 99a73ca82bc3..d5ab5887da61 100644 --- a/basegfx/source/polygon/b2dpolygoncutandtouch.cxx +++ b/basegfx/source/polygon/b2dpolygoncutandtouch.cxx @@ -19,6 +19,7 @@ #include <basegfx/polygon/b2dpolygoncutandtouch.hxx> #include <osl/diagnose.h> +#include <sal/log.hxx> #include <basegfx/numeric/ftools.hxx> #include <basegfx/point/b2dpoint.hxx> #include <basegfx/vector/b2dvector.hxx> @@ -203,7 +204,7 @@ namespace basegfx // predefines for calls to this methods before method implementation - void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints); + void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints, size_t* pPointLimit = nullptr); void findTouches(const B2DPolygon& rEdgePolygon, const B2DPolygon& rPointPolygon, temporaryPointVector& rTempPoints); void findCuts(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB); @@ -487,7 +488,7 @@ namespace basegfx } } - void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints) + void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints, size_t* pPointLimit) { // find out if there are edges with intersections (self-cuts). If yes, add // entries to rTempPoints accordingly @@ -588,6 +589,9 @@ namespace basegfx findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPoints, rTempPoints); } + if (pPointLimit && rTempPoints.size() > *pPointLimit) + break; + // prepare next step aCurrB = aNextB; } @@ -596,6 +600,14 @@ namespace basegfx aCurrA = aNextA; } } + + if (pPointLimit) + { + if (rTempPoints.size() > *pPointLimit) + *pPointLimit = 0; + else + *pPointLimit -= rTempPoints.size(); + } } } // end of anonymous namespace @@ -841,14 +853,19 @@ namespace basegfx namespace basegfx::utils { - B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate) + B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate, size_t* pPointLimit) { if(rCandidate.count()) { temporaryPointVector aTempPoints; findTouches(rCandidate, rCandidate, aTempPoints); - findCuts(rCandidate, aTempPoints); + findCuts(rCandidate, aTempPoints, pPointLimit); + if (pPointLimit && !*pPointLimit) + { + SAL_WARN("basegfx", "addPointsAtCutsAndTouches hit point limit"); + return rCandidate; + } return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints); } @@ -858,7 +875,7 @@ namespace basegfx::utils } } - B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate) + B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate, size_t* pPointLimit) { const sal_uInt32 nCount(rCandidate.count()); @@ -880,7 +897,13 @@ namespace basegfx::utils for(a = 0; a < nCount; a++) { // use polygons with solved self intersections - pTempData[a].setPolygon(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(a))); + pTempData[a].setPolygon(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(a), pPointLimit)); + } + + if (pPointLimit && !*pPointLimit) + { + SAL_WARN("basegfx", "addPointsAtCutsAndTouches hit point limit"); + return rCandidate; } // now cuts and touches between the polygons diff --git a/basegfx/source/polygon/b2dpolypolygoncutter.cxx b/basegfx/source/polygon/b2dpolypolygoncutter.cxx index ac1e10660607..ddec57374649 100644 --- a/basegfx/source/polygon/b2dpolypolygoncutter.cxx +++ b/basegfx/source/polygon/b2dpolypolygoncutter.cxx @@ -513,7 +513,7 @@ namespace basegfx impSolve(); } - explicit solver(const B2DPolyPolygon& rOriginal) + explicit solver(const B2DPolyPolygon& rOriginal, size_t* pPointLimit = nullptr) : maOriginal(rOriginal), mbIsCurve(false), mbChanged(false) @@ -523,7 +523,7 @@ namespace basegfx if(!nOriginalCount) return; - B2DPolyPolygon aGeometry(utils::addPointsAtCutsAndTouches(maOriginal)); + B2DPolyPolygon aGeometry(utils::addPointsAtCutsAndTouches(maOriginal, pPointLimit)); aGeometry.removeDoublePoints(); aGeometry = utils::simplifyCurveSegments(aGeometry); mbIsCurve = aGeometry.areControlPointsUsed(); @@ -684,11 +684,11 @@ namespace basegfx namespace basegfx::utils { - B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate) + B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate, size_t* pPointLimit) { if(rCandidate.count() > 0) { - solver aSolver(rCandidate); + solver aSolver(rCandidate, pPointLimit); return aSolver.getB2DPolyPolygon(); } else diff --git a/include/basegfx/polygon/b2dpolygonclipper.hxx b/include/basegfx/polygon/b2dpolygonclipper.hxx index bc7bd2f1913e..a6a2ce9d2fa0 100644 --- a/include/basegfx/polygon/b2dpolygonclipper.hxx +++ b/include/basegfx/polygon/b2dpolygonclipper.hxx @@ -51,7 +51,8 @@ namespace basegfx::utils // With filled polygons, You get all tools::PolyPolygon parts which were inside rClip. // The switch bInside decides if the parts inside the clip polygon or outside shall be created. // The clip polygon is always assumed closed, even when it's isClosed() is false. - BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rClip, bool bInside, bool bStroke); + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rClip, + bool bInside, bool bStroke, size_t *pPointLimit = nullptr); BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolygonOnPolyPolygon(const B2DPolygon& rCandidate, const B2DPolyPolygon& rClip, bool bInside, bool bStroke); // clip the given polygon against the given range. the resulting polygon will always contain diff --git a/include/basegfx/polygon/b2dpolygoncutandtouch.hxx b/include/basegfx/polygon/b2dpolygoncutandtouch.hxx index 55bea6f3ebcb..600ad1c5cd90 100644 --- a/include/basegfx/polygon/b2dpolygoncutandtouch.hxx +++ b/include/basegfx/polygon/b2dpolygoncutandtouch.hxx @@ -27,12 +27,12 @@ namespace basegfx::utils // look for self-intersections and self-touches (points on an edge) in given polygon and add // extra points there. Result will have no touches or intersections on an edge, only on points -B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate); +B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate, size_t* pPointLimit = nullptr); // look for polypolygon-intersections and polypolygon-touches (point of poly A on an edge of poly B) in given tools::PolyPolygon and add // extra points there. Result will have no touches or intersections between contained polygons on an edge, only on points. For // convenience, the correction for self-intersections for each member polygon will be used, too. -B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate); +B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate, size_t* pPointLimit = nullptr); // look for intersections of rCandidate with the edge from rStart to rEnd and add extra points there. // Points are only added in the range of the edge, not on the endless vector. diff --git a/include/basegfx/polygon/b2dpolypolygoncutter.hxx b/include/basegfx/polygon/b2dpolypolygoncutter.hxx index a5f4ba6626af..55dd29cf8e52 100644 --- a/include/basegfx/polygon/b2dpolypolygoncutter.hxx +++ b/include/basegfx/polygon/b2dpolypolygoncutter.hxx @@ -39,7 +39,8 @@ namespace basegfx::utils preparing step and to explicitly correct their orientations. */ - BASEGFX_DLLPUBLIC B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate); + BASEGFX_DLLPUBLIC B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate, + size_t* pPointLimit = nullptr); /** Solve all crossovers (aka self-intersections) in a Polygon diff --git a/vcl/source/gdi/region.cxx b/vcl/source/gdi/region.cxx index 5293aa52328b..1f947f9b68fc 100644 --- a/vcl/source/gdi/region.cxx +++ b/vcl/source/gdi/region.cxx @@ -989,12 +989,15 @@ void vcl::Region::Intersect( const vcl::Region& rRegion ) return; } + static size_t gPointLimit = !utl::ConfigManager::IsFuzzing() ? SAL_MAX_SIZE : SAL_MAX_INT16; + size_t nPointLimit(gPointLimit); const basegfx::B2DPolyPolygon aClip( basegfx::utils::clipPolyPolygonOnPolyPolygon( aOtherPolyPoly, aThisPolyPoly, true, - false)); + false, + &nPointLimit)); *this = vcl::Region( aClip ); return; } |