Enabling the canvas bit to turn the clip stack into a flat replace exposed around 100 failures when testing the 800K skp set generated from the top 1M web sites.
This fixes all but one of those failures.
Major changes include:
- Replace angle indices with angle pointers. This was motivated by the need to add angles later but not renumber existing angles.
- Aggressive segment chase. When the winding is known on a segment, more aggressively passing that winding to adjacent segments allows fragmented data sets to succeed.
- Line segments with ends nearly the same are treated as coincident first.
- Transfer partial coincidence by observing that if segment A is partially coincident to B and C then B and C may be partially coincident.
TBR=reed
Author: caryclark@google.com
Review URL: https://codereview.chromium.org/272153002
diff --git a/src/pathops/SkDCubicIntersection.cpp b/src/pathops/SkDCubicIntersection.cpp
index dd51195..1c237d9 100644
--- a/src/pathops/SkDCubicIntersection.cpp
+++ b/src/pathops/SkDCubicIntersection.cpp
@@ -303,15 +303,39 @@
continue;
}
if (swap) {
- insert(testT, impTs[0][index], tmpLine[0]);
+ cubicInsert(testT, impTs[0][index], tmpLine[0], cubic2, cubic1);
} else {
- insert(impTs[0][index], testT, tmpLine[0]);
+ cubicInsert(impTs[0][index], testT, tmpLine[0], cubic1, cubic2);
}
return true;
}
return false;
}
+
+void SkIntersections::cubicInsert(double one, double two, const SkDPoint& pt,
+ const SkDCubic& cubic1, const SkDCubic& cubic2) {
+ for (int index = 0; index < fUsed; ++index) {
+ if (fT[0][index] == one) {
+ double oldTwo = fT[1][index];
+ if (oldTwo == two) {
+ return;
+ }
+ SkDPoint mid = cubic2.ptAtT((oldTwo + two) / 2);
+ if (mid.approximatelyEqual(fPt[index])) {
+ return;
+ }
+ }
+ if (fT[1][index] == two) {
+ SkDPoint mid = cubic1.ptAtT((fT[0][index] + two) / 2);
+ if (mid.approximatelyEqual(fPt[index])) {
+ return;
+ }
+ }
+ }
+ insert(one, two, pt);
+}
+
void SkIntersections::cubicNearEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cubic2,
const SkDRect& bounds2) {
SkDLine line;
@@ -371,11 +395,15 @@
double tMin2 = SkTMax(tVals[tIdx] - LINE_FRACTION, 0.0);
double tMax2 = SkTMin(tVals[tLast] + LINE_FRACTION, 1.0);
int lastUsed = used();
- ::intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, *this);
+ if (start ? tMax1 < tMin2 : tMax2 < tMin1) {
+ ::intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, *this);
+ }
if (lastUsed == used()) {
tMin2 = SkTMax(tVals[tIdx] - (1.0 / SkDCubic::gPrecisionUnit), 0.0);
tMax2 = SkTMin(tVals[tLast] + (1.0 / SkDCubic::gPrecisionUnit), 1.0);
- ::intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, *this);
+ if (start ? tMax1 < tMin2 : tMax2 < tMin1) {
+ ::intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, *this);
+ }
}
tIdx = tLast + 1;
} while (tIdx < tVals.count());
@@ -421,6 +449,9 @@
}
double adj = endPt[oppTest]->fX - origX;
double opp = endPt[oppTest]->fY - origY;
+ if (adj == 0 && opp == 0) { // if the other point equals the test point, ignore it
+ continue;
+ }
double sign = (c1[oddMan].fY - origY) * adj - (c1[oddMan].fX - origX) * opp;
if (approximately_zero(sign)) {
goto tryNextHalfPlane;
@@ -531,7 +562,7 @@
if (compCount) {
int exactCount = used();
if (exactCount == 0) {
- set(i);
+ *this = i;
} else {
// at least one is exact or near, and at least one was computed. Eliminate duplicates
for (int exIdx = 0; exIdx < exactCount; ++exIdx) {