Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/pathops/SkIntersections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ int SkIntersections::insert(double one, double two, const SkDPoint& pt) {
if (one == oldOne && two == oldTwo) {
return -1;
}
if (more_roughly_equal(oldOne, one) && more_roughly_equal(oldTwo, two)) {
// Check if T values are close enough to merge
bool tValuesClose = more_roughly_equal(oldOne, one) && more_roughly_equal(oldTwo, two);
// Check if coordinates are very close (for near-tangent curves where T values
// may differ more but coordinates are nearly identical)
bool coordsClose = pt.approximatelyEqual(fPt[index]);
if (tValuesClose || coordsClose) {
if ((!precisely_zero(one) || precisely_zero(oldOne))
&& (!precisely_equal(one, 1) || precisely_equal(oldOne, 1))
&& (!precisely_zero(two) || precisely_zero(oldTwo))
Expand Down
19 changes: 17 additions & 2 deletions src/pathops/SkOpSegment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,20 @@ bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
SkPathWriter* path) const {
const SkOpSpan* spanStart = start->starter(end);
FAIL_IF(spanStart->alreadyAdded());
printf("[DEBUG] addCurveTo: seg=%d spanStart=%p t=%.9g, start=(%.9g,%.9g) t=%.9g end=(%.9g,%.9g) t=%.9g\n",
this->debugID(), (void*)spanStart, spanStart->t(),
start->pt().fX, start->pt().fY, start->t(),
end->pt().fX, end->pt().fY, end->t());
fflush(stdout);
if (spanStart->alreadyAdded()) {
printf("[DEBUG] addCurveTo: alreadyAdded() returned true for seg=%d spanStart=%p\n",
this->debugID(), (void*)spanStart);
fflush(stdout);
return true;
}
printf("[DEBUG] addCurveTo: calling markAdded() for seg=%d spanStart=%p\n",
this->debugID(), (void*)spanStart);
fflush(stdout);
const_cast<SkOpSpan*>(spanStart)->markAdded();
SkDCurveSweep curvePart;
start->segment()->subDivide(start, end, &curvePart.fCurve);
Expand All @@ -176,7 +189,9 @@ bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
path->deferredMove(start->ptT());
switch (verb) {
case SkPath::kLine_Verb:
FAIL_IF(!path->deferredLine(end->ptT()));
if (!path->deferredLine(end->ptT())) {
return false;
}
break;
case SkPath::kQuad_Verb:
path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT());
Expand Down
21 changes: 16 additions & 5 deletions src/pathops/SkPathOpsCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,18 +86,26 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
SkOpSpanBase* span;
chase->pop(&span);
SkOpSegment* segment = span->segment();
// Skip if the segment is already done to avoid infinite loop.
if (segment->done()) {
continue;
}
*startPtr = span->ptT()->next()->span();
bool done = true;
*endPtr = nullptr;
if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
*startPtr = last->start();
*endPtr = last->end();
SkOpSegment* lastSegment = last->segment();
// Only re-add span to chase if the target segment is not done.
if (!lastSegment->done()) {
#if TRY_ROTATE
*chase->insert(0) = span;
*chase->insert(0) = span;
#else
*chase->append() = span;
*chase->append() = span;
#endif
return last->segment();
}
return lastSegment;
}
if (done) {
continue;
Expand Down Expand Up @@ -141,11 +149,14 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
}
}
if (first) {
// Only re-add span to chase if first segment is not done.
if (!first->done()) {
#if TRY_ROTATE
*chase->insert(0) = span;
*chase->insert(0) = span;
#else
*chase->append() = span;
*chase->append() = span;
#endif
}
return first;
}
}
Expand Down
61 changes: 56 additions & 5 deletions src/pathops/SkPathOpsOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "src/pathops/SkPathOpsCommon.h"
#include "src/pathops/SkPathWriter.h"

#include <algorithm>
#include <utility>

#if DEBUG_T_SECT_LOOP_COUNT
Expand All @@ -25,17 +26,25 @@ static bool findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase** startPtr
// OPTIMIZE: prev makes this compatible with old code -- but is it necessary?
*startPtr = span->ptT()->prev()->span();
SkOpSegment* segment = (*startPtr)->segment();
// Skip if the segment is already done to avoid infinite loop.
if (segment->done()) {
continue;
}
bool done = true;
*endPtr = nullptr;
if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
*startPtr = last->start();
*endPtr = last->end();
SkOpSegment* lastSegment = last->segment();
// Only re-add span to chase if the target segment is not done.
if (!lastSegment->done()) {
#if TRY_ROTATE
*chase.insert(0) = span;
*chase.insert(0) = span;
#else
*chase.append() = span;
*chase.append() = span;
#endif
*result = last->segment();
}
*result = lastSegment;
return true;
}
if (done) {
Expand Down Expand Up @@ -98,11 +107,14 @@ static bool findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase** startPtr
}
}
if (first) {
// Only re-add span to chase if first segment is not done.
if (!first->done()) {
#if TRY_ROTATE
*chase.insert(0) = span;
*chase.insert(0) = span;
#else
*chase.append() = span;
*chase.append() = span;
#endif
}
*result = first;
return true;
}
Expand All @@ -113,10 +125,30 @@ static bool findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase** startPtr

static bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op,
const int xorMask, const int xorOpMask, SkPathWriter* writer) {
// Count contours and segments for dynamic loop limits
int totalContours = 0;
int totalSegments = 0;
SkOpContour* contour = contourList;
while (contour) {
++totalContours;
totalSegments += contour->count();
contour = contour->next();
}
// Set loop limits based on what each loop processes
const int kMinLoops = 100;
const int kMultiplier = 10;
// Outer loop: processes contours, limit based on contour count
const int maxOuterLoops = std::max(kMinLoops, totalContours * kMultiplier);
// Curve loop: traverses segments, limit based on segment count
const int maxCurveLoops = std::max(kMinLoops, totalSegments * kMultiplier);
bool unsortable = false;
bool lastSimple = false;
bool simple = false;
int outerLoopCount = 0;
do {
if (++outerLoopCount > maxOuterLoops) {
break;
}
SkOpSpan* span = FindSortableTop(contourList);
if (!span) {
break;
Expand All @@ -125,9 +157,26 @@ static bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op,
SkOpSpanBase* start = span->next();
SkOpSpanBase* end = span;
SkTDArray<SkOpSpanBase*> chase;
// Calculate span count for current contour to set inner loop limit
int currentContourSpans = 0;
SkOpContour* currentContour = current->contour();
SkOpSegment* seg = currentContour->first();
while (seg) {
currentContourSpans += seg->count();
seg = seg->next();
}
const int maxInnerLoops = std::max(kMinLoops, currentContourSpans * kMultiplier);
int innerLoopCount = 0;
do {
if (++innerLoopCount > maxInnerLoops) {
break;
}
if (current->activeOp(start, end, xorMask, xorOpMask, op)) {
int curveLoopCount = 0;
do {
if (++curveLoopCount > maxCurveLoops) {
break;
}
if (!unsortable && current->done()) {
break;
}
Expand Down Expand Up @@ -371,6 +420,8 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
}

bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
printf("[DEBUG] Op(): called with op=%d\n", static_cast<int>(op));
fflush(stdout);
#if DEBUG_DUMP_VERIFY
if (SkPathOpsDebug::gVerifyOp) {
if (!OpDebug(one, two, op, result PkDEBUGPARAMS(false) PkDEBUGPARAMS(nullptr))) {
Expand Down
4 changes: 2 additions & 2 deletions src/pathops/SkPathOpsTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,8 @@ const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // FIXME: tune -- allow a few bits of error
const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16;
const double ROUGH_EPSILON = FLT_EPSILON * 64;
const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
const double WAY_ROUGH_EPSILON = FLT_EPSILON * 2048;
const double MORE_ROUGH_EPSILON = FLT_EPSILON * 8192; // Increased from 256 for near-tangent curves
const double WAY_ROUGH_EPSILON = FLT_EPSILON * 16384;
const double BUMP_EPSILON = FLT_EPSILON * 4096;

const SkScalar INVERSE_NUMBER_RANGE = FLT_EPSILON_ORDERABLE_ERR;
Expand Down