From 3bd5de707a361fc23d53dd5ad76c147722dfa2e9 Mon Sep 17 00:00:00 2001
From: "Armin.Le.Grand (CIB)" <Armin.Le.Grand@me.com>
Date: Tue, 3 Mar 2020 11:34:45 +0100
Subject: tdf#130150 Improve clipping in PDF export

For more info and discusson please have a look
at the task. It reverts the change from tdf#99680
which did a wrong paradigm change in how clip in
Region(s) is defined and tries to fix the
underlying error in a more correct way.
This includes problems noted in tdf#44388 and
tdf#113449.
This is a decent improvement, but - due to dealing
with numerical problems - not yet the whole healing.
Still thinking about how to solve this for good.
Adapted PdfExportTest::testTdf99680() and
PdfExportTest::testTdf99680_2() as needed, empty
clip regions are allowed again. Added comments, too.
Had to change solvePolygonOperationAnd to work
on ranges if both inputs *are* ranges. The AND-case
is then completely solvable. Also increased geometry
for transformations of clip geometries - may help
later.

Change-Id: I2370447597faa6efb81d58ee31c63654e304262e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89874
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
(cherry picked from commit 6dff631f8f4b964b48aadde52a1e1b8b04b9ba53)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89923
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
---
 basegfx/source/polygon/b2dpolygontools.cxx      | 15 ++++++-----
 basegfx/source/polygon/b2dpolypolygoncutter.cxx | 36 +++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 7 deletions(-)

(limited to 'basegfx')

diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx
index 4ac68958eaa2..cbc18ee74203 100644
--- a/basegfx/source/polygon/b2dpolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolygontools.cxx
@@ -333,15 +333,15 @@ namespace basegfx
                         const B2DPoint aPreviousPoint(aCurrentPoint);
                         aCurrentPoint = aCandidate.getB2DPoint(a);
 
-                        // cross-over in Y?
-                        const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
-                        const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
+                        // cross-over in Y? tdf#130150 use full precision, no need for epsilon
+                        const bool bCompYA(aPreviousPoint.getY() > rPoint.getY());
+                        const bool bCompYB(aCurrentPoint.getY() > rPoint.getY());
 
                         if(bCompYA != bCompYB)
                         {
-                            // cross-over in X?
-                            const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
-                            const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
+                            // cross-over in X? tdf#130150 use full precision, no need for epsilon
+                            const bool bCompXA(aPreviousPoint.getX() > rPoint.getX());
+                            const bool bCompXB(aCurrentPoint.getX() > rPoint.getX());
 
                             if(bCompXA == bCompXB)
                             {
@@ -357,7 +357,8 @@ namespace basegfx
                                     (aPreviousPoint.getX() - aCurrentPoint.getX()) /
                                     (aPreviousPoint.getY() - aCurrentPoint.getY()));
 
-                                if(fTools::more(fCompare, rPoint.getX()))
+                                // tdf#130150 use full precision, no need for epsilon
+                                if(fCompare > rPoint.getX())
                                 {
                                     bRetval = !bRetval;
                                 }
diff --git a/basegfx/source/polygon/b2dpolypolygoncutter.cxx b/basegfx/source/polygon/b2dpolypolygoncutter.cxx
index 0ea1e8b9b863..9d2e574c1b2d 100644
--- a/basegfx/source/polygon/b2dpolypolygoncutter.cxx
+++ b/basegfx/source/polygon/b2dpolypolygoncutter.cxx
@@ -986,6 +986,42 @@ namespace basegfx
             }
             else
             {
+                // tdf#130150 shortcut & precision: If both are simple ranges,
+                // solve based on ranges
+                if(basegfx::utils::isRectangle(rCandidateA) && basegfx::utils::isRectangle(rCandidateB))
+                {
+                    // *if* both are ranges, AND always can be solved
+                    const basegfx::B2DRange aRangeA(rCandidateA.getB2DRange());
+                    const basegfx::B2DRange aRangeB(rCandidateB.getB2DRange());
+
+                    if(aRangeA.isInside(aRangeB))
+                    {
+                        // 2nd completely inside 1st -> 2nd is result of AND
+                        return rCandidateB;
+                    }
+
+                    if(aRangeB.isInside(aRangeA))
+                    {
+                        // 2nd completely inside 1st -> 2nd is result of AND
+                        return rCandidateA;
+                    }
+
+                    // solve by intersection
+                    basegfx::B2DRange aIntersect(aRangeA);
+                    aIntersect.intersect(aRangeB);
+
+                    if(aIntersect.isEmpty())
+                    {
+                        // no overlap -> empty polygon as result of AND
+                        return B2DPolyPolygon();
+                    }
+
+                    // create polygon result
+                    return B2DPolyPolygon(
+                        basegfx::utils::createPolygonFromRect(
+                            aIntersect));
+                }
+
                 // concatenate polygons, solve crossovers and throw away all sub-polygons
                 // with a depth of < 1. This means to keep all polygons where at least two
                 // polygons do overlap.
-- 
cgit