xref: /aosp_15_r20/external/skia/src/pathops/SkPathOpsWinding.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker // given a prospective edge, compute its initial winding by projecting a ray
9*c8dee2aaSAndroid Build Coastguard Worker // if the ray hits another edge
10*c8dee2aaSAndroid Build Coastguard Worker     // if the edge doesn't have a winding yet, hop up to that edge and start over
11*c8dee2aaSAndroid Build Coastguard Worker         // concern : check for hops forming a loop
12*c8dee2aaSAndroid Build Coastguard Worker     // if the edge is unsortable, or
13*c8dee2aaSAndroid Build Coastguard Worker     // the intersection is nearly at the ends, or
14*c8dee2aaSAndroid Build Coastguard Worker     // the tangent at the intersection is nearly coincident to the ray,
15*c8dee2aaSAndroid Build Coastguard Worker         // choose a different ray and try again
16*c8dee2aaSAndroid Build Coastguard Worker             // concern : if it is unable to succeed after N tries, try another edge? direction?
17*c8dee2aaSAndroid Build Coastguard Worker // if no edge is hit, compute the winding directly
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker // given the top span, project the most perpendicular ray and look for intersections
20*c8dee2aaSAndroid Build Coastguard Worker     // let's try up and then down. What the hey
21*c8dee2aaSAndroid Build Coastguard Worker 
22*c8dee2aaSAndroid Build Coastguard Worker // bestXY is initialized by caller with basePt
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTSort.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpContour.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpSegment.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpSpan.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsBounds.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsCurve.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsPoint.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsTypes.h"
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
44*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker enum class SkOpRayDir {
49*c8dee2aaSAndroid Build Coastguard Worker     kLeft,
50*c8dee2aaSAndroid Build Coastguard Worker     kTop,
51*c8dee2aaSAndroid Build Coastguard Worker     kRight,
52*c8dee2aaSAndroid Build Coastguard Worker     kBottom,
53*c8dee2aaSAndroid Build Coastguard Worker };
54*c8dee2aaSAndroid Build Coastguard Worker 
55*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_WINDING
56*c8dee2aaSAndroid Build Coastguard Worker const char* gDebugRayDirName[] = {
57*c8dee2aaSAndroid Build Coastguard Worker     "kLeft",
58*c8dee2aaSAndroid Build Coastguard Worker     "kTop",
59*c8dee2aaSAndroid Build Coastguard Worker     "kRight",
60*c8dee2aaSAndroid Build Coastguard Worker     "kBottom"
61*c8dee2aaSAndroid Build Coastguard Worker };
62*c8dee2aaSAndroid Build Coastguard Worker #endif
63*c8dee2aaSAndroid Build Coastguard Worker 
xy_index(SkOpRayDir dir)64*c8dee2aaSAndroid Build Coastguard Worker static int xy_index(SkOpRayDir dir) {
65*c8dee2aaSAndroid Build Coastguard Worker     return static_cast<int>(dir) & 1;
66*c8dee2aaSAndroid Build Coastguard Worker }
67*c8dee2aaSAndroid Build Coastguard Worker 
pt_xy(const SkPoint & pt,SkOpRayDir dir)68*c8dee2aaSAndroid Build Coastguard Worker static SkScalar pt_xy(const SkPoint& pt, SkOpRayDir dir) {
69*c8dee2aaSAndroid Build Coastguard Worker     return (&pt.fX)[xy_index(dir)];
70*c8dee2aaSAndroid Build Coastguard Worker }
71*c8dee2aaSAndroid Build Coastguard Worker 
pt_yx(const SkPoint & pt,SkOpRayDir dir)72*c8dee2aaSAndroid Build Coastguard Worker static SkScalar pt_yx(const SkPoint& pt, SkOpRayDir dir) {
73*c8dee2aaSAndroid Build Coastguard Worker     return (&pt.fX)[!xy_index(dir)];
74*c8dee2aaSAndroid Build Coastguard Worker }
75*c8dee2aaSAndroid Build Coastguard Worker 
pt_dxdy(const SkDVector & v,SkOpRayDir dir)76*c8dee2aaSAndroid Build Coastguard Worker static double pt_dxdy(const SkDVector& v, SkOpRayDir dir) {
77*c8dee2aaSAndroid Build Coastguard Worker     return (&v.fX)[xy_index(dir)];
78*c8dee2aaSAndroid Build Coastguard Worker }
79*c8dee2aaSAndroid Build Coastguard Worker 
pt_dydx(const SkDVector & v,SkOpRayDir dir)80*c8dee2aaSAndroid Build Coastguard Worker static double pt_dydx(const SkDVector& v, SkOpRayDir dir) {
81*c8dee2aaSAndroid Build Coastguard Worker     return (&v.fX)[!xy_index(dir)];
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker 
rect_side(const SkRect & r,SkOpRayDir dir)84*c8dee2aaSAndroid Build Coastguard Worker static SkScalar rect_side(const SkRect& r, SkOpRayDir dir) {
85*c8dee2aaSAndroid Build Coastguard Worker     return (&r.fLeft)[static_cast<int>(dir)];
86*c8dee2aaSAndroid Build Coastguard Worker }
87*c8dee2aaSAndroid Build Coastguard Worker 
sideways_overlap(const SkRect & rect,const SkPoint & pt,SkOpRayDir dir)88*c8dee2aaSAndroid Build Coastguard Worker static bool sideways_overlap(const SkRect& rect, const SkPoint& pt, SkOpRayDir dir) {
89*c8dee2aaSAndroid Build Coastguard Worker     int i = !xy_index(dir);
90*c8dee2aaSAndroid Build Coastguard Worker     return approximately_between((&rect.fLeft)[i], (&pt.fX)[i], (&rect.fRight)[i]);
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker 
less_than(SkOpRayDir dir)93*c8dee2aaSAndroid Build Coastguard Worker static bool less_than(SkOpRayDir dir) {
94*c8dee2aaSAndroid Build Coastguard Worker     return static_cast<bool>((static_cast<int>(dir) & 2) == 0);
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker 
ccw_dxdy(const SkDVector & v,SkOpRayDir dir)97*c8dee2aaSAndroid Build Coastguard Worker static bool ccw_dxdy(const SkDVector& v, SkOpRayDir dir) {
98*c8dee2aaSAndroid Build Coastguard Worker     bool vPartPos = pt_dydx(v, dir) > 0;
99*c8dee2aaSAndroid Build Coastguard Worker     bool leftBottom = ((static_cast<int>(dir) + 1) & 2) != 0;
100*c8dee2aaSAndroid Build Coastguard Worker     return vPartPos == leftBottom;
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker struct SkOpRayHit {
makeTestBaseSkOpRayHit104*c8dee2aaSAndroid Build Coastguard Worker     SkOpRayDir makeTestBase(SkOpSpan* span, double t) {
105*c8dee2aaSAndroid Build Coastguard Worker         fNext = nullptr;
106*c8dee2aaSAndroid Build Coastguard Worker         fSpan = span;
107*c8dee2aaSAndroid Build Coastguard Worker         fT = span->t() * (1 - t) + span->next()->t() * t;
108*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = span->segment();
109*c8dee2aaSAndroid Build Coastguard Worker         fSlope = segment->dSlopeAtT(fT);
110*c8dee2aaSAndroid Build Coastguard Worker         fPt = segment->ptAtT(fT);
111*c8dee2aaSAndroid Build Coastguard Worker         fValid = true;
112*c8dee2aaSAndroid Build Coastguard Worker         return fabs(fSlope.fX) < fabs(fSlope.fY) ? SkOpRayDir::kLeft : SkOpRayDir::kTop;
113*c8dee2aaSAndroid Build Coastguard Worker     }
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker     SkOpRayHit* fNext;
116*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpan* fSpan;
117*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fPt;
118*c8dee2aaSAndroid Build Coastguard Worker     double fT;
119*c8dee2aaSAndroid Build Coastguard Worker     SkDVector fSlope;
120*c8dee2aaSAndroid Build Coastguard Worker     bool fValid;
121*c8dee2aaSAndroid Build Coastguard Worker };
122*c8dee2aaSAndroid Build Coastguard Worker 
rayCheck(const SkOpRayHit & base,SkOpRayDir dir,SkOpRayHit ** hits,SkArenaAlloc * allocator)123*c8dee2aaSAndroid Build Coastguard Worker void SkOpContour::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits,
124*c8dee2aaSAndroid Build Coastguard Worker                            SkArenaAlloc* allocator) {
125*c8dee2aaSAndroid Build Coastguard Worker     // if the bounds extreme is outside the best, we're done
126*c8dee2aaSAndroid Build Coastguard Worker     SkScalar baseXY = pt_xy(base.fPt, dir);
127*c8dee2aaSAndroid Build Coastguard Worker     SkScalar boundsXY = rect_side(fBounds, dir);
128*c8dee2aaSAndroid Build Coastguard Worker     bool checkLessThan = less_than(dir);
129*c8dee2aaSAndroid Build Coastguard Worker     if (!approximately_equal(baseXY, boundsXY) && (baseXY < boundsXY) == checkLessThan) {
130*c8dee2aaSAndroid Build Coastguard Worker         return;
131*c8dee2aaSAndroid Build Coastguard Worker     }
132*c8dee2aaSAndroid Build Coastguard Worker     SkOpSegment* testSegment = &fHead;
133*c8dee2aaSAndroid Build Coastguard Worker     do {
134*c8dee2aaSAndroid Build Coastguard Worker         testSegment->rayCheck(base, dir, hits, allocator);
135*c8dee2aaSAndroid Build Coastguard Worker     } while ((testSegment = testSegment->next()));
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker 
rayCheck(const SkOpRayHit & base,SkOpRayDir dir,SkOpRayHit ** hits,SkArenaAlloc * allocator)138*c8dee2aaSAndroid Build Coastguard Worker void SkOpSegment::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits,
139*c8dee2aaSAndroid Build Coastguard Worker                            SkArenaAlloc* allocator) {
140*c8dee2aaSAndroid Build Coastguard Worker     if (!sideways_overlap(fBounds, base.fPt, dir)) {
141*c8dee2aaSAndroid Build Coastguard Worker         return;
142*c8dee2aaSAndroid Build Coastguard Worker     }
143*c8dee2aaSAndroid Build Coastguard Worker     SkScalar baseXY = pt_xy(base.fPt, dir);
144*c8dee2aaSAndroid Build Coastguard Worker     SkScalar boundsXY = rect_side(fBounds, dir);
145*c8dee2aaSAndroid Build Coastguard Worker     bool checkLessThan = less_than(dir);
146*c8dee2aaSAndroid Build Coastguard Worker     if (!approximately_equal(baseXY, boundsXY) && (baseXY < boundsXY) == checkLessThan) {
147*c8dee2aaSAndroid Build Coastguard Worker         return;
148*c8dee2aaSAndroid Build Coastguard Worker     }
149*c8dee2aaSAndroid Build Coastguard Worker     double tVals[3];
150*c8dee2aaSAndroid Build Coastguard Worker     SkScalar baseYX = pt_yx(base.fPt, dir);
151*c8dee2aaSAndroid Build Coastguard Worker     int roots = (*CurveIntercept[fVerb * 2 + xy_index(dir)])(fPts, fWeight, baseYX, tVals);
152*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < roots; ++index) {
153*c8dee2aaSAndroid Build Coastguard Worker         double t = tVals[index];
154*c8dee2aaSAndroid Build Coastguard Worker         if (base.fSpan->segment() == this && approximately_equal(base.fT, t)) {
155*c8dee2aaSAndroid Build Coastguard Worker             continue;
156*c8dee2aaSAndroid Build Coastguard Worker         }
157*c8dee2aaSAndroid Build Coastguard Worker         SkDVector slope;
158*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pt;
159*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(sk_bzero(&slope, sizeof(slope)));
160*c8dee2aaSAndroid Build Coastguard Worker         bool valid = false;
161*c8dee2aaSAndroid Build Coastguard Worker         if (approximately_zero(t)) {
162*c8dee2aaSAndroid Build Coastguard Worker             pt = fPts[0];
163*c8dee2aaSAndroid Build Coastguard Worker         } else if (approximately_equal(t, 1)) {
164*c8dee2aaSAndroid Build Coastguard Worker             pt = fPts[SkPathOpsVerbToPoints(fVerb)];
165*c8dee2aaSAndroid Build Coastguard Worker         } else {
166*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(between(0, t, 1));
167*c8dee2aaSAndroid Build Coastguard Worker             pt = this->ptAtT(t);
168*c8dee2aaSAndroid Build Coastguard Worker             if (SkDPoint::ApproximatelyEqual(pt, base.fPt)) {
169*c8dee2aaSAndroid Build Coastguard Worker                 if (base.fSpan->segment() == this) {
170*c8dee2aaSAndroid Build Coastguard Worker                     continue;
171*c8dee2aaSAndroid Build Coastguard Worker                 }
172*c8dee2aaSAndroid Build Coastguard Worker             } else {
173*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar ptXY = pt_xy(pt, dir);
174*c8dee2aaSAndroid Build Coastguard Worker                 if (!approximately_equal(baseXY, ptXY) && (baseXY < ptXY) == checkLessThan) {
175*c8dee2aaSAndroid Build Coastguard Worker                     continue;
176*c8dee2aaSAndroid Build Coastguard Worker                 }
177*c8dee2aaSAndroid Build Coastguard Worker                 slope = this->dSlopeAtT(t);
178*c8dee2aaSAndroid Build Coastguard Worker                 if (fVerb == SkPath::kCubic_Verb && base.fSpan->segment() == this
179*c8dee2aaSAndroid Build Coastguard Worker                         && roughly_equal(base.fT, t)
180*c8dee2aaSAndroid Build Coastguard Worker                         && SkDPoint::RoughlyEqual(pt, base.fPt)) {
181*c8dee2aaSAndroid Build Coastguard Worker     #if DEBUG_WINDING
182*c8dee2aaSAndroid Build Coastguard Worker                     SkDebugf("%s (rarely expect this)\n", __FUNCTION__);
183*c8dee2aaSAndroid Build Coastguard Worker     #endif
184*c8dee2aaSAndroid Build Coastguard Worker                     continue;
185*c8dee2aaSAndroid Build Coastguard Worker                 }
186*c8dee2aaSAndroid Build Coastguard Worker                 if (fabs(pt_dydx(slope, dir) * 10000) > fabs(pt_dxdy(slope, dir))) {
187*c8dee2aaSAndroid Build Coastguard Worker                     valid = true;
188*c8dee2aaSAndroid Build Coastguard Worker                 }
189*c8dee2aaSAndroid Build Coastguard Worker             }
190*c8dee2aaSAndroid Build Coastguard Worker         }
191*c8dee2aaSAndroid Build Coastguard Worker         SkOpSpan* span = this->windingSpanAtT(t);
192*c8dee2aaSAndroid Build Coastguard Worker         if (!span) {
193*c8dee2aaSAndroid Build Coastguard Worker             valid = false;
194*c8dee2aaSAndroid Build Coastguard Worker         } else if (!span->windValue() && !span->oppValue()) {
195*c8dee2aaSAndroid Build Coastguard Worker             continue;
196*c8dee2aaSAndroid Build Coastguard Worker         }
197*c8dee2aaSAndroid Build Coastguard Worker         SkOpRayHit* newHit = allocator->make<SkOpRayHit>();
198*c8dee2aaSAndroid Build Coastguard Worker         newHit->fNext = *hits;
199*c8dee2aaSAndroid Build Coastguard Worker         newHit->fPt = pt;
200*c8dee2aaSAndroid Build Coastguard Worker         newHit->fSlope = slope;
201*c8dee2aaSAndroid Build Coastguard Worker         newHit->fSpan = span;
202*c8dee2aaSAndroid Build Coastguard Worker         newHit->fT = t;
203*c8dee2aaSAndroid Build Coastguard Worker         newHit->fValid = valid;
204*c8dee2aaSAndroid Build Coastguard Worker         *hits = newHit;
205*c8dee2aaSAndroid Build Coastguard Worker     }
206*c8dee2aaSAndroid Build Coastguard Worker }
207*c8dee2aaSAndroid Build Coastguard Worker 
windingSpanAtT(double tHit)208*c8dee2aaSAndroid Build Coastguard Worker SkOpSpan* SkOpSegment::windingSpanAtT(double tHit) {
209*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpan* span = &fHead;
210*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpanBase* next;
211*c8dee2aaSAndroid Build Coastguard Worker     do {
212*c8dee2aaSAndroid Build Coastguard Worker         next = span->next();
213*c8dee2aaSAndroid Build Coastguard Worker         if (approximately_equal(tHit, next->t())) {
214*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
215*c8dee2aaSAndroid Build Coastguard Worker         }
216*c8dee2aaSAndroid Build Coastguard Worker         if (tHit < next->t()) {
217*c8dee2aaSAndroid Build Coastguard Worker             return span;
218*c8dee2aaSAndroid Build Coastguard Worker         }
219*c8dee2aaSAndroid Build Coastguard Worker     } while (!next->final() && (span = next->upCast()));
220*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
221*c8dee2aaSAndroid Build Coastguard Worker }
222*c8dee2aaSAndroid Build Coastguard Worker 
hit_compare_x(const SkOpRayHit * a,const SkOpRayHit * b)223*c8dee2aaSAndroid Build Coastguard Worker static bool hit_compare_x(const SkOpRayHit* a, const SkOpRayHit* b) {
224*c8dee2aaSAndroid Build Coastguard Worker     return a->fPt.fX < b->fPt.fX;
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker 
reverse_hit_compare_x(const SkOpRayHit * a,const SkOpRayHit * b)227*c8dee2aaSAndroid Build Coastguard Worker static bool reverse_hit_compare_x(const SkOpRayHit* a, const SkOpRayHit* b) {
228*c8dee2aaSAndroid Build Coastguard Worker     return b->fPt.fX  < a->fPt.fX;
229*c8dee2aaSAndroid Build Coastguard Worker }
230*c8dee2aaSAndroid Build Coastguard Worker 
hit_compare_y(const SkOpRayHit * a,const SkOpRayHit * b)231*c8dee2aaSAndroid Build Coastguard Worker static bool hit_compare_y(const SkOpRayHit* a, const SkOpRayHit* b) {
232*c8dee2aaSAndroid Build Coastguard Worker     return a->fPt.fY < b->fPt.fY;
233*c8dee2aaSAndroid Build Coastguard Worker }
234*c8dee2aaSAndroid Build Coastguard Worker 
reverse_hit_compare_y(const SkOpRayHit * a,const SkOpRayHit * b)235*c8dee2aaSAndroid Build Coastguard Worker static bool reverse_hit_compare_y(const SkOpRayHit* a, const SkOpRayHit* b) {
236*c8dee2aaSAndroid Build Coastguard Worker     return b->fPt.fY  < a->fPt.fY;
237*c8dee2aaSAndroid Build Coastguard Worker }
238*c8dee2aaSAndroid Build Coastguard Worker 
get_t_guess(int tTry,int * dirOffset)239*c8dee2aaSAndroid Build Coastguard Worker static double get_t_guess(int tTry, int* dirOffset) {
240*c8dee2aaSAndroid Build Coastguard Worker     double t = 0.5;
241*c8dee2aaSAndroid Build Coastguard Worker     *dirOffset = tTry & 1;
242*c8dee2aaSAndroid Build Coastguard Worker     int tBase = tTry >> 1;
243*c8dee2aaSAndroid Build Coastguard Worker     int tBits = 0;
244*c8dee2aaSAndroid Build Coastguard Worker     while (tTry >>= 1) {
245*c8dee2aaSAndroid Build Coastguard Worker         t /= 2;
246*c8dee2aaSAndroid Build Coastguard Worker         ++tBits;
247*c8dee2aaSAndroid Build Coastguard Worker     }
248*c8dee2aaSAndroid Build Coastguard Worker     if (tBits) {
249*c8dee2aaSAndroid Build Coastguard Worker         int tIndex = (tBase - 1) & ((1 << tBits) - 1);
250*c8dee2aaSAndroid Build Coastguard Worker         t += t * 2 * tIndex;
251*c8dee2aaSAndroid Build Coastguard Worker     }
252*c8dee2aaSAndroid Build Coastguard Worker     return t;
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker 
sortableTop(SkOpContour * contourHead)255*c8dee2aaSAndroid Build Coastguard Worker bool SkOpSpan::sortableTop(SkOpContour* contourHead) {
256*c8dee2aaSAndroid Build Coastguard Worker     SkSTArenaAlloc<1024> allocator;
257*c8dee2aaSAndroid Build Coastguard Worker     int dirOffset;
258*c8dee2aaSAndroid Build Coastguard Worker     double t = get_t_guess(fTopTTry++, &dirOffset);
259*c8dee2aaSAndroid Build Coastguard Worker     SkOpRayHit hitBase;
260*c8dee2aaSAndroid Build Coastguard Worker     SkOpRayDir dir = hitBase.makeTestBase(this, t);
261*c8dee2aaSAndroid Build Coastguard Worker     if (hitBase.fSlope.fX == 0 && hitBase.fSlope.fY == 0) {
262*c8dee2aaSAndroid Build Coastguard Worker         return false;
263*c8dee2aaSAndroid Build Coastguard Worker     }
264*c8dee2aaSAndroid Build Coastguard Worker     SkOpRayHit* hitHead = &hitBase;
265*c8dee2aaSAndroid Build Coastguard Worker     dir = static_cast<SkOpRayDir>(static_cast<int>(dir) + dirOffset);
266*c8dee2aaSAndroid Build Coastguard Worker     if (hitBase.fSpan && hitBase.fSpan->segment()->verb() > SkPath::kLine_Verb
267*c8dee2aaSAndroid Build Coastguard Worker             && !pt_dydx(hitBase.fSlope, dir)) {
268*c8dee2aaSAndroid Build Coastguard Worker         return false;
269*c8dee2aaSAndroid Build Coastguard Worker     }
270*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour* contour = contourHead;
271*c8dee2aaSAndroid Build Coastguard Worker     do {
272*c8dee2aaSAndroid Build Coastguard Worker         if (!contour->count()) {
273*c8dee2aaSAndroid Build Coastguard Worker             continue;
274*c8dee2aaSAndroid Build Coastguard Worker         }
275*c8dee2aaSAndroid Build Coastguard Worker         contour->rayCheck(hitBase, dir, &hitHead, &allocator);
276*c8dee2aaSAndroid Build Coastguard Worker     } while ((contour = contour->next()));
277*c8dee2aaSAndroid Build Coastguard Worker     // sort hits
278*c8dee2aaSAndroid Build Coastguard Worker     STArray<1, SkOpRayHit*> sorted;
279*c8dee2aaSAndroid Build Coastguard Worker     SkOpRayHit* hit = hitHead;
280*c8dee2aaSAndroid Build Coastguard Worker     while (hit) {
281*c8dee2aaSAndroid Build Coastguard Worker         sorted.push_back(hit);
282*c8dee2aaSAndroid Build Coastguard Worker         hit = hit->fNext;
283*c8dee2aaSAndroid Build Coastguard Worker     }
284*c8dee2aaSAndroid Build Coastguard Worker     int count = sorted.size();
285*c8dee2aaSAndroid Build Coastguard Worker     SkTQSort(sorted.begin(), sorted.end(),
286*c8dee2aaSAndroid Build Coastguard Worker              xy_index(dir) ? less_than(dir) ? hit_compare_y : reverse_hit_compare_y
287*c8dee2aaSAndroid Build Coastguard Worker                            : less_than(dir) ? hit_compare_x : reverse_hit_compare_x);
288*c8dee2aaSAndroid Build Coastguard Worker     // verify windings
289*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_WINDING
290*c8dee2aaSAndroid Build Coastguard Worker     SkDebugf("%s dir=%s seg=%d t=%1.9g pt=(%1.9g,%1.9g)\n", __FUNCTION__,
291*c8dee2aaSAndroid Build Coastguard Worker             gDebugRayDirName[static_cast<int>(dir)], hitBase.fSpan->segment()->debugID(),
292*c8dee2aaSAndroid Build Coastguard Worker             hitBase.fT, hitBase.fPt.fX, hitBase.fPt.fY);
293*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < count; ++index) {
294*c8dee2aaSAndroid Build Coastguard Worker         hit = sorted[index];
295*c8dee2aaSAndroid Build Coastguard Worker         SkOpSpan* span = hit->fSpan;
296*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* hitSegment = span ? span->segment() : nullptr;
297*c8dee2aaSAndroid Build Coastguard Worker         bool operand = span ? hitSegment->operand() : false;
298*c8dee2aaSAndroid Build Coastguard Worker         bool ccw = ccw_dxdy(hit->fSlope, dir);
299*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("%s [%d] valid=%d operand=%d span=%d ccw=%d ", __FUNCTION__, index,
300*c8dee2aaSAndroid Build Coastguard Worker                 hit->fValid, operand, span ? span->debugID() : -1, ccw);
301*c8dee2aaSAndroid Build Coastguard Worker         if (span) {
302*c8dee2aaSAndroid Build Coastguard Worker             hitSegment->dumpPtsInner();
303*c8dee2aaSAndroid Build Coastguard Worker         }
304*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf(" t=%1.9g pt=(%1.9g,%1.9g) slope=(%1.9g,%1.9g)\n", hit->fT,
305*c8dee2aaSAndroid Build Coastguard Worker                 hit->fPt.fX, hit->fPt.fY, hit->fSlope.fX, hit->fSlope.fY);
306*c8dee2aaSAndroid Build Coastguard Worker     }
307*c8dee2aaSAndroid Build Coastguard Worker #endif
308*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint* last = nullptr;
309*c8dee2aaSAndroid Build Coastguard Worker     int wind = 0;
310*c8dee2aaSAndroid Build Coastguard Worker     int oppWind = 0;
311*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < count; ++index) {
312*c8dee2aaSAndroid Build Coastguard Worker         hit = sorted[index];
313*c8dee2aaSAndroid Build Coastguard Worker         if (!hit->fValid) {
314*c8dee2aaSAndroid Build Coastguard Worker             return false;
315*c8dee2aaSAndroid Build Coastguard Worker         }
316*c8dee2aaSAndroid Build Coastguard Worker         bool ccw = ccw_dxdy(hit->fSlope, dir);
317*c8dee2aaSAndroid Build Coastguard Worker //        SkASSERT(!approximately_zero(hit->fT) || !hit->fValid);
318*c8dee2aaSAndroid Build Coastguard Worker         SkOpSpan* span = hit->fSpan;
319*c8dee2aaSAndroid Build Coastguard Worker         if (!span) {
320*c8dee2aaSAndroid Build Coastguard Worker             return false;
321*c8dee2aaSAndroid Build Coastguard Worker         }
322*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* hitSegment = span->segment();
323*c8dee2aaSAndroid Build Coastguard Worker         if (span->windValue() == 0 && span->oppValue() == 0) {
324*c8dee2aaSAndroid Build Coastguard Worker             continue;
325*c8dee2aaSAndroid Build Coastguard Worker         }
326*c8dee2aaSAndroid Build Coastguard Worker         if (last && SkDPoint::ApproximatelyEqual(*last, hit->fPt)) {
327*c8dee2aaSAndroid Build Coastguard Worker             return false;
328*c8dee2aaSAndroid Build Coastguard Worker         }
329*c8dee2aaSAndroid Build Coastguard Worker         if (index < count - 1) {
330*c8dee2aaSAndroid Build Coastguard Worker             const SkPoint& next = sorted[index + 1]->fPt;
331*c8dee2aaSAndroid Build Coastguard Worker             if (SkDPoint::ApproximatelyEqual(next, hit->fPt)) {
332*c8dee2aaSAndroid Build Coastguard Worker                 return false;
333*c8dee2aaSAndroid Build Coastguard Worker             }
334*c8dee2aaSAndroid Build Coastguard Worker         }
335*c8dee2aaSAndroid Build Coastguard Worker         bool operand = hitSegment->operand();
336*c8dee2aaSAndroid Build Coastguard Worker         if (operand) {
337*c8dee2aaSAndroid Build Coastguard Worker             using std::swap;
338*c8dee2aaSAndroid Build Coastguard Worker             swap(wind, oppWind);
339*c8dee2aaSAndroid Build Coastguard Worker         }
340*c8dee2aaSAndroid Build Coastguard Worker         int lastWind = wind;
341*c8dee2aaSAndroid Build Coastguard Worker         int lastOpp = oppWind;
342*c8dee2aaSAndroid Build Coastguard Worker         int windValue = ccw ? -span->windValue() : span->windValue();
343*c8dee2aaSAndroid Build Coastguard Worker         int oppValue = ccw ? -span->oppValue() : span->oppValue();
344*c8dee2aaSAndroid Build Coastguard Worker         wind += windValue;
345*c8dee2aaSAndroid Build Coastguard Worker         oppWind += oppValue;
346*c8dee2aaSAndroid Build Coastguard Worker         bool sumSet = false;
347*c8dee2aaSAndroid Build Coastguard Worker         int spanSum = span->windSum();
348*c8dee2aaSAndroid Build Coastguard Worker         int windSum = SkOpSegment::UseInnerWinding(lastWind, wind) ? wind : lastWind;
349*c8dee2aaSAndroid Build Coastguard Worker         if (spanSum == SK_MinS32) {
350*c8dee2aaSAndroid Build Coastguard Worker             span->setWindSum(windSum);
351*c8dee2aaSAndroid Build Coastguard Worker             sumSet = true;
352*c8dee2aaSAndroid Build Coastguard Worker         } else {
353*c8dee2aaSAndroid Build Coastguard Worker             // the need for this condition suggests that UseInnerWinding is flawed
354*c8dee2aaSAndroid Build Coastguard Worker             // happened when last = 1 wind = -1
355*c8dee2aaSAndroid Build Coastguard Worker #if 0
356*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT((hitSegment->isXor() ? (windSum & 1) == (spanSum & 1) : windSum == spanSum)
357*c8dee2aaSAndroid Build Coastguard Worker                     || (abs(wind) == abs(lastWind)
358*c8dee2aaSAndroid Build Coastguard Worker                     && (windSum ^ wind ^ lastWind) == spanSum));
359*c8dee2aaSAndroid Build Coastguard Worker #endif
360*c8dee2aaSAndroid Build Coastguard Worker         }
361*c8dee2aaSAndroid Build Coastguard Worker         int oSpanSum = span->oppSum();
362*c8dee2aaSAndroid Build Coastguard Worker         int oppSum = SkOpSegment::UseInnerWinding(lastOpp, oppWind) ? oppWind : lastOpp;
363*c8dee2aaSAndroid Build Coastguard Worker         if (oSpanSum == SK_MinS32) {
364*c8dee2aaSAndroid Build Coastguard Worker             span->setOppSum(oppSum);
365*c8dee2aaSAndroid Build Coastguard Worker         } else {
366*c8dee2aaSAndroid Build Coastguard Worker #if 0
367*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(hitSegment->oppXor() ? (oppSum & 1) == (oSpanSum & 1) : oppSum == oSpanSum
368*c8dee2aaSAndroid Build Coastguard Worker                     || (abs(oppWind) == abs(lastOpp)
369*c8dee2aaSAndroid Build Coastguard Worker                     && (oppSum ^ oppWind ^ lastOpp) == oSpanSum));
370*c8dee2aaSAndroid Build Coastguard Worker #endif
371*c8dee2aaSAndroid Build Coastguard Worker         }
372*c8dee2aaSAndroid Build Coastguard Worker         if (sumSet) {
373*c8dee2aaSAndroid Build Coastguard Worker             if (this->globalState()->phase() == SkOpPhase::kFixWinding) {
374*c8dee2aaSAndroid Build Coastguard Worker                 hitSegment->contour()->setCcw(ccw);
375*c8dee2aaSAndroid Build Coastguard Worker             } else {
376*c8dee2aaSAndroid Build Coastguard Worker                 (void) hitSegment->markAndChaseWinding(span, span->next(), windSum, oppSum, nullptr);
377*c8dee2aaSAndroid Build Coastguard Worker                 (void) hitSegment->markAndChaseWinding(span->next(), span, windSum, oppSum, nullptr);
378*c8dee2aaSAndroid Build Coastguard Worker             }
379*c8dee2aaSAndroid Build Coastguard Worker         }
380*c8dee2aaSAndroid Build Coastguard Worker         if (operand) {
381*c8dee2aaSAndroid Build Coastguard Worker             using std::swap;
382*c8dee2aaSAndroid Build Coastguard Worker             swap(wind, oppWind);
383*c8dee2aaSAndroid Build Coastguard Worker         }
384*c8dee2aaSAndroid Build Coastguard Worker         last = &hit->fPt;
385*c8dee2aaSAndroid Build Coastguard Worker         this->globalState()->bumpNested();
386*c8dee2aaSAndroid Build Coastguard Worker     }
387*c8dee2aaSAndroid Build Coastguard Worker     return true;
388*c8dee2aaSAndroid Build Coastguard Worker }
389*c8dee2aaSAndroid Build Coastguard Worker 
findSortableTop(SkOpContour * contourHead)390*c8dee2aaSAndroid Build Coastguard Worker SkOpSpan* SkOpSegment::findSortableTop(SkOpContour* contourHead) {
391*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpan* span = &fHead;
392*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpanBase* next;
393*c8dee2aaSAndroid Build Coastguard Worker     do {
394*c8dee2aaSAndroid Build Coastguard Worker         next = span->next();
395*c8dee2aaSAndroid Build Coastguard Worker         if (span->done()) {
396*c8dee2aaSAndroid Build Coastguard Worker             continue;
397*c8dee2aaSAndroid Build Coastguard Worker         }
398*c8dee2aaSAndroid Build Coastguard Worker         if (span->windSum() != SK_MinS32) {
399*c8dee2aaSAndroid Build Coastguard Worker             return span;
400*c8dee2aaSAndroid Build Coastguard Worker         }
401*c8dee2aaSAndroid Build Coastguard Worker         if (span->sortableTop(contourHead)) {
402*c8dee2aaSAndroid Build Coastguard Worker             return span;
403*c8dee2aaSAndroid Build Coastguard Worker         }
404*c8dee2aaSAndroid Build Coastguard Worker     } while (!next->final() && (span = next->upCast()));
405*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
406*c8dee2aaSAndroid Build Coastguard Worker }
407*c8dee2aaSAndroid Build Coastguard Worker 
findSortableTop(SkOpContour * contourHead)408*c8dee2aaSAndroid Build Coastguard Worker SkOpSpan* SkOpContour::findSortableTop(SkOpContour* contourHead) {
409*c8dee2aaSAndroid Build Coastguard Worker     bool allDone = true;
410*c8dee2aaSAndroid Build Coastguard Worker     if (fCount) {
411*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* testSegment = &fHead;
412*c8dee2aaSAndroid Build Coastguard Worker         do {
413*c8dee2aaSAndroid Build Coastguard Worker             if (testSegment->done()) {
414*c8dee2aaSAndroid Build Coastguard Worker                 continue;
415*c8dee2aaSAndroid Build Coastguard Worker             }
416*c8dee2aaSAndroid Build Coastguard Worker             allDone = false;
417*c8dee2aaSAndroid Build Coastguard Worker             SkOpSpan* result = testSegment->findSortableTop(contourHead);
418*c8dee2aaSAndroid Build Coastguard Worker             if (result) {
419*c8dee2aaSAndroid Build Coastguard Worker                 return result;
420*c8dee2aaSAndroid Build Coastguard Worker             }
421*c8dee2aaSAndroid Build Coastguard Worker         } while ((testSegment = testSegment->next()));
422*c8dee2aaSAndroid Build Coastguard Worker     }
423*c8dee2aaSAndroid Build Coastguard Worker     if (allDone) {
424*c8dee2aaSAndroid Build Coastguard Worker       fDone = true;
425*c8dee2aaSAndroid Build Coastguard Worker     }
426*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
427*c8dee2aaSAndroid Build Coastguard Worker }
428*c8dee2aaSAndroid Build Coastguard Worker 
FindSortableTop(SkOpContourHead * contourHead)429*c8dee2aaSAndroid Build Coastguard Worker SkOpSpan* FindSortableTop(SkOpContourHead* contourHead) {
430*c8dee2aaSAndroid Build Coastguard Worker     for (int index = 0; index < SkOpGlobalState::kMaxWindingTries; ++index) {
431*c8dee2aaSAndroid Build Coastguard Worker         SkOpContour* contour = contourHead;
432*c8dee2aaSAndroid Build Coastguard Worker         do {
433*c8dee2aaSAndroid Build Coastguard Worker             if (contour->done()) {
434*c8dee2aaSAndroid Build Coastguard Worker                 continue;
435*c8dee2aaSAndroid Build Coastguard Worker             }
436*c8dee2aaSAndroid Build Coastguard Worker             SkOpSpan* result = contour->findSortableTop(contourHead);
437*c8dee2aaSAndroid Build Coastguard Worker             if (result) {
438*c8dee2aaSAndroid Build Coastguard Worker                 return result;
439*c8dee2aaSAndroid Build Coastguard Worker             }
440*c8dee2aaSAndroid Build Coastguard Worker         } while ((contour = contour->next()));
441*c8dee2aaSAndroid Build Coastguard Worker     }
442*c8dee2aaSAndroid Build Coastguard Worker     return nullptr;
443*c8dee2aaSAndroid Build Coastguard Worker }
444