1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2014 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 #include "src/pathops/SkPathOpsTSect.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMacros.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTSort.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkIntersections.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsConic.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsCubic.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsLine.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsQuad.h"
19*c8dee2aaSAndroid Build Coastguard Worker
20*c8dee2aaSAndroid Build Coastguard Worker #include <cfloat>
21*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
22*c8dee2aaSAndroid Build Coastguard Worker #include <array>
23*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker #define COINCIDENT_SPAN_COUNT 9
28*c8dee2aaSAndroid Build Coastguard Worker
setPerp(const SkTCurve & c1,double t,const SkDPoint & cPt,const SkTCurve & c2)29*c8dee2aaSAndroid Build Coastguard Worker void SkTCoincident::setPerp(const SkTCurve& c1, double t,
30*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint& cPt, const SkTCurve& c2) {
31*c8dee2aaSAndroid Build Coastguard Worker SkDVector dxdy = c1.dxdyAtT(t);
32*c8dee2aaSAndroid Build Coastguard Worker SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
33*c8dee2aaSAndroid Build Coastguard Worker SkIntersections i SkDEBUGCODE((c1.globalState()));
34*c8dee2aaSAndroid Build Coastguard Worker int used = i.intersectRay(c2, perp);
35*c8dee2aaSAndroid Build Coastguard Worker // only keep closest
36*c8dee2aaSAndroid Build Coastguard Worker if (used == 0 || used == 3) {
37*c8dee2aaSAndroid Build Coastguard Worker this->init();
38*c8dee2aaSAndroid Build Coastguard Worker return;
39*c8dee2aaSAndroid Build Coastguard Worker }
40*c8dee2aaSAndroid Build Coastguard Worker fPerpT = i[0][0];
41*c8dee2aaSAndroid Build Coastguard Worker fPerpPt = i.pt(0);
42*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(used <= 2);
43*c8dee2aaSAndroid Build Coastguard Worker if (used == 2) {
44*c8dee2aaSAndroid Build Coastguard Worker double distSq = (fPerpPt - cPt).lengthSquared();
45*c8dee2aaSAndroid Build Coastguard Worker double dist2Sq = (i.pt(1) - cPt).lengthSquared();
46*c8dee2aaSAndroid Build Coastguard Worker if (dist2Sq < distSq) {
47*c8dee2aaSAndroid Build Coastguard Worker fPerpT = i[0][1];
48*c8dee2aaSAndroid Build Coastguard Worker fPerpPt = i.pt(1);
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
52*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("setPerp t=%1.9g cPt=(%1.9g,%1.9g) %s oppT=%1.9g fPerpPt=(%1.9g,%1.9g)\n",
53*c8dee2aaSAndroid Build Coastguard Worker t, cPt.fX, cPt.fY,
54*c8dee2aaSAndroid Build Coastguard Worker cPt.approximatelyEqual(fPerpPt) ? "==" : "!=", fPerpT, fPerpPt.fX, fPerpPt.fY);
55*c8dee2aaSAndroid Build Coastguard Worker #endif
56*c8dee2aaSAndroid Build Coastguard Worker fMatch = cPt.approximatelyEqual(fPerpPt);
57*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
58*c8dee2aaSAndroid Build Coastguard Worker if (fMatch) {
59*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s", ""); // allow setting breakpoint
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker #endif
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker
addBounded(SkTSpan * span,SkArenaAlloc * heap)64*c8dee2aaSAndroid Build Coastguard Worker void SkTSpan::addBounded(SkTSpan* span, SkArenaAlloc* heap) {
65*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* bounded = heap->make<SkTSpanBounded>();
66*c8dee2aaSAndroid Build Coastguard Worker bounded->fBounded = span;
67*c8dee2aaSAndroid Build Coastguard Worker bounded->fNext = fBounded;
68*c8dee2aaSAndroid Build Coastguard Worker fBounded = bounded;
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker
addFollowing(SkTSpan * prior)71*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSect::addFollowing(
72*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* prior) {
73*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* result = this->addOne();
74*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(result->debugSetGlobalState(this->globalState()));
75*c8dee2aaSAndroid Build Coastguard Worker result->fStartT = prior ? prior->fEndT : 0;
76*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* next = prior ? prior->fNext : fHead;
77*c8dee2aaSAndroid Build Coastguard Worker result->fEndT = next ? next->fStartT : 1;
78*c8dee2aaSAndroid Build Coastguard Worker result->fPrev = prior;
79*c8dee2aaSAndroid Build Coastguard Worker result->fNext = next;
80*c8dee2aaSAndroid Build Coastguard Worker if (prior) {
81*c8dee2aaSAndroid Build Coastguard Worker prior->fNext = result;
82*c8dee2aaSAndroid Build Coastguard Worker } else {
83*c8dee2aaSAndroid Build Coastguard Worker fHead = result;
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker if (next) {
86*c8dee2aaSAndroid Build Coastguard Worker next->fPrev = result;
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker result->resetBounds(fCurve);
89*c8dee2aaSAndroid Build Coastguard Worker // world may not be consistent to call validate here
90*c8dee2aaSAndroid Build Coastguard Worker result->validate();
91*c8dee2aaSAndroid Build Coastguard Worker return result;
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker
addForPerp(SkTSpan * span,double t)94*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::addForPerp(SkTSpan* span, double t) {
95*c8dee2aaSAndroid Build Coastguard Worker if (!span->hasOppT(t)) {
96*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* priorSpan;
97*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* opp = this->spanAtT(t, &priorSpan);
98*c8dee2aaSAndroid Build Coastguard Worker if (!opp) {
99*c8dee2aaSAndroid Build Coastguard Worker opp = this->addFollowing(priorSpan);
100*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_PERP
101*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan ?
102*c8dee2aaSAndroid Build Coastguard Worker priorSpan->debugID() : -1, t, opp->debugID());
103*c8dee2aaSAndroid Build Coastguard Worker #endif
104*c8dee2aaSAndroid Build Coastguard Worker }
105*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_PERP
106*c8dee2aaSAndroid Build Coastguard Worker opp->dump(); SkDebugf("\n");
107*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s addBounded span=%d opp=%d\n", __FUNCTION__, priorSpan ?
108*c8dee2aaSAndroid Build Coastguard Worker priorSpan->debugID() : -1, opp->debugID());
109*c8dee2aaSAndroid Build Coastguard Worker #endif
110*c8dee2aaSAndroid Build Coastguard Worker opp->addBounded(span, &fHeap);
111*c8dee2aaSAndroid Build Coastguard Worker span->addBounded(opp, &fHeap);
112*c8dee2aaSAndroid Build Coastguard Worker }
113*c8dee2aaSAndroid Build Coastguard Worker this->validate();
114*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
115*c8dee2aaSAndroid Build Coastguard Worker span->validatePerpT(t);
116*c8dee2aaSAndroid Build Coastguard Worker #endif
117*c8dee2aaSAndroid Build Coastguard Worker }
118*c8dee2aaSAndroid Build Coastguard Worker
closestBoundedT(const SkDPoint & pt) const119*c8dee2aaSAndroid Build Coastguard Worker double SkTSpan::closestBoundedT(const SkDPoint& pt) const {
120*c8dee2aaSAndroid Build Coastguard Worker double result = -1;
121*c8dee2aaSAndroid Build Coastguard Worker double closest = DBL_MAX;
122*c8dee2aaSAndroid Build Coastguard Worker const SkTSpanBounded* testBounded = fBounded;
123*c8dee2aaSAndroid Build Coastguard Worker while (testBounded) {
124*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* test = testBounded->fBounded;
125*c8dee2aaSAndroid Build Coastguard Worker double startDist = test->pointFirst().distanceSquared(pt);
126*c8dee2aaSAndroid Build Coastguard Worker if (closest > startDist) {
127*c8dee2aaSAndroid Build Coastguard Worker closest = startDist;
128*c8dee2aaSAndroid Build Coastguard Worker result = test->fStartT;
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker double endDist = test->pointLast().distanceSquared(pt);
131*c8dee2aaSAndroid Build Coastguard Worker if (closest > endDist) {
132*c8dee2aaSAndroid Build Coastguard Worker closest = endDist;
133*c8dee2aaSAndroid Build Coastguard Worker result = test->fEndT;
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker testBounded = testBounded->fNext;
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(between(0, result, 1));
138*c8dee2aaSAndroid Build Coastguard Worker return result;
139*c8dee2aaSAndroid Build Coastguard Worker }
140*c8dee2aaSAndroid Build Coastguard Worker
141*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
142*c8dee2aaSAndroid Build Coastguard Worker
debugIsBefore(const SkTSpan * span) const143*c8dee2aaSAndroid Build Coastguard Worker bool SkTSpan::debugIsBefore(const SkTSpan* span) const {
144*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* work = this;
145*c8dee2aaSAndroid Build Coastguard Worker do {
146*c8dee2aaSAndroid Build Coastguard Worker if (span == work) {
147*c8dee2aaSAndroid Build Coastguard Worker return true;
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker } while ((work = work->fNext));
150*c8dee2aaSAndroid Build Coastguard Worker return false;
151*c8dee2aaSAndroid Build Coastguard Worker }
152*c8dee2aaSAndroid Build Coastguard Worker #endif
153*c8dee2aaSAndroid Build Coastguard Worker
contains(double t) const154*c8dee2aaSAndroid Build Coastguard Worker bool SkTSpan::contains(double t) const {
155*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* work = this;
156*c8dee2aaSAndroid Build Coastguard Worker do {
157*c8dee2aaSAndroid Build Coastguard Worker if (between(work->fStartT, t, work->fEndT)) {
158*c8dee2aaSAndroid Build Coastguard Worker return true;
159*c8dee2aaSAndroid Build Coastguard Worker }
160*c8dee2aaSAndroid Build Coastguard Worker } while ((work = work->fNext));
161*c8dee2aaSAndroid Build Coastguard Worker return false;
162*c8dee2aaSAndroid Build Coastguard Worker }
163*c8dee2aaSAndroid Build Coastguard Worker
debugOpp() const164*c8dee2aaSAndroid Build Coastguard Worker const SkTSect* SkTSpan::debugOpp() const {
165*c8dee2aaSAndroid Build Coastguard Worker return SkDEBUGRELEASE(fDebugSect->debugOpp(), nullptr);
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker
findOppSpan(const SkTSpan * opp) const168*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSpan::findOppSpan(
169*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* opp) const {
170*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* bounded = fBounded;
171*c8dee2aaSAndroid Build Coastguard Worker while (bounded) {
172*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = bounded->fBounded;
173*c8dee2aaSAndroid Build Coastguard Worker if (opp == test) {
174*c8dee2aaSAndroid Build Coastguard Worker return test;
175*c8dee2aaSAndroid Build Coastguard Worker }
176*c8dee2aaSAndroid Build Coastguard Worker bounded = bounded->fNext;
177*c8dee2aaSAndroid Build Coastguard Worker }
178*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
179*c8dee2aaSAndroid Build Coastguard Worker }
180*c8dee2aaSAndroid Build Coastguard Worker
181*c8dee2aaSAndroid Build Coastguard Worker // returns 0 if no hull intersection
182*c8dee2aaSAndroid Build Coastguard Worker // 1 if hulls intersect
183*c8dee2aaSAndroid Build Coastguard Worker // 2 if hulls only share a common endpoint
184*c8dee2aaSAndroid Build Coastguard Worker // -1 if linear and further checking is required
185*c8dee2aaSAndroid Build Coastguard Worker
hullCheck(const SkTSpan * opp,bool * start,bool * oppStart)186*c8dee2aaSAndroid Build Coastguard Worker int SkTSpan::hullCheck(const SkTSpan* opp,
187*c8dee2aaSAndroid Build Coastguard Worker bool* start, bool* oppStart) {
188*c8dee2aaSAndroid Build Coastguard Worker if (fIsLinear) {
189*c8dee2aaSAndroid Build Coastguard Worker return -1;
190*c8dee2aaSAndroid Build Coastguard Worker }
191*c8dee2aaSAndroid Build Coastguard Worker bool ptsInCommon;
192*c8dee2aaSAndroid Build Coastguard Worker if (onlyEndPointsInCommon(opp, start, oppStart, &ptsInCommon)) {
193*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(ptsInCommon);
194*c8dee2aaSAndroid Build Coastguard Worker return 2;
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker bool linear;
197*c8dee2aaSAndroid Build Coastguard Worker if (fPart->hullIntersects(*opp->fPart, &linear)) {
198*c8dee2aaSAndroid Build Coastguard Worker if (!linear) { // check set true if linear
199*c8dee2aaSAndroid Build Coastguard Worker return 1;
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker fIsLinear = true;
202*c8dee2aaSAndroid Build Coastguard Worker fIsLine = fPart->controlsInside();
203*c8dee2aaSAndroid Build Coastguard Worker return ptsInCommon ? 1 : -1;
204*c8dee2aaSAndroid Build Coastguard Worker }
205*c8dee2aaSAndroid Build Coastguard Worker // hull is not linear; check set true if intersected at the end points
206*c8dee2aaSAndroid Build Coastguard Worker return ((int) ptsInCommon) << 1; // 0 or 2
207*c8dee2aaSAndroid Build Coastguard Worker }
208*c8dee2aaSAndroid Build Coastguard Worker
209*c8dee2aaSAndroid Build Coastguard Worker // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear,
210*c8dee2aaSAndroid Build Coastguard Worker // use line intersection to guess a better split than 0.5
211*c8dee2aaSAndroid Build Coastguard Worker // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all future splits are linear
212*c8dee2aaSAndroid Build Coastguard Worker
hullsIntersect(SkTSpan * opp,bool * start,bool * oppStart)213*c8dee2aaSAndroid Build Coastguard Worker int SkTSpan::hullsIntersect(SkTSpan* opp,
214*c8dee2aaSAndroid Build Coastguard Worker bool* start, bool* oppStart) {
215*c8dee2aaSAndroid Build Coastguard Worker if (!fBounds.intersects(opp->fBounds)) {
216*c8dee2aaSAndroid Build Coastguard Worker return 0;
217*c8dee2aaSAndroid Build Coastguard Worker }
218*c8dee2aaSAndroid Build Coastguard Worker int hullSect = this->hullCheck(opp, start, oppStart);
219*c8dee2aaSAndroid Build Coastguard Worker if (hullSect >= 0) {
220*c8dee2aaSAndroid Build Coastguard Worker return hullSect;
221*c8dee2aaSAndroid Build Coastguard Worker }
222*c8dee2aaSAndroid Build Coastguard Worker hullSect = opp->hullCheck(this, oppStart, start);
223*c8dee2aaSAndroid Build Coastguard Worker if (hullSect >= 0) {
224*c8dee2aaSAndroid Build Coastguard Worker return hullSect;
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker return -1;
227*c8dee2aaSAndroid Build Coastguard Worker }
228*c8dee2aaSAndroid Build Coastguard Worker
init(const SkTCurve & c)229*c8dee2aaSAndroid Build Coastguard Worker void SkTSpan::init(const SkTCurve& c) {
230*c8dee2aaSAndroid Build Coastguard Worker fPrev = fNext = nullptr;
231*c8dee2aaSAndroid Build Coastguard Worker fStartT = 0;
232*c8dee2aaSAndroid Build Coastguard Worker fEndT = 1;
233*c8dee2aaSAndroid Build Coastguard Worker fBounded = nullptr;
234*c8dee2aaSAndroid Build Coastguard Worker resetBounds(c);
235*c8dee2aaSAndroid Build Coastguard Worker }
236*c8dee2aaSAndroid Build Coastguard Worker
initBounds(const SkTCurve & c)237*c8dee2aaSAndroid Build Coastguard Worker bool SkTSpan::initBounds(const SkTCurve& c) {
238*c8dee2aaSAndroid Build Coastguard Worker if (SkIsNaN(fStartT) || SkIsNaN(fEndT)) {
239*c8dee2aaSAndroid Build Coastguard Worker return false;
240*c8dee2aaSAndroid Build Coastguard Worker }
241*c8dee2aaSAndroid Build Coastguard Worker c.subDivide(fStartT, fEndT, fPart);
242*c8dee2aaSAndroid Build Coastguard Worker fBounds.setBounds(*fPart);
243*c8dee2aaSAndroid Build Coastguard Worker fCoinStart.init();
244*c8dee2aaSAndroid Build Coastguard Worker fCoinEnd.init();
245*c8dee2aaSAndroid Build Coastguard Worker fBoundsMax = std::max(fBounds.width(), fBounds.height());
246*c8dee2aaSAndroid Build Coastguard Worker fCollapsed = fPart->collapsed();
247*c8dee2aaSAndroid Build Coastguard Worker fHasPerp = false;
248*c8dee2aaSAndroid Build Coastguard Worker fDeleted = false;
249*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
250*c8dee2aaSAndroid Build Coastguard Worker if (fCollapsed) {
251*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s", ""); // for convenient breakpoints
252*c8dee2aaSAndroid Build Coastguard Worker }
253*c8dee2aaSAndroid Build Coastguard Worker #endif
254*c8dee2aaSAndroid Build Coastguard Worker return fBounds.valid();
255*c8dee2aaSAndroid Build Coastguard Worker }
256*c8dee2aaSAndroid Build Coastguard Worker
linearsIntersect(SkTSpan * span)257*c8dee2aaSAndroid Build Coastguard Worker bool SkTSpan::linearsIntersect(SkTSpan* span) {
258*c8dee2aaSAndroid Build Coastguard Worker int result = this->linearIntersects(*span->fPart);
259*c8dee2aaSAndroid Build Coastguard Worker if (result <= 1) {
260*c8dee2aaSAndroid Build Coastguard Worker return SkToBool(result);
261*c8dee2aaSAndroid Build Coastguard Worker }
262*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(span->fIsLinear);
263*c8dee2aaSAndroid Build Coastguard Worker result = span->linearIntersects(*fPart);
264*c8dee2aaSAndroid Build Coastguard Worker // SkASSERT(result <= 1);
265*c8dee2aaSAndroid Build Coastguard Worker return SkToBool(result);
266*c8dee2aaSAndroid Build Coastguard Worker }
267*c8dee2aaSAndroid Build Coastguard Worker
linearT(const SkDPoint & pt) const268*c8dee2aaSAndroid Build Coastguard Worker double SkTSpan::linearT(const SkDPoint& pt) const {
269*c8dee2aaSAndroid Build Coastguard Worker SkDVector len = this->pointLast() - this->pointFirst();
270*c8dee2aaSAndroid Build Coastguard Worker return fabs(len.fX) > fabs(len.fY)
271*c8dee2aaSAndroid Build Coastguard Worker ? (pt.fX - this->pointFirst().fX) / len.fX
272*c8dee2aaSAndroid Build Coastguard Worker : (pt.fY - this->pointFirst().fY) / len.fY;
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker
linearIntersects(const SkTCurve & q2) const275*c8dee2aaSAndroid Build Coastguard Worker int SkTSpan::linearIntersects(const SkTCurve& q2) const {
276*c8dee2aaSAndroid Build Coastguard Worker // looks like q1 is near-linear
277*c8dee2aaSAndroid Build Coastguard Worker int start = 0, end = fPart->pointLast(); // the outside points are usually the extremes
278*c8dee2aaSAndroid Build Coastguard Worker if (!fPart->controlsInside()) {
279*c8dee2aaSAndroid Build Coastguard Worker double dist = 0; // if there's any question, compute distance to find best outsiders
280*c8dee2aaSAndroid Build Coastguard Worker for (int outer = 0; outer < this->pointCount() - 1; ++outer) {
281*c8dee2aaSAndroid Build Coastguard Worker for (int inner = outer + 1; inner < this->pointCount(); ++inner) {
282*c8dee2aaSAndroid Build Coastguard Worker double test = ((*fPart)[outer] - (*fPart)[inner]).lengthSquared();
283*c8dee2aaSAndroid Build Coastguard Worker if (dist > test) {
284*c8dee2aaSAndroid Build Coastguard Worker continue;
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker dist = test;
287*c8dee2aaSAndroid Build Coastguard Worker start = outer;
288*c8dee2aaSAndroid Build Coastguard Worker end = inner;
289*c8dee2aaSAndroid Build Coastguard Worker }
290*c8dee2aaSAndroid Build Coastguard Worker }
291*c8dee2aaSAndroid Build Coastguard Worker }
292*c8dee2aaSAndroid Build Coastguard Worker // see if q2 is on one side of the line formed by the extreme points
293*c8dee2aaSAndroid Build Coastguard Worker double origX = (*fPart)[start].fX;
294*c8dee2aaSAndroid Build Coastguard Worker double origY = (*fPart)[start].fY;
295*c8dee2aaSAndroid Build Coastguard Worker double adj = (*fPart)[end].fX - origX;
296*c8dee2aaSAndroid Build Coastguard Worker double opp = (*fPart)[end].fY - origY;
297*c8dee2aaSAndroid Build Coastguard Worker double maxPart = std::max(fabs(adj), fabs(opp));
298*c8dee2aaSAndroid Build Coastguard Worker double sign = 0; // initialization to shut up warning in release build
299*c8dee2aaSAndroid Build Coastguard Worker for (int n = 0; n < q2.pointCount(); ++n) {
300*c8dee2aaSAndroid Build Coastguard Worker double dx = q2[n].fY - origY;
301*c8dee2aaSAndroid Build Coastguard Worker double dy = q2[n].fX - origX;
302*c8dee2aaSAndroid Build Coastguard Worker double maxVal = std::max(maxPart, std::max(fabs(dx), fabs(dy)));
303*c8dee2aaSAndroid Build Coastguard Worker double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp;
304*c8dee2aaSAndroid Build Coastguard Worker if (precisely_zero_when_compared_to(test, maxVal)) {
305*c8dee2aaSAndroid Build Coastguard Worker return 1;
306*c8dee2aaSAndroid Build Coastguard Worker }
307*c8dee2aaSAndroid Build Coastguard Worker if (approximately_zero_when_compared_to(test, maxVal)) {
308*c8dee2aaSAndroid Build Coastguard Worker return 3;
309*c8dee2aaSAndroid Build Coastguard Worker }
310*c8dee2aaSAndroid Build Coastguard Worker if (n == 0) {
311*c8dee2aaSAndroid Build Coastguard Worker sign = test;
312*c8dee2aaSAndroid Build Coastguard Worker continue;
313*c8dee2aaSAndroid Build Coastguard Worker }
314*c8dee2aaSAndroid Build Coastguard Worker if (test * sign < 0) {
315*c8dee2aaSAndroid Build Coastguard Worker return 1;
316*c8dee2aaSAndroid Build Coastguard Worker }
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker return 0;
319*c8dee2aaSAndroid Build Coastguard Worker }
320*c8dee2aaSAndroid Build Coastguard Worker
onlyEndPointsInCommon(const SkTSpan * opp,bool * start,bool * oppStart,bool * ptsInCommon)321*c8dee2aaSAndroid Build Coastguard Worker bool SkTSpan::onlyEndPointsInCommon(const SkTSpan* opp,
322*c8dee2aaSAndroid Build Coastguard Worker bool* start, bool* oppStart, bool* ptsInCommon) {
323*c8dee2aaSAndroid Build Coastguard Worker if (opp->pointFirst() == this->pointFirst()) {
324*c8dee2aaSAndroid Build Coastguard Worker *start = *oppStart = true;
325*c8dee2aaSAndroid Build Coastguard Worker } else if (opp->pointFirst() == this->pointLast()) {
326*c8dee2aaSAndroid Build Coastguard Worker *start = false;
327*c8dee2aaSAndroid Build Coastguard Worker *oppStart = true;
328*c8dee2aaSAndroid Build Coastguard Worker } else if (opp->pointLast() == this->pointFirst()) {
329*c8dee2aaSAndroid Build Coastguard Worker *start = true;
330*c8dee2aaSAndroid Build Coastguard Worker *oppStart = false;
331*c8dee2aaSAndroid Build Coastguard Worker } else if (opp->pointLast() == this->pointLast()) {
332*c8dee2aaSAndroid Build Coastguard Worker *start = *oppStart = false;
333*c8dee2aaSAndroid Build Coastguard Worker } else {
334*c8dee2aaSAndroid Build Coastguard Worker *ptsInCommon = false;
335*c8dee2aaSAndroid Build Coastguard Worker return false;
336*c8dee2aaSAndroid Build Coastguard Worker }
337*c8dee2aaSAndroid Build Coastguard Worker *ptsInCommon = true;
338*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint* otherPts[4], * oppOtherPts[4];
339*c8dee2aaSAndroid Build Coastguard Worker // const SkDPoint* otherPts[this->pointCount() - 1], * oppOtherPts[opp->pointCount() - 1];
340*c8dee2aaSAndroid Build Coastguard Worker int baseIndex = *start ? 0 : fPart->pointLast();
341*c8dee2aaSAndroid Build Coastguard Worker fPart->otherPts(baseIndex, otherPts);
342*c8dee2aaSAndroid Build Coastguard Worker opp->fPart->otherPts(*oppStart ? 0 : opp->fPart->pointLast(), oppOtherPts);
343*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint& base = (*fPart)[baseIndex];
344*c8dee2aaSAndroid Build Coastguard Worker for (int o1 = 0; o1 < this->pointCount() - 1; ++o1) {
345*c8dee2aaSAndroid Build Coastguard Worker SkDVector v1 = *otherPts[o1] - base;
346*c8dee2aaSAndroid Build Coastguard Worker for (int o2 = 0; o2 < opp->pointCount() - 1; ++o2) {
347*c8dee2aaSAndroid Build Coastguard Worker SkDVector v2 = *oppOtherPts[o2] - base;
348*c8dee2aaSAndroid Build Coastguard Worker if (v2.dot(v1) >= 0) {
349*c8dee2aaSAndroid Build Coastguard Worker return false;
350*c8dee2aaSAndroid Build Coastguard Worker }
351*c8dee2aaSAndroid Build Coastguard Worker }
352*c8dee2aaSAndroid Build Coastguard Worker }
353*c8dee2aaSAndroid Build Coastguard Worker return true;
354*c8dee2aaSAndroid Build Coastguard Worker }
355*c8dee2aaSAndroid Build Coastguard Worker
oppT(double t) const356*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSpan::oppT(double t) const {
357*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* bounded = fBounded;
358*c8dee2aaSAndroid Build Coastguard Worker while (bounded) {
359*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = bounded->fBounded;
360*c8dee2aaSAndroid Build Coastguard Worker if (between(test->fStartT, t, test->fEndT)) {
361*c8dee2aaSAndroid Build Coastguard Worker return test;
362*c8dee2aaSAndroid Build Coastguard Worker }
363*c8dee2aaSAndroid Build Coastguard Worker bounded = bounded->fNext;
364*c8dee2aaSAndroid Build Coastguard Worker }
365*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
366*c8dee2aaSAndroid Build Coastguard Worker }
367*c8dee2aaSAndroid Build Coastguard Worker
removeAllBounded()368*c8dee2aaSAndroid Build Coastguard Worker bool SkTSpan::removeAllBounded() {
369*c8dee2aaSAndroid Build Coastguard Worker bool deleteSpan = false;
370*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* bounded = fBounded;
371*c8dee2aaSAndroid Build Coastguard Worker while (bounded) {
372*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* opp = bounded->fBounded;
373*c8dee2aaSAndroid Build Coastguard Worker deleteSpan |= opp->removeBounded(this);
374*c8dee2aaSAndroid Build Coastguard Worker bounded = bounded->fNext;
375*c8dee2aaSAndroid Build Coastguard Worker }
376*c8dee2aaSAndroid Build Coastguard Worker return deleteSpan;
377*c8dee2aaSAndroid Build Coastguard Worker }
378*c8dee2aaSAndroid Build Coastguard Worker
removeBounded(const SkTSpan * opp)379*c8dee2aaSAndroid Build Coastguard Worker bool SkTSpan::removeBounded(const SkTSpan* opp) {
380*c8dee2aaSAndroid Build Coastguard Worker if (fHasPerp) {
381*c8dee2aaSAndroid Build Coastguard Worker bool foundStart = false;
382*c8dee2aaSAndroid Build Coastguard Worker bool foundEnd = false;
383*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* bounded = fBounded;
384*c8dee2aaSAndroid Build Coastguard Worker while (bounded) {
385*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = bounded->fBounded;
386*c8dee2aaSAndroid Build Coastguard Worker if (opp != test) {
387*c8dee2aaSAndroid Build Coastguard Worker foundStart |= between(test->fStartT, fCoinStart.perpT(), test->fEndT);
388*c8dee2aaSAndroid Build Coastguard Worker foundEnd |= between(test->fStartT, fCoinEnd.perpT(), test->fEndT);
389*c8dee2aaSAndroid Build Coastguard Worker }
390*c8dee2aaSAndroid Build Coastguard Worker bounded = bounded->fNext;
391*c8dee2aaSAndroid Build Coastguard Worker }
392*c8dee2aaSAndroid Build Coastguard Worker if (!foundStart || !foundEnd) {
393*c8dee2aaSAndroid Build Coastguard Worker fHasPerp = false;
394*c8dee2aaSAndroid Build Coastguard Worker fCoinStart.init();
395*c8dee2aaSAndroid Build Coastguard Worker fCoinEnd.init();
396*c8dee2aaSAndroid Build Coastguard Worker }
397*c8dee2aaSAndroid Build Coastguard Worker }
398*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* bounded = fBounded;
399*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* prev = nullptr;
400*c8dee2aaSAndroid Build Coastguard Worker while (bounded) {
401*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* boundedNext = bounded->fNext;
402*c8dee2aaSAndroid Build Coastguard Worker if (opp == bounded->fBounded) {
403*c8dee2aaSAndroid Build Coastguard Worker if (prev) {
404*c8dee2aaSAndroid Build Coastguard Worker prev->fNext = boundedNext;
405*c8dee2aaSAndroid Build Coastguard Worker return false;
406*c8dee2aaSAndroid Build Coastguard Worker } else {
407*c8dee2aaSAndroid Build Coastguard Worker fBounded = boundedNext;
408*c8dee2aaSAndroid Build Coastguard Worker return fBounded == nullptr;
409*c8dee2aaSAndroid Build Coastguard Worker }
410*c8dee2aaSAndroid Build Coastguard Worker }
411*c8dee2aaSAndroid Build Coastguard Worker prev = bounded;
412*c8dee2aaSAndroid Build Coastguard Worker bounded = boundedNext;
413*c8dee2aaSAndroid Build Coastguard Worker }
414*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(0);
415*c8dee2aaSAndroid Build Coastguard Worker return false;
416*c8dee2aaSAndroid Build Coastguard Worker }
417*c8dee2aaSAndroid Build Coastguard Worker
splitAt(SkTSpan * work,double t,SkArenaAlloc * heap)418*c8dee2aaSAndroid Build Coastguard Worker bool SkTSpan::splitAt(SkTSpan* work, double t, SkArenaAlloc* heap) {
419*c8dee2aaSAndroid Build Coastguard Worker fStartT = t;
420*c8dee2aaSAndroid Build Coastguard Worker fEndT = work->fEndT;
421*c8dee2aaSAndroid Build Coastguard Worker if (fStartT == fEndT) {
422*c8dee2aaSAndroid Build Coastguard Worker fCollapsed = true;
423*c8dee2aaSAndroid Build Coastguard Worker return false;
424*c8dee2aaSAndroid Build Coastguard Worker }
425*c8dee2aaSAndroid Build Coastguard Worker work->fEndT = t;
426*c8dee2aaSAndroid Build Coastguard Worker if (work->fStartT == work->fEndT) {
427*c8dee2aaSAndroid Build Coastguard Worker work->fCollapsed = true;
428*c8dee2aaSAndroid Build Coastguard Worker return false;
429*c8dee2aaSAndroid Build Coastguard Worker }
430*c8dee2aaSAndroid Build Coastguard Worker fPrev = work;
431*c8dee2aaSAndroid Build Coastguard Worker fNext = work->fNext;
432*c8dee2aaSAndroid Build Coastguard Worker fIsLinear = work->fIsLinear;
433*c8dee2aaSAndroid Build Coastguard Worker fIsLine = work->fIsLine;
434*c8dee2aaSAndroid Build Coastguard Worker
435*c8dee2aaSAndroid Build Coastguard Worker work->fNext = this;
436*c8dee2aaSAndroid Build Coastguard Worker if (fNext) {
437*c8dee2aaSAndroid Build Coastguard Worker fNext->fPrev = this;
438*c8dee2aaSAndroid Build Coastguard Worker }
439*c8dee2aaSAndroid Build Coastguard Worker this->validate();
440*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* bounded = work->fBounded;
441*c8dee2aaSAndroid Build Coastguard Worker fBounded = nullptr;
442*c8dee2aaSAndroid Build Coastguard Worker while (bounded) {
443*c8dee2aaSAndroid Build Coastguard Worker this->addBounded(bounded->fBounded, heap);
444*c8dee2aaSAndroid Build Coastguard Worker bounded = bounded->fNext;
445*c8dee2aaSAndroid Build Coastguard Worker }
446*c8dee2aaSAndroid Build Coastguard Worker bounded = fBounded;
447*c8dee2aaSAndroid Build Coastguard Worker while (bounded) {
448*c8dee2aaSAndroid Build Coastguard Worker bounded->fBounded->addBounded(this, heap);
449*c8dee2aaSAndroid Build Coastguard Worker bounded = bounded->fNext;
450*c8dee2aaSAndroid Build Coastguard Worker }
451*c8dee2aaSAndroid Build Coastguard Worker return true;
452*c8dee2aaSAndroid Build Coastguard Worker }
453*c8dee2aaSAndroid Build Coastguard Worker
validate() const454*c8dee2aaSAndroid Build Coastguard Worker void SkTSpan::validate() const {
455*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_VALIDATE
456*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this != fPrev);
457*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this != fNext);
458*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fNext == nullptr || fNext != fPrev);
459*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fNext == nullptr || this == fNext->fPrev);
460*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fPrev == nullptr || this == fPrev->fNext);
461*c8dee2aaSAndroid Build Coastguard Worker this->validateBounded();
462*c8dee2aaSAndroid Build Coastguard Worker #endif
463*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
464*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBounds.width() || fBounds.height() || fCollapsed);
465*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBoundsMax == std::max(fBounds.width(), fBounds.height()) || fCollapsed == 0xFF);
466*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 <= fStartT);
467*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fEndT <= 1);
468*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fStartT <= fEndT);
469*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBounded || fCollapsed == 0xFF);
470*c8dee2aaSAndroid Build Coastguard Worker if (fHasPerp) {
471*c8dee2aaSAndroid Build Coastguard Worker if (fCoinStart.isMatch()) {
472*c8dee2aaSAndroid Build Coastguard Worker validatePerpT(fCoinStart.perpT());
473*c8dee2aaSAndroid Build Coastguard Worker validatePerpPt(fCoinStart.perpT(), fCoinStart.perpPt());
474*c8dee2aaSAndroid Build Coastguard Worker }
475*c8dee2aaSAndroid Build Coastguard Worker if (fCoinEnd.isMatch()) {
476*c8dee2aaSAndroid Build Coastguard Worker validatePerpT(fCoinEnd.perpT());
477*c8dee2aaSAndroid Build Coastguard Worker validatePerpPt(fCoinEnd.perpT(), fCoinEnd.perpPt());
478*c8dee2aaSAndroid Build Coastguard Worker }
479*c8dee2aaSAndroid Build Coastguard Worker }
480*c8dee2aaSAndroid Build Coastguard Worker #endif
481*c8dee2aaSAndroid Build Coastguard Worker }
482*c8dee2aaSAndroid Build Coastguard Worker
validateBounded() const483*c8dee2aaSAndroid Build Coastguard Worker void SkTSpan::validateBounded() const {
484*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_VALIDATE
485*c8dee2aaSAndroid Build Coastguard Worker const SkTSpanBounded* testBounded = fBounded;
486*c8dee2aaSAndroid Build Coastguard Worker while (testBounded) {
487*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(const SkTSpan* overlap = testBounded->fBounded);
488*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!overlap->fDeleted);
489*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
490*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(((this->debugID() ^ overlap->debugID()) & 1) == 1);
491*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(overlap->findOppSpan(this));
492*c8dee2aaSAndroid Build Coastguard Worker #endif
493*c8dee2aaSAndroid Build Coastguard Worker testBounded = testBounded->fNext;
494*c8dee2aaSAndroid Build Coastguard Worker }
495*c8dee2aaSAndroid Build Coastguard Worker #endif
496*c8dee2aaSAndroid Build Coastguard Worker }
497*c8dee2aaSAndroid Build Coastguard Worker
validatePerpT(double oppT) const498*c8dee2aaSAndroid Build Coastguard Worker void SkTSpan::validatePerpT(double oppT) const {
499*c8dee2aaSAndroid Build Coastguard Worker const SkTSpanBounded* testBounded = fBounded;
500*c8dee2aaSAndroid Build Coastguard Worker while (testBounded) {
501*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* overlap = testBounded->fBounded;
502*c8dee2aaSAndroid Build Coastguard Worker if (precisely_between(overlap->fStartT, oppT, overlap->fEndT)) {
503*c8dee2aaSAndroid Build Coastguard Worker return;
504*c8dee2aaSAndroid Build Coastguard Worker }
505*c8dee2aaSAndroid Build Coastguard Worker testBounded = testBounded->fNext;
506*c8dee2aaSAndroid Build Coastguard Worker }
507*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0);
508*c8dee2aaSAndroid Build Coastguard Worker }
509*c8dee2aaSAndroid Build Coastguard Worker
validatePerpPt(double t,const SkDPoint & pt) const510*c8dee2aaSAndroid Build Coastguard Worker void SkTSpan::validatePerpPt(double t, const SkDPoint& pt) const {
511*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fDebugSect->fOppSect->fCurve.ptAtT(t) == pt);
512*c8dee2aaSAndroid Build Coastguard Worker }
513*c8dee2aaSAndroid Build Coastguard Worker
SkTSect(const SkTCurve & c SkDEBUGPARAMS (SkOpGlobalState * debugGlobalState)PATH_OPS_DEBUG_T_SECT_PARAMS (int id))514*c8dee2aaSAndroid Build Coastguard Worker SkTSect::SkTSect(const SkTCurve& c
515*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGPARAMS(SkOpGlobalState* debugGlobalState)
516*c8dee2aaSAndroid Build Coastguard Worker PATH_OPS_DEBUG_T_SECT_PARAMS(int id))
517*c8dee2aaSAndroid Build Coastguard Worker : fCurve(c)
518*c8dee2aaSAndroid Build Coastguard Worker , fHeap(sizeof(SkTSpan) * 4)
519*c8dee2aaSAndroid Build Coastguard Worker , fCoincident(nullptr)
520*c8dee2aaSAndroid Build Coastguard Worker , fDeleted(nullptr)
521*c8dee2aaSAndroid Build Coastguard Worker , fActiveCount(0)
522*c8dee2aaSAndroid Build Coastguard Worker , fHung(false)
523*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGPARAMS(fDebugGlobalState(debugGlobalState))
524*c8dee2aaSAndroid Build Coastguard Worker PATH_OPS_DEBUG_T_SECT_PARAMS(fID(id))
525*c8dee2aaSAndroid Build Coastguard Worker PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugCount(0))
526*c8dee2aaSAndroid Build Coastguard Worker PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugAllocatedCount(0))
527*c8dee2aaSAndroid Build Coastguard Worker {
528*c8dee2aaSAndroid Build Coastguard Worker this->resetRemovedEnds();
529*c8dee2aaSAndroid Build Coastguard Worker fHead = this->addOne();
530*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fHead->debugSetGlobalState(debugGlobalState));
531*c8dee2aaSAndroid Build Coastguard Worker fHead->init(c);
532*c8dee2aaSAndroid Build Coastguard Worker }
533*c8dee2aaSAndroid Build Coastguard Worker
addOne()534*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSect::addOne() {
535*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* result;
536*c8dee2aaSAndroid Build Coastguard Worker if (fDeleted) {
537*c8dee2aaSAndroid Build Coastguard Worker result = fDeleted;
538*c8dee2aaSAndroid Build Coastguard Worker fDeleted = result->fNext;
539*c8dee2aaSAndroid Build Coastguard Worker } else {
540*c8dee2aaSAndroid Build Coastguard Worker result = fHeap.make<SkTSpan>(fCurve, fHeap);
541*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
542*c8dee2aaSAndroid Build Coastguard Worker ++fDebugAllocatedCount;
543*c8dee2aaSAndroid Build Coastguard Worker #endif
544*c8dee2aaSAndroid Build Coastguard Worker }
545*c8dee2aaSAndroid Build Coastguard Worker result->reset();
546*c8dee2aaSAndroid Build Coastguard Worker result->fHasPerp = false;
547*c8dee2aaSAndroid Build Coastguard Worker result->fDeleted = false;
548*c8dee2aaSAndroid Build Coastguard Worker ++fActiveCount;
549*c8dee2aaSAndroid Build Coastguard Worker PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID);
550*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(result->fDebugSect = this);
551*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
552*c8dee2aaSAndroid Build Coastguard Worker result->debugInit(fCurve, fHeap);
553*c8dee2aaSAndroid Build Coastguard Worker result->fCoinStart.debugInit();
554*c8dee2aaSAndroid Build Coastguard Worker result->fCoinEnd.debugInit();
555*c8dee2aaSAndroid Build Coastguard Worker result->fPrev = result->fNext = nullptr;
556*c8dee2aaSAndroid Build Coastguard Worker result->fBounds.debugInit();
557*c8dee2aaSAndroid Build Coastguard Worker result->fStartT = result->fEndT = result->fBoundsMax = SK_ScalarNaN;
558*c8dee2aaSAndroid Build Coastguard Worker result->fCollapsed = result->fIsLinear = result->fIsLine = 0xFF;
559*c8dee2aaSAndroid Build Coastguard Worker #endif
560*c8dee2aaSAndroid Build Coastguard Worker return result;
561*c8dee2aaSAndroid Build Coastguard Worker }
562*c8dee2aaSAndroid Build Coastguard Worker
binarySearchCoin(SkTSect * sect2,double tStart,double tStep,double * resultT,double * oppT,SkTSpan ** oppFirst)563*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::binarySearchCoin(SkTSect* sect2, double tStart,
564*c8dee2aaSAndroid Build Coastguard Worker double tStep, double* resultT, double* oppT, SkTSpan** oppFirst) {
565*c8dee2aaSAndroid Build Coastguard Worker SkTSpan work(fCurve, fHeap);
566*c8dee2aaSAndroid Build Coastguard Worker double result = work.fStartT = work.fEndT = tStart;
567*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(work.fDebugSect = this);
568*c8dee2aaSAndroid Build Coastguard Worker SkDPoint last = fCurve.ptAtT(tStart);
569*c8dee2aaSAndroid Build Coastguard Worker SkDPoint oppPt;
570*c8dee2aaSAndroid Build Coastguard Worker bool flip = false;
571*c8dee2aaSAndroid Build Coastguard Worker bool contained = false;
572*c8dee2aaSAndroid Build Coastguard Worker bool down = tStep < 0;
573*c8dee2aaSAndroid Build Coastguard Worker const SkTCurve& opp = sect2->fCurve;
574*c8dee2aaSAndroid Build Coastguard Worker do {
575*c8dee2aaSAndroid Build Coastguard Worker tStep *= 0.5;
576*c8dee2aaSAndroid Build Coastguard Worker work.fStartT += tStep;
577*c8dee2aaSAndroid Build Coastguard Worker if (flip) {
578*c8dee2aaSAndroid Build Coastguard Worker tStep = -tStep;
579*c8dee2aaSAndroid Build Coastguard Worker flip = false;
580*c8dee2aaSAndroid Build Coastguard Worker }
581*c8dee2aaSAndroid Build Coastguard Worker work.initBounds(fCurve);
582*c8dee2aaSAndroid Build Coastguard Worker if (work.fCollapsed) {
583*c8dee2aaSAndroid Build Coastguard Worker return false;
584*c8dee2aaSAndroid Build Coastguard Worker }
585*c8dee2aaSAndroid Build Coastguard Worker if (last.approximatelyEqual(work.pointFirst())) {
586*c8dee2aaSAndroid Build Coastguard Worker break;
587*c8dee2aaSAndroid Build Coastguard Worker }
588*c8dee2aaSAndroid Build Coastguard Worker last = work.pointFirst();
589*c8dee2aaSAndroid Build Coastguard Worker work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp);
590*c8dee2aaSAndroid Build Coastguard Worker if (work.fCoinStart.isMatch()) {
591*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
592*c8dee2aaSAndroid Build Coastguard Worker work.validatePerpPt(work.fCoinStart.perpT(), work.fCoinStart.perpPt());
593*c8dee2aaSAndroid Build Coastguard Worker #endif
594*c8dee2aaSAndroid Build Coastguard Worker double oppTTest = work.fCoinStart.perpT();
595*c8dee2aaSAndroid Build Coastguard Worker if (sect2->fHead->contains(oppTTest)) {
596*c8dee2aaSAndroid Build Coastguard Worker *oppT = oppTTest;
597*c8dee2aaSAndroid Build Coastguard Worker oppPt = work.fCoinStart.perpPt();
598*c8dee2aaSAndroid Build Coastguard Worker contained = true;
599*c8dee2aaSAndroid Build Coastguard Worker if (down ? result <= work.fStartT : result >= work.fStartT) {
600*c8dee2aaSAndroid Build Coastguard Worker *oppFirst = nullptr; // signal caller to fail
601*c8dee2aaSAndroid Build Coastguard Worker return false;
602*c8dee2aaSAndroid Build Coastguard Worker }
603*c8dee2aaSAndroid Build Coastguard Worker result = work.fStartT;
604*c8dee2aaSAndroid Build Coastguard Worker continue;
605*c8dee2aaSAndroid Build Coastguard Worker }
606*c8dee2aaSAndroid Build Coastguard Worker }
607*c8dee2aaSAndroid Build Coastguard Worker tStep = -tStep;
608*c8dee2aaSAndroid Build Coastguard Worker flip = true;
609*c8dee2aaSAndroid Build Coastguard Worker } while (true);
610*c8dee2aaSAndroid Build Coastguard Worker if (!contained) {
611*c8dee2aaSAndroid Build Coastguard Worker return false;
612*c8dee2aaSAndroid Build Coastguard Worker }
613*c8dee2aaSAndroid Build Coastguard Worker if (last.approximatelyEqual(fCurve[0])) {
614*c8dee2aaSAndroid Build Coastguard Worker result = 0;
615*c8dee2aaSAndroid Build Coastguard Worker } else if (last.approximatelyEqual(this->pointLast())) {
616*c8dee2aaSAndroid Build Coastguard Worker result = 1;
617*c8dee2aaSAndroid Build Coastguard Worker }
618*c8dee2aaSAndroid Build Coastguard Worker if (oppPt.approximatelyEqual(opp[0])) {
619*c8dee2aaSAndroid Build Coastguard Worker *oppT = 0;
620*c8dee2aaSAndroid Build Coastguard Worker } else if (oppPt.approximatelyEqual(sect2->pointLast())) {
621*c8dee2aaSAndroid Build Coastguard Worker *oppT = 1;
622*c8dee2aaSAndroid Build Coastguard Worker }
623*c8dee2aaSAndroid Build Coastguard Worker *resultT = result;
624*c8dee2aaSAndroid Build Coastguard Worker return true;
625*c8dee2aaSAndroid Build Coastguard Worker }
626*c8dee2aaSAndroid Build Coastguard Worker
627*c8dee2aaSAndroid Build Coastguard Worker // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in quad span
628*c8dee2aaSAndroid Build Coastguard Worker // so that each quad sect has a pointer to the largest, and can update it as spans
629*c8dee2aaSAndroid Build Coastguard Worker // are split
630*c8dee2aaSAndroid Build Coastguard Worker
boundsMax()631*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSect::boundsMax() {
632*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = fHead;
633*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* largest = fHead;
634*c8dee2aaSAndroid Build Coastguard Worker bool lCollapsed = largest->fCollapsed;
635*c8dee2aaSAndroid Build Coastguard Worker int safetyNet = 10000;
636*c8dee2aaSAndroid Build Coastguard Worker while ((test = test->fNext)) {
637*c8dee2aaSAndroid Build Coastguard Worker if (!--safetyNet) {
638*c8dee2aaSAndroid Build Coastguard Worker fHung = true;
639*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
640*c8dee2aaSAndroid Build Coastguard Worker }
641*c8dee2aaSAndroid Build Coastguard Worker bool tCollapsed = test->fCollapsed;
642*c8dee2aaSAndroid Build Coastguard Worker if ((lCollapsed && !tCollapsed) || (lCollapsed == tCollapsed &&
643*c8dee2aaSAndroid Build Coastguard Worker largest->fBoundsMax < test->fBoundsMax)) {
644*c8dee2aaSAndroid Build Coastguard Worker largest = test;
645*c8dee2aaSAndroid Build Coastguard Worker lCollapsed = test->fCollapsed;
646*c8dee2aaSAndroid Build Coastguard Worker }
647*c8dee2aaSAndroid Build Coastguard Worker }
648*c8dee2aaSAndroid Build Coastguard Worker return largest;
649*c8dee2aaSAndroid Build Coastguard Worker }
650*c8dee2aaSAndroid Build Coastguard Worker
coincidentCheck(SkTSect * sect2)651*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::coincidentCheck(SkTSect* sect2) {
652*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* first = fHead;
653*c8dee2aaSAndroid Build Coastguard Worker if (!first) {
654*c8dee2aaSAndroid Build Coastguard Worker return false;
655*c8dee2aaSAndroid Build Coastguard Worker }
656*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* last, * next;
657*c8dee2aaSAndroid Build Coastguard Worker do {
658*c8dee2aaSAndroid Build Coastguard Worker int consecutive = this->countConsecutiveSpans(first, &last);
659*c8dee2aaSAndroid Build Coastguard Worker next = last->fNext;
660*c8dee2aaSAndroid Build Coastguard Worker if (consecutive < COINCIDENT_SPAN_COUNT) {
661*c8dee2aaSAndroid Build Coastguard Worker continue;
662*c8dee2aaSAndroid Build Coastguard Worker }
663*c8dee2aaSAndroid Build Coastguard Worker this->validate();
664*c8dee2aaSAndroid Build Coastguard Worker sect2->validate();
665*c8dee2aaSAndroid Build Coastguard Worker this->computePerpendiculars(sect2, first, last);
666*c8dee2aaSAndroid Build Coastguard Worker this->validate();
667*c8dee2aaSAndroid Build Coastguard Worker sect2->validate();
668*c8dee2aaSAndroid Build Coastguard Worker // check to see if a range of points are on the curve
669*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* coinStart = first;
670*c8dee2aaSAndroid Build Coastguard Worker do {
671*c8dee2aaSAndroid Build Coastguard Worker bool success = this->extractCoincident(sect2, coinStart, last, &coinStart);
672*c8dee2aaSAndroid Build Coastguard Worker if (!success) {
673*c8dee2aaSAndroid Build Coastguard Worker return false;
674*c8dee2aaSAndroid Build Coastguard Worker }
675*c8dee2aaSAndroid Build Coastguard Worker } while (coinStart && !last->fDeleted);
676*c8dee2aaSAndroid Build Coastguard Worker if (!fHead || !sect2->fHead) {
677*c8dee2aaSAndroid Build Coastguard Worker break;
678*c8dee2aaSAndroid Build Coastguard Worker }
679*c8dee2aaSAndroid Build Coastguard Worker if (!next || next->fDeleted) {
680*c8dee2aaSAndroid Build Coastguard Worker break;
681*c8dee2aaSAndroid Build Coastguard Worker }
682*c8dee2aaSAndroid Build Coastguard Worker } while ((first = next));
683*c8dee2aaSAndroid Build Coastguard Worker return true;
684*c8dee2aaSAndroid Build Coastguard Worker }
685*c8dee2aaSAndroid Build Coastguard Worker
coincidentForce(SkTSect * sect2,double start1s,double start1e)686*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::coincidentForce(SkTSect* sect2,
687*c8dee2aaSAndroid Build Coastguard Worker double start1s, double start1e) {
688*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* first = fHead;
689*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* last = this->tail();
690*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* oppFirst = sect2->fHead;
691*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* oppLast = sect2->tail();
692*c8dee2aaSAndroid Build Coastguard Worker if (!last || !oppLast) {
693*c8dee2aaSAndroid Build Coastguard Worker return;
694*c8dee2aaSAndroid Build Coastguard Worker }
695*c8dee2aaSAndroid Build Coastguard Worker bool deleteEmptySpans = this->updateBounded(first, last, oppFirst);
696*c8dee2aaSAndroid Build Coastguard Worker deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first);
697*c8dee2aaSAndroid Build Coastguard Worker this->removeSpanRange(first, last);
698*c8dee2aaSAndroid Build Coastguard Worker sect2->removeSpanRange(oppFirst, oppLast);
699*c8dee2aaSAndroid Build Coastguard Worker first->fStartT = start1s;
700*c8dee2aaSAndroid Build Coastguard Worker first->fEndT = start1e;
701*c8dee2aaSAndroid Build Coastguard Worker first->resetBounds(fCurve);
702*c8dee2aaSAndroid Build Coastguard Worker first->fCoinStart.setPerp(fCurve, start1s, fCurve[0], sect2->fCurve);
703*c8dee2aaSAndroid Build Coastguard Worker first->fCoinEnd.setPerp(fCurve, start1e, this->pointLast(), sect2->fCurve);
704*c8dee2aaSAndroid Build Coastguard Worker bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
705*c8dee2aaSAndroid Build Coastguard Worker double oppStartT = first->fCoinStart.perpT() == -1 ? 0 : std::max(0., first->fCoinStart.perpT());
706*c8dee2aaSAndroid Build Coastguard Worker double oppEndT = first->fCoinEnd.perpT() == -1 ? 1 : std::min(1., first->fCoinEnd.perpT());
707*c8dee2aaSAndroid Build Coastguard Worker if (!oppMatched) {
708*c8dee2aaSAndroid Build Coastguard Worker using std::swap;
709*c8dee2aaSAndroid Build Coastguard Worker swap(oppStartT, oppEndT);
710*c8dee2aaSAndroid Build Coastguard Worker }
711*c8dee2aaSAndroid Build Coastguard Worker oppFirst->fStartT = oppStartT;
712*c8dee2aaSAndroid Build Coastguard Worker oppFirst->fEndT = oppEndT;
713*c8dee2aaSAndroid Build Coastguard Worker oppFirst->resetBounds(sect2->fCurve);
714*c8dee2aaSAndroid Build Coastguard Worker this->removeCoincident(first, false);
715*c8dee2aaSAndroid Build Coastguard Worker sect2->removeCoincident(oppFirst, true);
716*c8dee2aaSAndroid Build Coastguard Worker if (deleteEmptySpans) {
717*c8dee2aaSAndroid Build Coastguard Worker this->deleteEmptySpans();
718*c8dee2aaSAndroid Build Coastguard Worker sect2->deleteEmptySpans();
719*c8dee2aaSAndroid Build Coastguard Worker }
720*c8dee2aaSAndroid Build Coastguard Worker }
721*c8dee2aaSAndroid Build Coastguard Worker
coincidentHasT(double t)722*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::coincidentHasT(double t) {
723*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = fCoincident;
724*c8dee2aaSAndroid Build Coastguard Worker while (test) {
725*c8dee2aaSAndroid Build Coastguard Worker if (between(test->fStartT, t, test->fEndT)) {
726*c8dee2aaSAndroid Build Coastguard Worker return true;
727*c8dee2aaSAndroid Build Coastguard Worker }
728*c8dee2aaSAndroid Build Coastguard Worker test = test->fNext;
729*c8dee2aaSAndroid Build Coastguard Worker }
730*c8dee2aaSAndroid Build Coastguard Worker return false;
731*c8dee2aaSAndroid Build Coastguard Worker }
732*c8dee2aaSAndroid Build Coastguard Worker
collapsed() const733*c8dee2aaSAndroid Build Coastguard Worker int SkTSect::collapsed() const {
734*c8dee2aaSAndroid Build Coastguard Worker int result = 0;
735*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* test = fHead;
736*c8dee2aaSAndroid Build Coastguard Worker while (test) {
737*c8dee2aaSAndroid Build Coastguard Worker if (test->fCollapsed) {
738*c8dee2aaSAndroid Build Coastguard Worker ++result;
739*c8dee2aaSAndroid Build Coastguard Worker }
740*c8dee2aaSAndroid Build Coastguard Worker test = test->next();
741*c8dee2aaSAndroid Build Coastguard Worker }
742*c8dee2aaSAndroid Build Coastguard Worker return result;
743*c8dee2aaSAndroid Build Coastguard Worker }
744*c8dee2aaSAndroid Build Coastguard Worker
computePerpendiculars(SkTSect * sect2,SkTSpan * first,SkTSpan * last)745*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::computePerpendiculars(SkTSect* sect2,
746*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* first, SkTSpan* last) {
747*c8dee2aaSAndroid Build Coastguard Worker if (!last) {
748*c8dee2aaSAndroid Build Coastguard Worker return;
749*c8dee2aaSAndroid Build Coastguard Worker }
750*c8dee2aaSAndroid Build Coastguard Worker const SkTCurve& opp = sect2->fCurve;
751*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* work = first;
752*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* prior = nullptr;
753*c8dee2aaSAndroid Build Coastguard Worker do {
754*c8dee2aaSAndroid Build Coastguard Worker if (!work->fHasPerp && !work->fCollapsed) {
755*c8dee2aaSAndroid Build Coastguard Worker if (prior) {
756*c8dee2aaSAndroid Build Coastguard Worker work->fCoinStart = prior->fCoinEnd;
757*c8dee2aaSAndroid Build Coastguard Worker } else {
758*c8dee2aaSAndroid Build Coastguard Worker work->fCoinStart.setPerp(fCurve, work->fStartT, work->pointFirst(), opp);
759*c8dee2aaSAndroid Build Coastguard Worker }
760*c8dee2aaSAndroid Build Coastguard Worker if (work->fCoinStart.isMatch()) {
761*c8dee2aaSAndroid Build Coastguard Worker double perpT = work->fCoinStart.perpT();
762*c8dee2aaSAndroid Build Coastguard Worker if (sect2->coincidentHasT(perpT)) {
763*c8dee2aaSAndroid Build Coastguard Worker work->fCoinStart.init();
764*c8dee2aaSAndroid Build Coastguard Worker } else {
765*c8dee2aaSAndroid Build Coastguard Worker sect2->addForPerp(work, perpT);
766*c8dee2aaSAndroid Build Coastguard Worker }
767*c8dee2aaSAndroid Build Coastguard Worker }
768*c8dee2aaSAndroid Build Coastguard Worker work->fCoinEnd.setPerp(fCurve, work->fEndT, work->pointLast(), opp);
769*c8dee2aaSAndroid Build Coastguard Worker if (work->fCoinEnd.isMatch()) {
770*c8dee2aaSAndroid Build Coastguard Worker double perpT = work->fCoinEnd.perpT();
771*c8dee2aaSAndroid Build Coastguard Worker if (sect2->coincidentHasT(perpT)) {
772*c8dee2aaSAndroid Build Coastguard Worker work->fCoinEnd.init();
773*c8dee2aaSAndroid Build Coastguard Worker } else {
774*c8dee2aaSAndroid Build Coastguard Worker sect2->addForPerp(work, perpT);
775*c8dee2aaSAndroid Build Coastguard Worker }
776*c8dee2aaSAndroid Build Coastguard Worker }
777*c8dee2aaSAndroid Build Coastguard Worker work->fHasPerp = true;
778*c8dee2aaSAndroid Build Coastguard Worker }
779*c8dee2aaSAndroid Build Coastguard Worker if (work == last) {
780*c8dee2aaSAndroid Build Coastguard Worker break;
781*c8dee2aaSAndroid Build Coastguard Worker }
782*c8dee2aaSAndroid Build Coastguard Worker prior = work;
783*c8dee2aaSAndroid Build Coastguard Worker work = work->fNext;
784*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(work);
785*c8dee2aaSAndroid Build Coastguard Worker } while (true);
786*c8dee2aaSAndroid Build Coastguard Worker }
787*c8dee2aaSAndroid Build Coastguard Worker
countConsecutiveSpans(SkTSpan * first,SkTSpan ** lastPtr) const788*c8dee2aaSAndroid Build Coastguard Worker int SkTSect::countConsecutiveSpans(SkTSpan* first,
789*c8dee2aaSAndroid Build Coastguard Worker SkTSpan** lastPtr) const {
790*c8dee2aaSAndroid Build Coastguard Worker int consecutive = 1;
791*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* last = first;
792*c8dee2aaSAndroid Build Coastguard Worker do {
793*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* next = last->fNext;
794*c8dee2aaSAndroid Build Coastguard Worker if (!next) {
795*c8dee2aaSAndroid Build Coastguard Worker break;
796*c8dee2aaSAndroid Build Coastguard Worker }
797*c8dee2aaSAndroid Build Coastguard Worker if (next->fStartT > last->fEndT) {
798*c8dee2aaSAndroid Build Coastguard Worker break;
799*c8dee2aaSAndroid Build Coastguard Worker }
800*c8dee2aaSAndroid Build Coastguard Worker ++consecutive;
801*c8dee2aaSAndroid Build Coastguard Worker last = next;
802*c8dee2aaSAndroid Build Coastguard Worker } while (true);
803*c8dee2aaSAndroid Build Coastguard Worker *lastPtr = last;
804*c8dee2aaSAndroid Build Coastguard Worker return consecutive;
805*c8dee2aaSAndroid Build Coastguard Worker }
806*c8dee2aaSAndroid Build Coastguard Worker
hasBounded(const SkTSpan * span) const807*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::hasBounded(const SkTSpan* span) const {
808*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* test = fHead;
809*c8dee2aaSAndroid Build Coastguard Worker if (!test) {
810*c8dee2aaSAndroid Build Coastguard Worker return false;
811*c8dee2aaSAndroid Build Coastguard Worker }
812*c8dee2aaSAndroid Build Coastguard Worker do {
813*c8dee2aaSAndroid Build Coastguard Worker if (test->findOppSpan(span)) {
814*c8dee2aaSAndroid Build Coastguard Worker return true;
815*c8dee2aaSAndroid Build Coastguard Worker }
816*c8dee2aaSAndroid Build Coastguard Worker } while ((test = test->next()));
817*c8dee2aaSAndroid Build Coastguard Worker return false;
818*c8dee2aaSAndroid Build Coastguard Worker }
819*c8dee2aaSAndroid Build Coastguard Worker
deleteEmptySpans()820*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::deleteEmptySpans() {
821*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test;
822*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* next = fHead;
823*c8dee2aaSAndroid Build Coastguard Worker int safetyHatch = 1000;
824*c8dee2aaSAndroid Build Coastguard Worker while ((test = next)) {
825*c8dee2aaSAndroid Build Coastguard Worker next = test->fNext;
826*c8dee2aaSAndroid Build Coastguard Worker if (!test->fBounded) {
827*c8dee2aaSAndroid Build Coastguard Worker if (!this->removeSpan(test)) {
828*c8dee2aaSAndroid Build Coastguard Worker return false;
829*c8dee2aaSAndroid Build Coastguard Worker }
830*c8dee2aaSAndroid Build Coastguard Worker }
831*c8dee2aaSAndroid Build Coastguard Worker if (--safetyHatch < 0) {
832*c8dee2aaSAndroid Build Coastguard Worker return false;
833*c8dee2aaSAndroid Build Coastguard Worker }
834*c8dee2aaSAndroid Build Coastguard Worker }
835*c8dee2aaSAndroid Build Coastguard Worker return true;
836*c8dee2aaSAndroid Build Coastguard Worker }
837*c8dee2aaSAndroid Build Coastguard Worker
extractCoincident(SkTSect * sect2,SkTSpan * first,SkTSpan * last,SkTSpan ** result)838*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::extractCoincident(
839*c8dee2aaSAndroid Build Coastguard Worker SkTSect* sect2,
840*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* first, SkTSpan* last,
841*c8dee2aaSAndroid Build Coastguard Worker SkTSpan** result) {
842*c8dee2aaSAndroid Build Coastguard Worker first = findCoincidentRun(first, &last);
843*c8dee2aaSAndroid Build Coastguard Worker if (!first || !last) {
844*c8dee2aaSAndroid Build Coastguard Worker *result = nullptr;
845*c8dee2aaSAndroid Build Coastguard Worker return true;
846*c8dee2aaSAndroid Build Coastguard Worker }
847*c8dee2aaSAndroid Build Coastguard Worker // march outwards to find limit of coincidence from here to previous and next spans
848*c8dee2aaSAndroid Build Coastguard Worker double startT = first->fStartT;
849*c8dee2aaSAndroid Build Coastguard Worker double oppStartT SK_INIT_TO_AVOID_WARNING;
850*c8dee2aaSAndroid Build Coastguard Worker double oppEndT SK_INIT_TO_AVOID_WARNING;
851*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* prev = first->fPrev;
852*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(first->fCoinStart.isMatch());
853*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* oppFirst = first->findOppT(first->fCoinStart.perpT());
854*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(last->fCoinEnd.isMatch());
855*c8dee2aaSAndroid Build Coastguard Worker bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
856*c8dee2aaSAndroid Build Coastguard Worker double coinStart;
857*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(double coinEnd);
858*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* cutFirst;
859*c8dee2aaSAndroid Build Coastguard Worker if (prev && prev->fEndT == startT
860*c8dee2aaSAndroid Build Coastguard Worker && this->binarySearchCoin(sect2, startT, prev->fStartT - startT, &coinStart,
861*c8dee2aaSAndroid Build Coastguard Worker &oppStartT, &oppFirst)
862*c8dee2aaSAndroid Build Coastguard Worker && prev->fStartT < coinStart && coinStart < startT
863*c8dee2aaSAndroid Build Coastguard Worker && (cutFirst = prev->oppT(oppStartT))) {
864*c8dee2aaSAndroid Build Coastguard Worker oppFirst = cutFirst;
865*c8dee2aaSAndroid Build Coastguard Worker first = this->addSplitAt(prev, coinStart);
866*c8dee2aaSAndroid Build Coastguard Worker first->markCoincident();
867*c8dee2aaSAndroid Build Coastguard Worker prev->fCoinEnd.markCoincident();
868*c8dee2aaSAndroid Build Coastguard Worker if (oppFirst->fStartT < oppStartT && oppStartT < oppFirst->fEndT) {
869*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* oppHalf = sect2->addSplitAt(oppFirst, oppStartT);
870*c8dee2aaSAndroid Build Coastguard Worker if (oppMatched) {
871*c8dee2aaSAndroid Build Coastguard Worker oppFirst->fCoinEnd.markCoincident();
872*c8dee2aaSAndroid Build Coastguard Worker oppHalf->markCoincident();
873*c8dee2aaSAndroid Build Coastguard Worker oppFirst = oppHalf;
874*c8dee2aaSAndroid Build Coastguard Worker } else {
875*c8dee2aaSAndroid Build Coastguard Worker oppFirst->markCoincident();
876*c8dee2aaSAndroid Build Coastguard Worker oppHalf->fCoinStart.markCoincident();
877*c8dee2aaSAndroid Build Coastguard Worker }
878*c8dee2aaSAndroid Build Coastguard Worker }
879*c8dee2aaSAndroid Build Coastguard Worker } else {
880*c8dee2aaSAndroid Build Coastguard Worker if (!oppFirst) {
881*c8dee2aaSAndroid Build Coastguard Worker return false;
882*c8dee2aaSAndroid Build Coastguard Worker }
883*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(coinStart = first->fStartT);
884*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT);
885*c8dee2aaSAndroid Build Coastguard Worker }
886*c8dee2aaSAndroid Build Coastguard Worker // FIXME: incomplete : if we're not at the end, find end of coin
887*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* oppLast;
888*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(last->fCoinEnd.isMatch());
889*c8dee2aaSAndroid Build Coastguard Worker oppLast = last->findOppT(last->fCoinEnd.perpT());
890*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(coinEnd = last->fEndT);
891*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
892*c8dee2aaSAndroid Build Coastguard Worker if (!this->globalState() || !this->globalState()->debugSkipAssert()) {
893*c8dee2aaSAndroid Build Coastguard Worker oppEndT = oppMatched ? oppLast->fEndT : oppLast->fStartT;
894*c8dee2aaSAndroid Build Coastguard Worker }
895*c8dee2aaSAndroid Build Coastguard Worker #endif
896*c8dee2aaSAndroid Build Coastguard Worker if (!oppMatched) {
897*c8dee2aaSAndroid Build Coastguard Worker using std::swap;
898*c8dee2aaSAndroid Build Coastguard Worker swap(oppFirst, oppLast);
899*c8dee2aaSAndroid Build Coastguard Worker swap(oppStartT, oppEndT);
900*c8dee2aaSAndroid Build Coastguard Worker }
901*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(oppStartT < oppEndT);
902*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(coinStart == first->fStartT);
903*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(coinEnd == last->fEndT);
904*c8dee2aaSAndroid Build Coastguard Worker if (!oppFirst) {
905*c8dee2aaSAndroid Build Coastguard Worker *result = nullptr;
906*c8dee2aaSAndroid Build Coastguard Worker return true;
907*c8dee2aaSAndroid Build Coastguard Worker }
908*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(oppStartT == oppFirst->fStartT);
909*c8dee2aaSAndroid Build Coastguard Worker if (!oppLast) {
910*c8dee2aaSAndroid Build Coastguard Worker *result = nullptr;
911*c8dee2aaSAndroid Build Coastguard Worker return true;
912*c8dee2aaSAndroid Build Coastguard Worker }
913*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(oppEndT == oppLast->fEndT);
914*c8dee2aaSAndroid Build Coastguard Worker // reduce coincident runs to single entries
915*c8dee2aaSAndroid Build Coastguard Worker this->validate();
916*c8dee2aaSAndroid Build Coastguard Worker sect2->validate();
917*c8dee2aaSAndroid Build Coastguard Worker bool deleteEmptySpans = this->updateBounded(first, last, oppFirst);
918*c8dee2aaSAndroid Build Coastguard Worker deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first);
919*c8dee2aaSAndroid Build Coastguard Worker this->removeSpanRange(first, last);
920*c8dee2aaSAndroid Build Coastguard Worker sect2->removeSpanRange(oppFirst, oppLast);
921*c8dee2aaSAndroid Build Coastguard Worker first->fEndT = last->fEndT;
922*c8dee2aaSAndroid Build Coastguard Worker first->resetBounds(this->fCurve);
923*c8dee2aaSAndroid Build Coastguard Worker first->fCoinStart.setPerp(fCurve, first->fStartT, first->pointFirst(), sect2->fCurve);
924*c8dee2aaSAndroid Build Coastguard Worker first->fCoinEnd.setPerp(fCurve, first->fEndT, first->pointLast(), sect2->fCurve);
925*c8dee2aaSAndroid Build Coastguard Worker oppStartT = first->fCoinStart.perpT();
926*c8dee2aaSAndroid Build Coastguard Worker oppEndT = first->fCoinEnd.perpT();
927*c8dee2aaSAndroid Build Coastguard Worker if (between(0, oppStartT, 1) && between(0, oppEndT, 1)) {
928*c8dee2aaSAndroid Build Coastguard Worker if (!oppMatched) {
929*c8dee2aaSAndroid Build Coastguard Worker using std::swap;
930*c8dee2aaSAndroid Build Coastguard Worker swap(oppStartT, oppEndT);
931*c8dee2aaSAndroid Build Coastguard Worker }
932*c8dee2aaSAndroid Build Coastguard Worker oppFirst->fStartT = oppStartT;
933*c8dee2aaSAndroid Build Coastguard Worker oppFirst->fEndT = oppEndT;
934*c8dee2aaSAndroid Build Coastguard Worker oppFirst->resetBounds(sect2->fCurve);
935*c8dee2aaSAndroid Build Coastguard Worker }
936*c8dee2aaSAndroid Build Coastguard Worker this->validateBounded();
937*c8dee2aaSAndroid Build Coastguard Worker sect2->validateBounded();
938*c8dee2aaSAndroid Build Coastguard Worker last = first->fNext;
939*c8dee2aaSAndroid Build Coastguard Worker if (!this->removeCoincident(first, false)) {
940*c8dee2aaSAndroid Build Coastguard Worker return false;
941*c8dee2aaSAndroid Build Coastguard Worker }
942*c8dee2aaSAndroid Build Coastguard Worker if (!sect2->removeCoincident(oppFirst, true)) {
943*c8dee2aaSAndroid Build Coastguard Worker return false;
944*c8dee2aaSAndroid Build Coastguard Worker }
945*c8dee2aaSAndroid Build Coastguard Worker if (deleteEmptySpans) {
946*c8dee2aaSAndroid Build Coastguard Worker if (!this->deleteEmptySpans() || !sect2->deleteEmptySpans()) {
947*c8dee2aaSAndroid Build Coastguard Worker *result = nullptr;
948*c8dee2aaSAndroid Build Coastguard Worker return false;
949*c8dee2aaSAndroid Build Coastguard Worker }
950*c8dee2aaSAndroid Build Coastguard Worker }
951*c8dee2aaSAndroid Build Coastguard Worker this->validate();
952*c8dee2aaSAndroid Build Coastguard Worker sect2->validate();
953*c8dee2aaSAndroid Build Coastguard Worker *result = last && !last->fDeleted && fHead && sect2->fHead ? last : nullptr;
954*c8dee2aaSAndroid Build Coastguard Worker return true;
955*c8dee2aaSAndroid Build Coastguard Worker }
956*c8dee2aaSAndroid Build Coastguard Worker
findCoincidentRun(SkTSpan * first,SkTSpan ** lastPtr)957*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSect::findCoincidentRun(
958*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* first, SkTSpan** lastPtr) {
959*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* work = first;
960*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* lastCandidate = nullptr;
961*c8dee2aaSAndroid Build Coastguard Worker first = nullptr;
962*c8dee2aaSAndroid Build Coastguard Worker // find the first fully coincident span
963*c8dee2aaSAndroid Build Coastguard Worker do {
964*c8dee2aaSAndroid Build Coastguard Worker if (work->fCoinStart.isMatch()) {
965*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
966*c8dee2aaSAndroid Build Coastguard Worker work->validatePerpT(work->fCoinStart.perpT());
967*c8dee2aaSAndroid Build Coastguard Worker work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt());
968*c8dee2aaSAndroid Build Coastguard Worker #endif
969*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(work->hasOppT(work->fCoinStart.perpT()));
970*c8dee2aaSAndroid Build Coastguard Worker if (!work->fCoinEnd.isMatch()) {
971*c8dee2aaSAndroid Build Coastguard Worker break;
972*c8dee2aaSAndroid Build Coastguard Worker }
973*c8dee2aaSAndroid Build Coastguard Worker lastCandidate = work;
974*c8dee2aaSAndroid Build Coastguard Worker if (!first) {
975*c8dee2aaSAndroid Build Coastguard Worker first = work;
976*c8dee2aaSAndroid Build Coastguard Worker }
977*c8dee2aaSAndroid Build Coastguard Worker } else if (first && work->fCollapsed) {
978*c8dee2aaSAndroid Build Coastguard Worker *lastPtr = lastCandidate;
979*c8dee2aaSAndroid Build Coastguard Worker return first;
980*c8dee2aaSAndroid Build Coastguard Worker } else {
981*c8dee2aaSAndroid Build Coastguard Worker lastCandidate = nullptr;
982*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(!first);
983*c8dee2aaSAndroid Build Coastguard Worker }
984*c8dee2aaSAndroid Build Coastguard Worker if (work == *lastPtr) {
985*c8dee2aaSAndroid Build Coastguard Worker return first;
986*c8dee2aaSAndroid Build Coastguard Worker }
987*c8dee2aaSAndroid Build Coastguard Worker work = work->fNext;
988*c8dee2aaSAndroid Build Coastguard Worker if (!work) {
989*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
990*c8dee2aaSAndroid Build Coastguard Worker }
991*c8dee2aaSAndroid Build Coastguard Worker } while (true);
992*c8dee2aaSAndroid Build Coastguard Worker if (lastCandidate) {
993*c8dee2aaSAndroid Build Coastguard Worker *lastPtr = lastCandidate;
994*c8dee2aaSAndroid Build Coastguard Worker }
995*c8dee2aaSAndroid Build Coastguard Worker return first;
996*c8dee2aaSAndroid Build Coastguard Worker }
997*c8dee2aaSAndroid Build Coastguard Worker
intersects(SkTSpan * span,SkTSect * opp,SkTSpan * oppSpan,int * oppResult)998*c8dee2aaSAndroid Build Coastguard Worker int SkTSect::intersects(SkTSpan* span,
999*c8dee2aaSAndroid Build Coastguard Worker SkTSect* opp,
1000*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* oppSpan, int* oppResult) {
1001*c8dee2aaSAndroid Build Coastguard Worker bool spanStart, oppStart;
1002*c8dee2aaSAndroid Build Coastguard Worker int hullResult = span->hullsIntersect(oppSpan, &spanStart, &oppStart);
1003*c8dee2aaSAndroid Build Coastguard Worker if (hullResult >= 0) {
1004*c8dee2aaSAndroid Build Coastguard Worker if (hullResult == 2) { // hulls have one point in common
1005*c8dee2aaSAndroid Build Coastguard Worker if (!span->fBounded || !span->fBounded->fNext) {
1006*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!span->fBounded || span->fBounded->fBounded == oppSpan);
1007*c8dee2aaSAndroid Build Coastguard Worker if (spanStart) {
1008*c8dee2aaSAndroid Build Coastguard Worker span->fEndT = span->fStartT;
1009*c8dee2aaSAndroid Build Coastguard Worker } else {
1010*c8dee2aaSAndroid Build Coastguard Worker span->fStartT = span->fEndT;
1011*c8dee2aaSAndroid Build Coastguard Worker }
1012*c8dee2aaSAndroid Build Coastguard Worker } else {
1013*c8dee2aaSAndroid Build Coastguard Worker hullResult = 1;
1014*c8dee2aaSAndroid Build Coastguard Worker }
1015*c8dee2aaSAndroid Build Coastguard Worker if (!oppSpan->fBounded || !oppSpan->fBounded->fNext) {
1016*c8dee2aaSAndroid Build Coastguard Worker if (oppSpan->fBounded && oppSpan->fBounded->fBounded != span) {
1017*c8dee2aaSAndroid Build Coastguard Worker return 0;
1018*c8dee2aaSAndroid Build Coastguard Worker }
1019*c8dee2aaSAndroid Build Coastguard Worker if (oppStart) {
1020*c8dee2aaSAndroid Build Coastguard Worker oppSpan->fEndT = oppSpan->fStartT;
1021*c8dee2aaSAndroid Build Coastguard Worker } else {
1022*c8dee2aaSAndroid Build Coastguard Worker oppSpan->fStartT = oppSpan->fEndT;
1023*c8dee2aaSAndroid Build Coastguard Worker }
1024*c8dee2aaSAndroid Build Coastguard Worker *oppResult = 2;
1025*c8dee2aaSAndroid Build Coastguard Worker } else {
1026*c8dee2aaSAndroid Build Coastguard Worker *oppResult = 1;
1027*c8dee2aaSAndroid Build Coastguard Worker }
1028*c8dee2aaSAndroid Build Coastguard Worker } else {
1029*c8dee2aaSAndroid Build Coastguard Worker *oppResult = 1;
1030*c8dee2aaSAndroid Build Coastguard Worker }
1031*c8dee2aaSAndroid Build Coastguard Worker return hullResult;
1032*c8dee2aaSAndroid Build Coastguard Worker }
1033*c8dee2aaSAndroid Build Coastguard Worker if (span->fIsLine && oppSpan->fIsLine) {
1034*c8dee2aaSAndroid Build Coastguard Worker SkIntersections i;
1035*c8dee2aaSAndroid Build Coastguard Worker int sects = this->linesIntersect(span, opp, oppSpan, &i);
1036*c8dee2aaSAndroid Build Coastguard Worker if (sects == 2) {
1037*c8dee2aaSAndroid Build Coastguard Worker return *oppResult = 1;
1038*c8dee2aaSAndroid Build Coastguard Worker }
1039*c8dee2aaSAndroid Build Coastguard Worker if (!sects) {
1040*c8dee2aaSAndroid Build Coastguard Worker return -1;
1041*c8dee2aaSAndroid Build Coastguard Worker }
1042*c8dee2aaSAndroid Build Coastguard Worker this->removedEndCheck(span);
1043*c8dee2aaSAndroid Build Coastguard Worker span->fStartT = span->fEndT = i[0][0];
1044*c8dee2aaSAndroid Build Coastguard Worker opp->removedEndCheck(oppSpan);
1045*c8dee2aaSAndroid Build Coastguard Worker oppSpan->fStartT = oppSpan->fEndT = i[1][0];
1046*c8dee2aaSAndroid Build Coastguard Worker return *oppResult = 2;
1047*c8dee2aaSAndroid Build Coastguard Worker }
1048*c8dee2aaSAndroid Build Coastguard Worker if (span->fIsLinear || oppSpan->fIsLinear) {
1049*c8dee2aaSAndroid Build Coastguard Worker return *oppResult = (int) span->linearsIntersect(oppSpan);
1050*c8dee2aaSAndroid Build Coastguard Worker }
1051*c8dee2aaSAndroid Build Coastguard Worker return *oppResult = 1;
1052*c8dee2aaSAndroid Build Coastguard Worker }
1053*c8dee2aaSAndroid Build Coastguard Worker
1054*c8dee2aaSAndroid Build Coastguard Worker template<typename SkTCurve>
is_parallel(const SkDLine & thisLine,const SkTCurve & opp)1055*c8dee2aaSAndroid Build Coastguard Worker static bool is_parallel(const SkDLine& thisLine, const SkTCurve& opp) {
1056*c8dee2aaSAndroid Build Coastguard Worker if (!opp.IsConic()) {
1057*c8dee2aaSAndroid Build Coastguard Worker return false; // FIXME : breaks a lot of stuff now
1058*c8dee2aaSAndroid Build Coastguard Worker }
1059*c8dee2aaSAndroid Build Coastguard Worker int finds = 0;
1060*c8dee2aaSAndroid Build Coastguard Worker SkDLine thisPerp;
1061*c8dee2aaSAndroid Build Coastguard Worker thisPerp.fPts[0].fX = thisLine.fPts[1].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY);
1062*c8dee2aaSAndroid Build Coastguard Worker thisPerp.fPts[0].fY = thisLine.fPts[1].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX);
1063*c8dee2aaSAndroid Build Coastguard Worker thisPerp.fPts[1] = thisLine.fPts[1];
1064*c8dee2aaSAndroid Build Coastguard Worker SkIntersections perpRayI;
1065*c8dee2aaSAndroid Build Coastguard Worker perpRayI.intersectRay(opp, thisPerp);
1066*c8dee2aaSAndroid Build Coastguard Worker for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) {
1067*c8dee2aaSAndroid Build Coastguard Worker finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[1]);
1068*c8dee2aaSAndroid Build Coastguard Worker }
1069*c8dee2aaSAndroid Build Coastguard Worker thisPerp.fPts[1].fX = thisLine.fPts[0].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY);
1070*c8dee2aaSAndroid Build Coastguard Worker thisPerp.fPts[1].fY = thisLine.fPts[0].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX);
1071*c8dee2aaSAndroid Build Coastguard Worker thisPerp.fPts[0] = thisLine.fPts[0];
1072*c8dee2aaSAndroid Build Coastguard Worker perpRayI.intersectRay(opp, thisPerp);
1073*c8dee2aaSAndroid Build Coastguard Worker for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) {
1074*c8dee2aaSAndroid Build Coastguard Worker finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[0]);
1075*c8dee2aaSAndroid Build Coastguard Worker }
1076*c8dee2aaSAndroid Build Coastguard Worker return finds >= 2;
1077*c8dee2aaSAndroid Build Coastguard Worker }
1078*c8dee2aaSAndroid Build Coastguard Worker
1079*c8dee2aaSAndroid Build Coastguard Worker // while the intersection points are sufficiently far apart:
1080*c8dee2aaSAndroid Build Coastguard Worker // construct the tangent lines from the intersections
1081*c8dee2aaSAndroid Build Coastguard Worker // find the point where the tangent line intersects the opposite curve
1082*c8dee2aaSAndroid Build Coastguard Worker
linesIntersect(SkTSpan * span,SkTSect * opp,SkTSpan * oppSpan,SkIntersections * i)1083*c8dee2aaSAndroid Build Coastguard Worker int SkTSect::linesIntersect(SkTSpan* span,
1084*c8dee2aaSAndroid Build Coastguard Worker SkTSect* opp,
1085*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* oppSpan, SkIntersections* i) {
1086*c8dee2aaSAndroid Build Coastguard Worker SkIntersections thisRayI SkDEBUGCODE((span->fDebugGlobalState));
1087*c8dee2aaSAndroid Build Coastguard Worker SkIntersections oppRayI SkDEBUGCODE((span->fDebugGlobalState));
1088*c8dee2aaSAndroid Build Coastguard Worker SkDLine thisLine = {{ span->pointFirst(), span->pointLast() }};
1089*c8dee2aaSAndroid Build Coastguard Worker SkDLine oppLine = {{ oppSpan->pointFirst(), oppSpan->pointLast() }};
1090*c8dee2aaSAndroid Build Coastguard Worker int loopCount = 0;
1091*c8dee2aaSAndroid Build Coastguard Worker double bestDistSq = DBL_MAX;
1092*c8dee2aaSAndroid Build Coastguard Worker if (!thisRayI.intersectRay(opp->fCurve, thisLine)) {
1093*c8dee2aaSAndroid Build Coastguard Worker return 0;
1094*c8dee2aaSAndroid Build Coastguard Worker }
1095*c8dee2aaSAndroid Build Coastguard Worker if (!oppRayI.intersectRay(this->fCurve, oppLine)) {
1096*c8dee2aaSAndroid Build Coastguard Worker return 0;
1097*c8dee2aaSAndroid Build Coastguard Worker }
1098*c8dee2aaSAndroid Build Coastguard Worker // if the ends of each line intersect the opposite curve, the lines are coincident
1099*c8dee2aaSAndroid Build Coastguard Worker if (thisRayI.used() > 1) {
1100*c8dee2aaSAndroid Build Coastguard Worker int ptMatches = 0;
1101*c8dee2aaSAndroid Build Coastguard Worker for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) {
1102*c8dee2aaSAndroid Build Coastguard Worker for (int lIndex = 0; lIndex < (int) std::size(thisLine.fPts); ++lIndex) {
1103*c8dee2aaSAndroid Build Coastguard Worker ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPts[lIndex]);
1104*c8dee2aaSAndroid Build Coastguard Worker }
1105*c8dee2aaSAndroid Build Coastguard Worker }
1106*c8dee2aaSAndroid Build Coastguard Worker if (ptMatches == 2 || is_parallel(thisLine, opp->fCurve)) {
1107*c8dee2aaSAndroid Build Coastguard Worker return 2;
1108*c8dee2aaSAndroid Build Coastguard Worker }
1109*c8dee2aaSAndroid Build Coastguard Worker }
1110*c8dee2aaSAndroid Build Coastguard Worker if (oppRayI.used() > 1) {
1111*c8dee2aaSAndroid Build Coastguard Worker int ptMatches = 0;
1112*c8dee2aaSAndroid Build Coastguard Worker for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) {
1113*c8dee2aaSAndroid Build Coastguard Worker for (int lIndex = 0; lIndex < (int) std::size(oppLine.fPts); ++lIndex) {
1114*c8dee2aaSAndroid Build Coastguard Worker ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[lIndex]);
1115*c8dee2aaSAndroid Build Coastguard Worker }
1116*c8dee2aaSAndroid Build Coastguard Worker }
1117*c8dee2aaSAndroid Build Coastguard Worker if (ptMatches == 2|| is_parallel(oppLine, this->fCurve)) {
1118*c8dee2aaSAndroid Build Coastguard Worker return 2;
1119*c8dee2aaSAndroid Build Coastguard Worker }
1120*c8dee2aaSAndroid Build Coastguard Worker }
1121*c8dee2aaSAndroid Build Coastguard Worker do {
1122*c8dee2aaSAndroid Build Coastguard Worker // pick the closest pair of points
1123*c8dee2aaSAndroid Build Coastguard Worker double closest = DBL_MAX;
1124*c8dee2aaSAndroid Build Coastguard Worker int closeIndex SK_INIT_TO_AVOID_WARNING;
1125*c8dee2aaSAndroid Build Coastguard Worker int oppCloseIndex SK_INIT_TO_AVOID_WARNING;
1126*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < oppRayI.used(); ++index) {
1127*c8dee2aaSAndroid Build Coastguard Worker if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT)) {
1128*c8dee2aaSAndroid Build Coastguard Worker continue;
1129*c8dee2aaSAndroid Build Coastguard Worker }
1130*c8dee2aaSAndroid Build Coastguard Worker for (int oIndex = 0; oIndex < thisRayI.used(); ++oIndex) {
1131*c8dee2aaSAndroid Build Coastguard Worker if (!roughly_between(oppSpan->fStartT, thisRayI[0][oIndex], oppSpan->fEndT)) {
1132*c8dee2aaSAndroid Build Coastguard Worker continue;
1133*c8dee2aaSAndroid Build Coastguard Worker }
1134*c8dee2aaSAndroid Build Coastguard Worker double distSq = thisRayI.pt(index).distanceSquared(oppRayI.pt(oIndex));
1135*c8dee2aaSAndroid Build Coastguard Worker if (closest > distSq) {
1136*c8dee2aaSAndroid Build Coastguard Worker closest = distSq;
1137*c8dee2aaSAndroid Build Coastguard Worker closeIndex = index;
1138*c8dee2aaSAndroid Build Coastguard Worker oppCloseIndex = oIndex;
1139*c8dee2aaSAndroid Build Coastguard Worker }
1140*c8dee2aaSAndroid Build Coastguard Worker }
1141*c8dee2aaSAndroid Build Coastguard Worker }
1142*c8dee2aaSAndroid Build Coastguard Worker if (closest == DBL_MAX) {
1143*c8dee2aaSAndroid Build Coastguard Worker break;
1144*c8dee2aaSAndroid Build Coastguard Worker }
1145*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint& oppIPt = thisRayI.pt(oppCloseIndex);
1146*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint& iPt = oppRayI.pt(closeIndex);
1147*c8dee2aaSAndroid Build Coastguard Worker if (between(span->fStartT, oppRayI[0][closeIndex], span->fEndT)
1148*c8dee2aaSAndroid Build Coastguard Worker && between(oppSpan->fStartT, thisRayI[0][oppCloseIndex], oppSpan->fEndT)
1149*c8dee2aaSAndroid Build Coastguard Worker && oppIPt.approximatelyEqual(iPt)) {
1150*c8dee2aaSAndroid Build Coastguard Worker i->merge(oppRayI, closeIndex, thisRayI, oppCloseIndex);
1151*c8dee2aaSAndroid Build Coastguard Worker return i->used();
1152*c8dee2aaSAndroid Build Coastguard Worker }
1153*c8dee2aaSAndroid Build Coastguard Worker double distSq = oppIPt.distanceSquared(iPt);
1154*c8dee2aaSAndroid Build Coastguard Worker if (bestDistSq < distSq || ++loopCount > 5) {
1155*c8dee2aaSAndroid Build Coastguard Worker return 0;
1156*c8dee2aaSAndroid Build Coastguard Worker }
1157*c8dee2aaSAndroid Build Coastguard Worker bestDistSq = distSq;
1158*c8dee2aaSAndroid Build Coastguard Worker double oppStart = oppRayI[0][closeIndex];
1159*c8dee2aaSAndroid Build Coastguard Worker thisLine[0] = fCurve.ptAtT(oppStart);
1160*c8dee2aaSAndroid Build Coastguard Worker thisLine[1] = thisLine[0] + fCurve.dxdyAtT(oppStart);
1161*c8dee2aaSAndroid Build Coastguard Worker if (!thisRayI.intersectRay(opp->fCurve, thisLine)) {
1162*c8dee2aaSAndroid Build Coastguard Worker break;
1163*c8dee2aaSAndroid Build Coastguard Worker }
1164*c8dee2aaSAndroid Build Coastguard Worker double start = thisRayI[0][oppCloseIndex];
1165*c8dee2aaSAndroid Build Coastguard Worker oppLine[0] = opp->fCurve.ptAtT(start);
1166*c8dee2aaSAndroid Build Coastguard Worker oppLine[1] = oppLine[0] + opp->fCurve.dxdyAtT(start);
1167*c8dee2aaSAndroid Build Coastguard Worker if (!oppRayI.intersectRay(this->fCurve, oppLine)) {
1168*c8dee2aaSAndroid Build Coastguard Worker break;
1169*c8dee2aaSAndroid Build Coastguard Worker }
1170*c8dee2aaSAndroid Build Coastguard Worker } while (true);
1171*c8dee2aaSAndroid Build Coastguard Worker // convergence may fail if the curves are nearly coincident
1172*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident oCoinS, oCoinE;
1173*c8dee2aaSAndroid Build Coastguard Worker oCoinS.setPerp(opp->fCurve, oppSpan->fStartT, oppSpan->pointFirst(), fCurve);
1174*c8dee2aaSAndroid Build Coastguard Worker oCoinE.setPerp(opp->fCurve, oppSpan->fEndT, oppSpan->pointLast(), fCurve);
1175*c8dee2aaSAndroid Build Coastguard Worker double tStart = oCoinS.perpT();
1176*c8dee2aaSAndroid Build Coastguard Worker double tEnd = oCoinE.perpT();
1177*c8dee2aaSAndroid Build Coastguard Worker bool swap = tStart > tEnd;
1178*c8dee2aaSAndroid Build Coastguard Worker if (swap) {
1179*c8dee2aaSAndroid Build Coastguard Worker using std::swap;
1180*c8dee2aaSAndroid Build Coastguard Worker swap(tStart, tEnd);
1181*c8dee2aaSAndroid Build Coastguard Worker }
1182*c8dee2aaSAndroid Build Coastguard Worker tStart = std::max(tStart, span->fStartT);
1183*c8dee2aaSAndroid Build Coastguard Worker tEnd = std::min(tEnd, span->fEndT);
1184*c8dee2aaSAndroid Build Coastguard Worker if (tStart > tEnd) {
1185*c8dee2aaSAndroid Build Coastguard Worker return 0;
1186*c8dee2aaSAndroid Build Coastguard Worker }
1187*c8dee2aaSAndroid Build Coastguard Worker SkDVector perpS, perpE;
1188*c8dee2aaSAndroid Build Coastguard Worker if (tStart == span->fStartT) {
1189*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident coinS;
1190*c8dee2aaSAndroid Build Coastguard Worker coinS.setPerp(fCurve, span->fStartT, span->pointFirst(), opp->fCurve);
1191*c8dee2aaSAndroid Build Coastguard Worker perpS = span->pointFirst() - coinS.perpPt();
1192*c8dee2aaSAndroid Build Coastguard Worker } else if (swap) {
1193*c8dee2aaSAndroid Build Coastguard Worker perpS = oCoinE.perpPt() - oppSpan->pointLast();
1194*c8dee2aaSAndroid Build Coastguard Worker } else {
1195*c8dee2aaSAndroid Build Coastguard Worker perpS = oCoinS.perpPt() - oppSpan->pointFirst();
1196*c8dee2aaSAndroid Build Coastguard Worker }
1197*c8dee2aaSAndroid Build Coastguard Worker if (tEnd == span->fEndT) {
1198*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident coinE;
1199*c8dee2aaSAndroid Build Coastguard Worker coinE.setPerp(fCurve, span->fEndT, span->pointLast(), opp->fCurve);
1200*c8dee2aaSAndroid Build Coastguard Worker perpE = span->pointLast() - coinE.perpPt();
1201*c8dee2aaSAndroid Build Coastguard Worker } else if (swap) {
1202*c8dee2aaSAndroid Build Coastguard Worker perpE = oCoinS.perpPt() - oppSpan->pointFirst();
1203*c8dee2aaSAndroid Build Coastguard Worker } else {
1204*c8dee2aaSAndroid Build Coastguard Worker perpE = oCoinE.perpPt() - oppSpan->pointLast();
1205*c8dee2aaSAndroid Build Coastguard Worker }
1206*c8dee2aaSAndroid Build Coastguard Worker if (perpS.dot(perpE) >= 0) {
1207*c8dee2aaSAndroid Build Coastguard Worker return 0;
1208*c8dee2aaSAndroid Build Coastguard Worker }
1209*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident coinW;
1210*c8dee2aaSAndroid Build Coastguard Worker double workT = tStart;
1211*c8dee2aaSAndroid Build Coastguard Worker double tStep = tEnd - tStart;
1212*c8dee2aaSAndroid Build Coastguard Worker SkDPoint workPt;
1213*c8dee2aaSAndroid Build Coastguard Worker do {
1214*c8dee2aaSAndroid Build Coastguard Worker tStep *= 0.5;
1215*c8dee2aaSAndroid Build Coastguard Worker if (precisely_zero(tStep)) {
1216*c8dee2aaSAndroid Build Coastguard Worker return 0;
1217*c8dee2aaSAndroid Build Coastguard Worker }
1218*c8dee2aaSAndroid Build Coastguard Worker workT += tStep;
1219*c8dee2aaSAndroid Build Coastguard Worker workPt = fCurve.ptAtT(workT);
1220*c8dee2aaSAndroid Build Coastguard Worker coinW.setPerp(fCurve, workT, workPt, opp->fCurve);
1221*c8dee2aaSAndroid Build Coastguard Worker double perpT = coinW.perpT();
1222*c8dee2aaSAndroid Build Coastguard Worker if (coinW.isMatch() ? !between(oppSpan->fStartT, perpT, oppSpan->fEndT) : perpT < 0) {
1223*c8dee2aaSAndroid Build Coastguard Worker continue;
1224*c8dee2aaSAndroid Build Coastguard Worker }
1225*c8dee2aaSAndroid Build Coastguard Worker SkDVector perpW = workPt - coinW.perpPt();
1226*c8dee2aaSAndroid Build Coastguard Worker if ((perpS.dot(perpW) >= 0) == (tStep < 0)) {
1227*c8dee2aaSAndroid Build Coastguard Worker tStep = -tStep;
1228*c8dee2aaSAndroid Build Coastguard Worker }
1229*c8dee2aaSAndroid Build Coastguard Worker if (workPt.approximatelyEqual(coinW.perpPt())) {
1230*c8dee2aaSAndroid Build Coastguard Worker break;
1231*c8dee2aaSAndroid Build Coastguard Worker }
1232*c8dee2aaSAndroid Build Coastguard Worker } while (true);
1233*c8dee2aaSAndroid Build Coastguard Worker double oppTTest = coinW.perpT();
1234*c8dee2aaSAndroid Build Coastguard Worker if (!opp->fHead->contains(oppTTest)) {
1235*c8dee2aaSAndroid Build Coastguard Worker return 0;
1236*c8dee2aaSAndroid Build Coastguard Worker }
1237*c8dee2aaSAndroid Build Coastguard Worker i->setMax(1);
1238*c8dee2aaSAndroid Build Coastguard Worker i->insert(workT, oppTTest, workPt);
1239*c8dee2aaSAndroid Build Coastguard Worker return 1;
1240*c8dee2aaSAndroid Build Coastguard Worker }
1241*c8dee2aaSAndroid Build Coastguard Worker
markSpanGone(SkTSpan * span)1242*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::markSpanGone(SkTSpan* span) {
1243*c8dee2aaSAndroid Build Coastguard Worker if (--fActiveCount < 0) {
1244*c8dee2aaSAndroid Build Coastguard Worker return false;
1245*c8dee2aaSAndroid Build Coastguard Worker }
1246*c8dee2aaSAndroid Build Coastguard Worker span->fNext = fDeleted;
1247*c8dee2aaSAndroid Build Coastguard Worker fDeleted = span;
1248*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(!span->fDeleted);
1249*c8dee2aaSAndroid Build Coastguard Worker span->fDeleted = true;
1250*c8dee2aaSAndroid Build Coastguard Worker return true;
1251*c8dee2aaSAndroid Build Coastguard Worker }
1252*c8dee2aaSAndroid Build Coastguard Worker
matchedDirection(double t,const SkTSect * sect2,double t2) const1253*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::matchedDirection(double t, const SkTSect* sect2,
1254*c8dee2aaSAndroid Build Coastguard Worker double t2) const {
1255*c8dee2aaSAndroid Build Coastguard Worker SkDVector dxdy = this->fCurve.dxdyAtT(t);
1256*c8dee2aaSAndroid Build Coastguard Worker SkDVector dxdy2 = sect2->fCurve.dxdyAtT(t2);
1257*c8dee2aaSAndroid Build Coastguard Worker return dxdy.dot(dxdy2) >= 0;
1258*c8dee2aaSAndroid Build Coastguard Worker }
1259*c8dee2aaSAndroid Build Coastguard Worker
matchedDirCheck(double t,const SkTSect * sect2,double t2,bool * calcMatched,bool * oppMatched) const1260*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::matchedDirCheck(double t, const SkTSect* sect2,
1261*c8dee2aaSAndroid Build Coastguard Worker double t2, bool* calcMatched, bool* oppMatched) const {
1262*c8dee2aaSAndroid Build Coastguard Worker if (*calcMatched) {
1263*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(*oppMatched == this->matchedDirection(t, sect2, t2));
1264*c8dee2aaSAndroid Build Coastguard Worker } else {
1265*c8dee2aaSAndroid Build Coastguard Worker *oppMatched = this->matchedDirection(t, sect2, t2);
1266*c8dee2aaSAndroid Build Coastguard Worker *calcMatched = true;
1267*c8dee2aaSAndroid Build Coastguard Worker }
1268*c8dee2aaSAndroid Build Coastguard Worker }
1269*c8dee2aaSAndroid Build Coastguard Worker
mergeCoincidence(SkTSect * sect2)1270*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::mergeCoincidence(SkTSect* sect2) {
1271*c8dee2aaSAndroid Build Coastguard Worker double smallLimit = 0;
1272*c8dee2aaSAndroid Build Coastguard Worker do {
1273*c8dee2aaSAndroid Build Coastguard Worker // find the smallest unprocessed span
1274*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* smaller = nullptr;
1275*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = fCoincident;
1276*c8dee2aaSAndroid Build Coastguard Worker do {
1277*c8dee2aaSAndroid Build Coastguard Worker if (!test) {
1278*c8dee2aaSAndroid Build Coastguard Worker return;
1279*c8dee2aaSAndroid Build Coastguard Worker }
1280*c8dee2aaSAndroid Build Coastguard Worker if (test->fStartT < smallLimit) {
1281*c8dee2aaSAndroid Build Coastguard Worker continue;
1282*c8dee2aaSAndroid Build Coastguard Worker }
1283*c8dee2aaSAndroid Build Coastguard Worker if (smaller && smaller->fEndT < test->fStartT) {
1284*c8dee2aaSAndroid Build Coastguard Worker continue;
1285*c8dee2aaSAndroid Build Coastguard Worker }
1286*c8dee2aaSAndroid Build Coastguard Worker smaller = test;
1287*c8dee2aaSAndroid Build Coastguard Worker } while ((test = test->fNext));
1288*c8dee2aaSAndroid Build Coastguard Worker if (!smaller) {
1289*c8dee2aaSAndroid Build Coastguard Worker return;
1290*c8dee2aaSAndroid Build Coastguard Worker }
1291*c8dee2aaSAndroid Build Coastguard Worker smallLimit = smaller->fEndT;
1292*c8dee2aaSAndroid Build Coastguard Worker // find next larger span
1293*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* prior = nullptr;
1294*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* larger = nullptr;
1295*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* largerPrior = nullptr;
1296*c8dee2aaSAndroid Build Coastguard Worker test = fCoincident;
1297*c8dee2aaSAndroid Build Coastguard Worker do {
1298*c8dee2aaSAndroid Build Coastguard Worker if (test->fStartT < smaller->fEndT) {
1299*c8dee2aaSAndroid Build Coastguard Worker continue;
1300*c8dee2aaSAndroid Build Coastguard Worker }
1301*c8dee2aaSAndroid Build Coastguard Worker SkOPASSERT(test->fStartT != smaller->fEndT);
1302*c8dee2aaSAndroid Build Coastguard Worker if (larger && larger->fStartT < test->fStartT) {
1303*c8dee2aaSAndroid Build Coastguard Worker continue;
1304*c8dee2aaSAndroid Build Coastguard Worker }
1305*c8dee2aaSAndroid Build Coastguard Worker largerPrior = prior;
1306*c8dee2aaSAndroid Build Coastguard Worker larger = test;
1307*c8dee2aaSAndroid Build Coastguard Worker } while ((void) (prior = test), (test = test->fNext));
1308*c8dee2aaSAndroid Build Coastguard Worker if (!larger) {
1309*c8dee2aaSAndroid Build Coastguard Worker continue;
1310*c8dee2aaSAndroid Build Coastguard Worker }
1311*c8dee2aaSAndroid Build Coastguard Worker // check middle t value to see if it is coincident as well
1312*c8dee2aaSAndroid Build Coastguard Worker double midT = (smaller->fEndT + larger->fStartT) / 2;
1313*c8dee2aaSAndroid Build Coastguard Worker SkDPoint midPt = fCurve.ptAtT(midT);
1314*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident coin;
1315*c8dee2aaSAndroid Build Coastguard Worker coin.setPerp(fCurve, midT, midPt, sect2->fCurve);
1316*c8dee2aaSAndroid Build Coastguard Worker if (coin.isMatch()) {
1317*c8dee2aaSAndroid Build Coastguard Worker smaller->fEndT = larger->fEndT;
1318*c8dee2aaSAndroid Build Coastguard Worker smaller->fCoinEnd = larger->fCoinEnd;
1319*c8dee2aaSAndroid Build Coastguard Worker if (largerPrior) {
1320*c8dee2aaSAndroid Build Coastguard Worker largerPrior->fNext = larger->fNext;
1321*c8dee2aaSAndroid Build Coastguard Worker largerPrior->validate();
1322*c8dee2aaSAndroid Build Coastguard Worker } else {
1323*c8dee2aaSAndroid Build Coastguard Worker fCoincident = larger->fNext;
1324*c8dee2aaSAndroid Build Coastguard Worker }
1325*c8dee2aaSAndroid Build Coastguard Worker }
1326*c8dee2aaSAndroid Build Coastguard Worker } while (true);
1327*c8dee2aaSAndroid Build Coastguard Worker }
1328*c8dee2aaSAndroid Build Coastguard Worker
prev(SkTSpan * span) const1329*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSect::prev(
1330*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* span) const {
1331*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* result = nullptr;
1332*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = fHead;
1333*c8dee2aaSAndroid Build Coastguard Worker while (span != test) {
1334*c8dee2aaSAndroid Build Coastguard Worker result = test;
1335*c8dee2aaSAndroid Build Coastguard Worker test = test->fNext;
1336*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(test);
1337*c8dee2aaSAndroid Build Coastguard Worker }
1338*c8dee2aaSAndroid Build Coastguard Worker return result;
1339*c8dee2aaSAndroid Build Coastguard Worker }
1340*c8dee2aaSAndroid Build Coastguard Worker
recoverCollapsed()1341*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::recoverCollapsed() {
1342*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* deleted = fDeleted;
1343*c8dee2aaSAndroid Build Coastguard Worker while (deleted) {
1344*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* delNext = deleted->fNext;
1345*c8dee2aaSAndroid Build Coastguard Worker if (deleted->fCollapsed) {
1346*c8dee2aaSAndroid Build Coastguard Worker SkTSpan** spanPtr = &fHead;
1347*c8dee2aaSAndroid Build Coastguard Worker while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) {
1348*c8dee2aaSAndroid Build Coastguard Worker spanPtr = &(*spanPtr)->fNext;
1349*c8dee2aaSAndroid Build Coastguard Worker }
1350*c8dee2aaSAndroid Build Coastguard Worker deleted->fNext = *spanPtr;
1351*c8dee2aaSAndroid Build Coastguard Worker *spanPtr = deleted;
1352*c8dee2aaSAndroid Build Coastguard Worker }
1353*c8dee2aaSAndroid Build Coastguard Worker deleted = delNext;
1354*c8dee2aaSAndroid Build Coastguard Worker }
1355*c8dee2aaSAndroid Build Coastguard Worker }
1356*c8dee2aaSAndroid Build Coastguard Worker
removeAllBut(const SkTSpan * keep,SkTSpan * span,SkTSect * opp)1357*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::removeAllBut(const SkTSpan* keep,
1358*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* span, SkTSect* opp) {
1359*c8dee2aaSAndroid Build Coastguard Worker const SkTSpanBounded* testBounded = span->fBounded;
1360*c8dee2aaSAndroid Build Coastguard Worker while (testBounded) {
1361*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* bounded = testBounded->fBounded;
1362*c8dee2aaSAndroid Build Coastguard Worker const SkTSpanBounded* next = testBounded->fNext;
1363*c8dee2aaSAndroid Build Coastguard Worker // may have been deleted when opp did 'remove all but'
1364*c8dee2aaSAndroid Build Coastguard Worker if (bounded != keep && !bounded->fDeleted) {
1365*c8dee2aaSAndroid Build Coastguard Worker SkAssertResult(SkDEBUGCODE(!) span->removeBounded(bounded));
1366*c8dee2aaSAndroid Build Coastguard Worker if (bounded->removeBounded(span)) {
1367*c8dee2aaSAndroid Build Coastguard Worker opp->removeSpan(bounded);
1368*c8dee2aaSAndroid Build Coastguard Worker }
1369*c8dee2aaSAndroid Build Coastguard Worker }
1370*c8dee2aaSAndroid Build Coastguard Worker testBounded = next;
1371*c8dee2aaSAndroid Build Coastguard Worker }
1372*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!span->fDeleted);
1373*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(span->findOppSpan(keep));
1374*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(keep->findOppSpan(span));
1375*c8dee2aaSAndroid Build Coastguard Worker }
1376*c8dee2aaSAndroid Build Coastguard Worker
removeByPerpendicular(SkTSect * opp)1377*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::removeByPerpendicular(SkTSect* opp) {
1378*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = fHead;
1379*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* next;
1380*c8dee2aaSAndroid Build Coastguard Worker do {
1381*c8dee2aaSAndroid Build Coastguard Worker next = test->fNext;
1382*c8dee2aaSAndroid Build Coastguard Worker if (test->fCoinStart.perpT() < 0 || test->fCoinEnd.perpT() < 0) {
1383*c8dee2aaSAndroid Build Coastguard Worker continue;
1384*c8dee2aaSAndroid Build Coastguard Worker }
1385*c8dee2aaSAndroid Build Coastguard Worker SkDVector startV = test->fCoinStart.perpPt() - test->pointFirst();
1386*c8dee2aaSAndroid Build Coastguard Worker SkDVector endV = test->fCoinEnd.perpPt() - test->pointLast();
1387*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
1388*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s startV=(%1.9g,%1.9g) endV=(%1.9g,%1.9g) dot=%1.9g\n", __FUNCTION__,
1389*c8dee2aaSAndroid Build Coastguard Worker startV.fX, startV.fY, endV.fX, endV.fY, startV.dot(endV));
1390*c8dee2aaSAndroid Build Coastguard Worker #endif
1391*c8dee2aaSAndroid Build Coastguard Worker if (startV.dot(endV) <= 0) {
1392*c8dee2aaSAndroid Build Coastguard Worker continue;
1393*c8dee2aaSAndroid Build Coastguard Worker }
1394*c8dee2aaSAndroid Build Coastguard Worker if (!this->removeSpans(test, opp)) {
1395*c8dee2aaSAndroid Build Coastguard Worker return false;
1396*c8dee2aaSAndroid Build Coastguard Worker }
1397*c8dee2aaSAndroid Build Coastguard Worker } while ((test = next));
1398*c8dee2aaSAndroid Build Coastguard Worker return true;
1399*c8dee2aaSAndroid Build Coastguard Worker }
1400*c8dee2aaSAndroid Build Coastguard Worker
removeCoincident(SkTSpan * span,bool isBetween)1401*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::removeCoincident(SkTSpan* span, bool isBetween) {
1402*c8dee2aaSAndroid Build Coastguard Worker if (!this->unlinkSpan(span)) {
1403*c8dee2aaSAndroid Build Coastguard Worker return false;
1404*c8dee2aaSAndroid Build Coastguard Worker }
1405*c8dee2aaSAndroid Build Coastguard Worker if (isBetween || between(0, span->fCoinStart.perpT(), 1)) {
1406*c8dee2aaSAndroid Build Coastguard Worker --fActiveCount;
1407*c8dee2aaSAndroid Build Coastguard Worker span->fNext = fCoincident;
1408*c8dee2aaSAndroid Build Coastguard Worker fCoincident = span;
1409*c8dee2aaSAndroid Build Coastguard Worker } else {
1410*c8dee2aaSAndroid Build Coastguard Worker this->markSpanGone(span);
1411*c8dee2aaSAndroid Build Coastguard Worker }
1412*c8dee2aaSAndroid Build Coastguard Worker return true;
1413*c8dee2aaSAndroid Build Coastguard Worker }
1414*c8dee2aaSAndroid Build Coastguard Worker
removedEndCheck(SkTSpan * span)1415*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::removedEndCheck(SkTSpan* span) {
1416*c8dee2aaSAndroid Build Coastguard Worker if (!span->fStartT) {
1417*c8dee2aaSAndroid Build Coastguard Worker fRemovedStartT = true;
1418*c8dee2aaSAndroid Build Coastguard Worker }
1419*c8dee2aaSAndroid Build Coastguard Worker if (1 == span->fEndT) {
1420*c8dee2aaSAndroid Build Coastguard Worker fRemovedEndT = true;
1421*c8dee2aaSAndroid Build Coastguard Worker }
1422*c8dee2aaSAndroid Build Coastguard Worker }
1423*c8dee2aaSAndroid Build Coastguard Worker
removeSpan(SkTSpan * span)1424*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::removeSpan(SkTSpan* span) {\
1425*c8dee2aaSAndroid Build Coastguard Worker this->removedEndCheck(span);
1426*c8dee2aaSAndroid Build Coastguard Worker if (!this->unlinkSpan(span)) {
1427*c8dee2aaSAndroid Build Coastguard Worker return false;
1428*c8dee2aaSAndroid Build Coastguard Worker }
1429*c8dee2aaSAndroid Build Coastguard Worker return this->markSpanGone(span);
1430*c8dee2aaSAndroid Build Coastguard Worker }
1431*c8dee2aaSAndroid Build Coastguard Worker
removeSpanRange(SkTSpan * first,SkTSpan * last)1432*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::removeSpanRange(SkTSpan* first,
1433*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* last) {
1434*c8dee2aaSAndroid Build Coastguard Worker if (first == last) {
1435*c8dee2aaSAndroid Build Coastguard Worker return;
1436*c8dee2aaSAndroid Build Coastguard Worker }
1437*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* span = first;
1438*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(span);
1439*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* final = last->fNext;
1440*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* next = span->fNext;
1441*c8dee2aaSAndroid Build Coastguard Worker while ((span = next) && span != final) {
1442*c8dee2aaSAndroid Build Coastguard Worker next = span->fNext;
1443*c8dee2aaSAndroid Build Coastguard Worker this->markSpanGone(span);
1444*c8dee2aaSAndroid Build Coastguard Worker }
1445*c8dee2aaSAndroid Build Coastguard Worker if (final) {
1446*c8dee2aaSAndroid Build Coastguard Worker final->fPrev = first;
1447*c8dee2aaSAndroid Build Coastguard Worker }
1448*c8dee2aaSAndroid Build Coastguard Worker first->fNext = final;
1449*c8dee2aaSAndroid Build Coastguard Worker // world may not be ready for validation here
1450*c8dee2aaSAndroid Build Coastguard Worker first->validate();
1451*c8dee2aaSAndroid Build Coastguard Worker }
1452*c8dee2aaSAndroid Build Coastguard Worker
removeSpans(SkTSpan * span,SkTSect * opp)1453*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::removeSpans(SkTSpan* span,
1454*c8dee2aaSAndroid Build Coastguard Worker SkTSect* opp) {
1455*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* bounded = span->fBounded;
1456*c8dee2aaSAndroid Build Coastguard Worker while (bounded) {
1457*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* spanBounded = bounded->fBounded;
1458*c8dee2aaSAndroid Build Coastguard Worker SkTSpanBounded* next = bounded->fNext;
1459*c8dee2aaSAndroid Build Coastguard Worker if (span->removeBounded(spanBounded)) { // shuffles last into position 0
1460*c8dee2aaSAndroid Build Coastguard Worker this->removeSpan(span);
1461*c8dee2aaSAndroid Build Coastguard Worker }
1462*c8dee2aaSAndroid Build Coastguard Worker if (spanBounded->removeBounded(span)) {
1463*c8dee2aaSAndroid Build Coastguard Worker opp->removeSpan(spanBounded);
1464*c8dee2aaSAndroid Build Coastguard Worker }
1465*c8dee2aaSAndroid Build Coastguard Worker if (span->fDeleted && opp->hasBounded(span)) {
1466*c8dee2aaSAndroid Build Coastguard Worker return false;
1467*c8dee2aaSAndroid Build Coastguard Worker }
1468*c8dee2aaSAndroid Build Coastguard Worker bounded = next;
1469*c8dee2aaSAndroid Build Coastguard Worker }
1470*c8dee2aaSAndroid Build Coastguard Worker return true;
1471*c8dee2aaSAndroid Build Coastguard Worker }
1472*c8dee2aaSAndroid Build Coastguard Worker
spanAtT(double t,SkTSpan ** priorSpan)1473*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSect::spanAtT(double t,
1474*c8dee2aaSAndroid Build Coastguard Worker SkTSpan** priorSpan) {
1475*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = fHead;
1476*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* prev = nullptr;
1477*c8dee2aaSAndroid Build Coastguard Worker while (test && test->fEndT < t) {
1478*c8dee2aaSAndroid Build Coastguard Worker prev = test;
1479*c8dee2aaSAndroid Build Coastguard Worker test = test->fNext;
1480*c8dee2aaSAndroid Build Coastguard Worker }
1481*c8dee2aaSAndroid Build Coastguard Worker *priorSpan = prev;
1482*c8dee2aaSAndroid Build Coastguard Worker return test && test->fStartT <= t ? test : nullptr;
1483*c8dee2aaSAndroid Build Coastguard Worker }
1484*c8dee2aaSAndroid Build Coastguard Worker
tail()1485*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* SkTSect::tail() {
1486*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* result = fHead;
1487*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* next = fHead;
1488*c8dee2aaSAndroid Build Coastguard Worker int safetyNet = 100000;
1489*c8dee2aaSAndroid Build Coastguard Worker while ((next = next->fNext)) {
1490*c8dee2aaSAndroid Build Coastguard Worker if (!--safetyNet) {
1491*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
1492*c8dee2aaSAndroid Build Coastguard Worker }
1493*c8dee2aaSAndroid Build Coastguard Worker if (next->fEndT > result->fEndT) {
1494*c8dee2aaSAndroid Build Coastguard Worker result = next;
1495*c8dee2aaSAndroid Build Coastguard Worker }
1496*c8dee2aaSAndroid Build Coastguard Worker }
1497*c8dee2aaSAndroid Build Coastguard Worker return result;
1498*c8dee2aaSAndroid Build Coastguard Worker }
1499*c8dee2aaSAndroid Build Coastguard Worker
1500*c8dee2aaSAndroid Build Coastguard Worker /* Each span has a range of opposite spans it intersects. After the span is split in two,
1501*c8dee2aaSAndroid Build Coastguard Worker adjust the range to its new size */
1502*c8dee2aaSAndroid Build Coastguard Worker
trim(SkTSpan * span,SkTSect * opp)1503*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::trim(SkTSpan* span,
1504*c8dee2aaSAndroid Build Coastguard Worker SkTSect* opp) {
1505*c8dee2aaSAndroid Build Coastguard Worker FAIL_IF(!span->initBounds(fCurve));
1506*c8dee2aaSAndroid Build Coastguard Worker const SkTSpanBounded* testBounded = span->fBounded;
1507*c8dee2aaSAndroid Build Coastguard Worker while (testBounded) {
1508*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = testBounded->fBounded;
1509*c8dee2aaSAndroid Build Coastguard Worker const SkTSpanBounded* next = testBounded->fNext;
1510*c8dee2aaSAndroid Build Coastguard Worker int oppSects, sects = this->intersects(span, opp, test, &oppSects);
1511*c8dee2aaSAndroid Build Coastguard Worker if (sects >= 1) {
1512*c8dee2aaSAndroid Build Coastguard Worker if (oppSects == 2) {
1513*c8dee2aaSAndroid Build Coastguard Worker test->initBounds(opp->fCurve);
1514*c8dee2aaSAndroid Build Coastguard Worker opp->removeAllBut(span, test, this);
1515*c8dee2aaSAndroid Build Coastguard Worker }
1516*c8dee2aaSAndroid Build Coastguard Worker if (sects == 2) {
1517*c8dee2aaSAndroid Build Coastguard Worker span->initBounds(fCurve);
1518*c8dee2aaSAndroid Build Coastguard Worker this->removeAllBut(test, span, opp);
1519*c8dee2aaSAndroid Build Coastguard Worker return true;
1520*c8dee2aaSAndroid Build Coastguard Worker }
1521*c8dee2aaSAndroid Build Coastguard Worker } else {
1522*c8dee2aaSAndroid Build Coastguard Worker if (span->removeBounded(test)) {
1523*c8dee2aaSAndroid Build Coastguard Worker this->removeSpan(span);
1524*c8dee2aaSAndroid Build Coastguard Worker }
1525*c8dee2aaSAndroid Build Coastguard Worker if (test->removeBounded(span)) {
1526*c8dee2aaSAndroid Build Coastguard Worker opp->removeSpan(test);
1527*c8dee2aaSAndroid Build Coastguard Worker }
1528*c8dee2aaSAndroid Build Coastguard Worker }
1529*c8dee2aaSAndroid Build Coastguard Worker testBounded = next;
1530*c8dee2aaSAndroid Build Coastguard Worker }
1531*c8dee2aaSAndroid Build Coastguard Worker return true;
1532*c8dee2aaSAndroid Build Coastguard Worker }
1533*c8dee2aaSAndroid Build Coastguard Worker
unlinkSpan(SkTSpan * span)1534*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::unlinkSpan(SkTSpan* span) {
1535*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* prev = span->fPrev;
1536*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* next = span->fNext;
1537*c8dee2aaSAndroid Build Coastguard Worker if (prev) {
1538*c8dee2aaSAndroid Build Coastguard Worker prev->fNext = next;
1539*c8dee2aaSAndroid Build Coastguard Worker if (next) {
1540*c8dee2aaSAndroid Build Coastguard Worker next->fPrev = prev;
1541*c8dee2aaSAndroid Build Coastguard Worker if (next->fStartT > next->fEndT) {
1542*c8dee2aaSAndroid Build Coastguard Worker return false;
1543*c8dee2aaSAndroid Build Coastguard Worker }
1544*c8dee2aaSAndroid Build Coastguard Worker // world may not be ready for validate here
1545*c8dee2aaSAndroid Build Coastguard Worker next->validate();
1546*c8dee2aaSAndroid Build Coastguard Worker }
1547*c8dee2aaSAndroid Build Coastguard Worker } else {
1548*c8dee2aaSAndroid Build Coastguard Worker fHead = next;
1549*c8dee2aaSAndroid Build Coastguard Worker if (next) {
1550*c8dee2aaSAndroid Build Coastguard Worker next->fPrev = nullptr;
1551*c8dee2aaSAndroid Build Coastguard Worker }
1552*c8dee2aaSAndroid Build Coastguard Worker }
1553*c8dee2aaSAndroid Build Coastguard Worker return true;
1554*c8dee2aaSAndroid Build Coastguard Worker }
1555*c8dee2aaSAndroid Build Coastguard Worker
updateBounded(SkTSpan * first,SkTSpan * last,SkTSpan * oppFirst)1556*c8dee2aaSAndroid Build Coastguard Worker bool SkTSect::updateBounded(SkTSpan* first,
1557*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* last, SkTSpan* oppFirst) {
1558*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* test = first;
1559*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* final = last->next();
1560*c8dee2aaSAndroid Build Coastguard Worker bool deleteSpan = false;
1561*c8dee2aaSAndroid Build Coastguard Worker do {
1562*c8dee2aaSAndroid Build Coastguard Worker deleteSpan |= test->removeAllBounded();
1563*c8dee2aaSAndroid Build Coastguard Worker } while ((test = test->fNext) != final && test);
1564*c8dee2aaSAndroid Build Coastguard Worker first->fBounded = nullptr;
1565*c8dee2aaSAndroid Build Coastguard Worker first->addBounded(oppFirst, &fHeap);
1566*c8dee2aaSAndroid Build Coastguard Worker // cannot call validate until remove span range is called
1567*c8dee2aaSAndroid Build Coastguard Worker return deleteSpan;
1568*c8dee2aaSAndroid Build Coastguard Worker }
1569*c8dee2aaSAndroid Build Coastguard Worker
validate() const1570*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::validate() const {
1571*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_VALIDATE
1572*c8dee2aaSAndroid Build Coastguard Worker int count = 0;
1573*c8dee2aaSAndroid Build Coastguard Worker double last = 0;
1574*c8dee2aaSAndroid Build Coastguard Worker if (fHead) {
1575*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* span = fHead;
1576*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!span->fPrev);
1577*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* next;
1578*c8dee2aaSAndroid Build Coastguard Worker do {
1579*c8dee2aaSAndroid Build Coastguard Worker span->validate();
1580*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(span->fStartT >= last);
1581*c8dee2aaSAndroid Build Coastguard Worker last = span->fEndT;
1582*c8dee2aaSAndroid Build Coastguard Worker ++count;
1583*c8dee2aaSAndroid Build Coastguard Worker next = span->fNext;
1584*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(next != span);
1585*c8dee2aaSAndroid Build Coastguard Worker } while ((span = next) != nullptr);
1586*c8dee2aaSAndroid Build Coastguard Worker }
1587*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(count == fActiveCount);
1588*c8dee2aaSAndroid Build Coastguard Worker #endif
1589*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT
1590*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fActiveCount <= fDebugAllocatedCount);
1591*c8dee2aaSAndroid Build Coastguard Worker int deletedCount = 0;
1592*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* deleted = fDeleted;
1593*c8dee2aaSAndroid Build Coastguard Worker while (deleted) {
1594*c8dee2aaSAndroid Build Coastguard Worker ++deletedCount;
1595*c8dee2aaSAndroid Build Coastguard Worker deleted = deleted->fNext;
1596*c8dee2aaSAndroid Build Coastguard Worker }
1597*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* coincident = fCoincident;
1598*c8dee2aaSAndroid Build Coastguard Worker while (coincident) {
1599*c8dee2aaSAndroid Build Coastguard Worker ++deletedCount;
1600*c8dee2aaSAndroid Build Coastguard Worker coincident = coincident->fNext;
1601*c8dee2aaSAndroid Build Coastguard Worker }
1602*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount);
1603*c8dee2aaSAndroid Build Coastguard Worker #endif
1604*c8dee2aaSAndroid Build Coastguard Worker }
1605*c8dee2aaSAndroid Build Coastguard Worker
validateBounded() const1606*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::validateBounded() const {
1607*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_VALIDATE
1608*c8dee2aaSAndroid Build Coastguard Worker if (!fHead) {
1609*c8dee2aaSAndroid Build Coastguard Worker return;
1610*c8dee2aaSAndroid Build Coastguard Worker }
1611*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* span = fHead;
1612*c8dee2aaSAndroid Build Coastguard Worker do {
1613*c8dee2aaSAndroid Build Coastguard Worker span->validateBounded();
1614*c8dee2aaSAndroid Build Coastguard Worker } while ((span = span->fNext) != nullptr);
1615*c8dee2aaSAndroid Build Coastguard Worker #endif
1616*c8dee2aaSAndroid Build Coastguard Worker }
1617*c8dee2aaSAndroid Build Coastguard Worker
EndsEqual(const SkTSect * sect1,const SkTSect * sect2,SkIntersections * intersections)1618*c8dee2aaSAndroid Build Coastguard Worker int SkTSect::EndsEqual(const SkTSect* sect1,
1619*c8dee2aaSAndroid Build Coastguard Worker const SkTSect* sect2, SkIntersections* intersections) {
1620*c8dee2aaSAndroid Build Coastguard Worker int zeroOneSet = 0;
1621*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fCurve[0] == sect2->fCurve[0]) {
1622*c8dee2aaSAndroid Build Coastguard Worker zeroOneSet |= kZeroS1Set | kZeroS2Set;
1623*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(0, 0, sect1->fCurve[0]);
1624*c8dee2aaSAndroid Build Coastguard Worker }
1625*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fCurve[0] == sect2->pointLast()) {
1626*c8dee2aaSAndroid Build Coastguard Worker zeroOneSet |= kZeroS1Set | kOneS2Set;
1627*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(0, 1, sect1->fCurve[0]);
1628*c8dee2aaSAndroid Build Coastguard Worker }
1629*c8dee2aaSAndroid Build Coastguard Worker if (sect1->pointLast() == sect2->fCurve[0]) {
1630*c8dee2aaSAndroid Build Coastguard Worker zeroOneSet |= kOneS1Set | kZeroS2Set;
1631*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(1, 0, sect1->pointLast());
1632*c8dee2aaSAndroid Build Coastguard Worker }
1633*c8dee2aaSAndroid Build Coastguard Worker if (sect1->pointLast() == sect2->pointLast()) {
1634*c8dee2aaSAndroid Build Coastguard Worker zeroOneSet |= kOneS1Set | kOneS2Set;
1635*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(1, 1, sect1->pointLast());
1636*c8dee2aaSAndroid Build Coastguard Worker }
1637*c8dee2aaSAndroid Build Coastguard Worker // check for zero
1638*c8dee2aaSAndroid Build Coastguard Worker if (!(zeroOneSet & (kZeroS1Set | kZeroS2Set))
1639*c8dee2aaSAndroid Build Coastguard Worker && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) {
1640*c8dee2aaSAndroid Build Coastguard Worker zeroOneSet |= kZeroS1Set | kZeroS2Set;
1641*c8dee2aaSAndroid Build Coastguard Worker intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]);
1642*c8dee2aaSAndroid Build Coastguard Worker }
1643*c8dee2aaSAndroid Build Coastguard Worker if (!(zeroOneSet & (kZeroS1Set | kOneS2Set))
1644*c8dee2aaSAndroid Build Coastguard Worker && sect1->fCurve[0].approximatelyEqual(sect2->pointLast())) {
1645*c8dee2aaSAndroid Build Coastguard Worker zeroOneSet |= kZeroS1Set | kOneS2Set;
1646*c8dee2aaSAndroid Build Coastguard Worker intersections->insertNear(0, 1, sect1->fCurve[0], sect2->pointLast());
1647*c8dee2aaSAndroid Build Coastguard Worker }
1648*c8dee2aaSAndroid Build Coastguard Worker // check for one
1649*c8dee2aaSAndroid Build Coastguard Worker if (!(zeroOneSet & (kOneS1Set | kZeroS2Set))
1650*c8dee2aaSAndroid Build Coastguard Worker && sect1->pointLast().approximatelyEqual(sect2->fCurve[0])) {
1651*c8dee2aaSAndroid Build Coastguard Worker zeroOneSet |= kOneS1Set | kZeroS2Set;
1652*c8dee2aaSAndroid Build Coastguard Worker intersections->insertNear(1, 0, sect1->pointLast(), sect2->fCurve[0]);
1653*c8dee2aaSAndroid Build Coastguard Worker }
1654*c8dee2aaSAndroid Build Coastguard Worker if (!(zeroOneSet & (kOneS1Set | kOneS2Set))
1655*c8dee2aaSAndroid Build Coastguard Worker && sect1->pointLast().approximatelyEqual(sect2->pointLast())) {
1656*c8dee2aaSAndroid Build Coastguard Worker zeroOneSet |= kOneS1Set | kOneS2Set;
1657*c8dee2aaSAndroid Build Coastguard Worker intersections->insertNear(1, 1, sect1->pointLast(), sect2->pointLast());
1658*c8dee2aaSAndroid Build Coastguard Worker }
1659*c8dee2aaSAndroid Build Coastguard Worker return zeroOneSet;
1660*c8dee2aaSAndroid Build Coastguard Worker }
1661*c8dee2aaSAndroid Build Coastguard Worker
1662*c8dee2aaSAndroid Build Coastguard Worker struct SkClosestRecord {
operator <SkClosestRecord1663*c8dee2aaSAndroid Build Coastguard Worker bool operator<(const SkClosestRecord& rh) const {
1664*c8dee2aaSAndroid Build Coastguard Worker return fClosest < rh.fClosest;
1665*c8dee2aaSAndroid Build Coastguard Worker }
1666*c8dee2aaSAndroid Build Coastguard Worker
addIntersectionSkClosestRecord1667*c8dee2aaSAndroid Build Coastguard Worker void addIntersection(SkIntersections* intersections) const {
1668*c8dee2aaSAndroid Build Coastguard Worker double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT();
1669*c8dee2aaSAndroid Build Coastguard Worker double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT();
1670*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]);
1671*c8dee2aaSAndroid Build Coastguard Worker }
1672*c8dee2aaSAndroid Build Coastguard Worker
findEndSkClosestRecord1673*c8dee2aaSAndroid Build Coastguard Worker void findEnd(const SkTSpan* span1, const SkTSpan* span2,
1674*c8dee2aaSAndroid Build Coastguard Worker int c1Index, int c2Index) {
1675*c8dee2aaSAndroid Build Coastguard Worker const SkTCurve& c1 = span1->part();
1676*c8dee2aaSAndroid Build Coastguard Worker const SkTCurve& c2 = span2->part();
1677*c8dee2aaSAndroid Build Coastguard Worker if (!c1[c1Index].approximatelyEqual(c2[c2Index])) {
1678*c8dee2aaSAndroid Build Coastguard Worker return;
1679*c8dee2aaSAndroid Build Coastguard Worker }
1680*c8dee2aaSAndroid Build Coastguard Worker double dist = c1[c1Index].distanceSquared(c2[c2Index]);
1681*c8dee2aaSAndroid Build Coastguard Worker if (fClosest < dist) {
1682*c8dee2aaSAndroid Build Coastguard Worker return;
1683*c8dee2aaSAndroid Build Coastguard Worker }
1684*c8dee2aaSAndroid Build Coastguard Worker fC1Span = span1;
1685*c8dee2aaSAndroid Build Coastguard Worker fC2Span = span2;
1686*c8dee2aaSAndroid Build Coastguard Worker fC1StartT = span1->startT();
1687*c8dee2aaSAndroid Build Coastguard Worker fC1EndT = span1->endT();
1688*c8dee2aaSAndroid Build Coastguard Worker fC2StartT = span2->startT();
1689*c8dee2aaSAndroid Build Coastguard Worker fC2EndT = span2->endT();
1690*c8dee2aaSAndroid Build Coastguard Worker fC1Index = c1Index;
1691*c8dee2aaSAndroid Build Coastguard Worker fC2Index = c2Index;
1692*c8dee2aaSAndroid Build Coastguard Worker fClosest = dist;
1693*c8dee2aaSAndroid Build Coastguard Worker }
1694*c8dee2aaSAndroid Build Coastguard Worker
matesWithSkClosestRecord1695*c8dee2aaSAndroid Build Coastguard Worker bool matesWith(const SkClosestRecord& mate SkDEBUGPARAMS(SkIntersections* i)) const {
1696*c8dee2aaSAndroid Build Coastguard Worker SkOPOBJASSERT(i, fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->startT()
1697*c8dee2aaSAndroid Build Coastguard Worker || mate.fC1Span->endT() <= fC1Span->startT());
1698*c8dee2aaSAndroid Build Coastguard Worker SkOPOBJASSERT(i, fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->startT()
1699*c8dee2aaSAndroid Build Coastguard Worker || mate.fC2Span->endT() <= fC2Span->startT());
1700*c8dee2aaSAndroid Build Coastguard Worker return fC1Span == mate.fC1Span || fC1Span->endT() == mate.fC1Span->startT()
1701*c8dee2aaSAndroid Build Coastguard Worker || fC1Span->startT() == mate.fC1Span->endT()
1702*c8dee2aaSAndroid Build Coastguard Worker || fC2Span == mate.fC2Span
1703*c8dee2aaSAndroid Build Coastguard Worker || fC2Span->endT() == mate.fC2Span->startT()
1704*c8dee2aaSAndroid Build Coastguard Worker || fC2Span->startT() == mate.fC2Span->endT();
1705*c8dee2aaSAndroid Build Coastguard Worker }
1706*c8dee2aaSAndroid Build Coastguard Worker
mergeSkClosestRecord1707*c8dee2aaSAndroid Build Coastguard Worker void merge(const SkClosestRecord& mate) {
1708*c8dee2aaSAndroid Build Coastguard Worker fC1Span = mate.fC1Span;
1709*c8dee2aaSAndroid Build Coastguard Worker fC2Span = mate.fC2Span;
1710*c8dee2aaSAndroid Build Coastguard Worker fClosest = mate.fClosest;
1711*c8dee2aaSAndroid Build Coastguard Worker fC1Index = mate.fC1Index;
1712*c8dee2aaSAndroid Build Coastguard Worker fC2Index = mate.fC2Index;
1713*c8dee2aaSAndroid Build Coastguard Worker }
1714*c8dee2aaSAndroid Build Coastguard Worker
resetSkClosestRecord1715*c8dee2aaSAndroid Build Coastguard Worker void reset() {
1716*c8dee2aaSAndroid Build Coastguard Worker fClosest = FLT_MAX;
1717*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fC1Span = nullptr);
1718*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fC2Span = nullptr);
1719*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fC1Index = fC2Index = -1);
1720*c8dee2aaSAndroid Build Coastguard Worker }
1721*c8dee2aaSAndroid Build Coastguard Worker
updateSkClosestRecord1722*c8dee2aaSAndroid Build Coastguard Worker void update(const SkClosestRecord& mate) {
1723*c8dee2aaSAndroid Build Coastguard Worker fC1StartT = std::min(fC1StartT, mate.fC1StartT);
1724*c8dee2aaSAndroid Build Coastguard Worker fC1EndT = std::max(fC1EndT, mate.fC1EndT);
1725*c8dee2aaSAndroid Build Coastguard Worker fC2StartT = std::min(fC2StartT, mate.fC2StartT);
1726*c8dee2aaSAndroid Build Coastguard Worker fC2EndT = std::max(fC2EndT, mate.fC2EndT);
1727*c8dee2aaSAndroid Build Coastguard Worker }
1728*c8dee2aaSAndroid Build Coastguard Worker
1729*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* fC1Span;
1730*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* fC2Span;
1731*c8dee2aaSAndroid Build Coastguard Worker double fC1StartT;
1732*c8dee2aaSAndroid Build Coastguard Worker double fC1EndT;
1733*c8dee2aaSAndroid Build Coastguard Worker double fC2StartT;
1734*c8dee2aaSAndroid Build Coastguard Worker double fC2EndT;
1735*c8dee2aaSAndroid Build Coastguard Worker double fClosest;
1736*c8dee2aaSAndroid Build Coastguard Worker int fC1Index;
1737*c8dee2aaSAndroid Build Coastguard Worker int fC2Index;
1738*c8dee2aaSAndroid Build Coastguard Worker };
1739*c8dee2aaSAndroid Build Coastguard Worker
1740*c8dee2aaSAndroid Build Coastguard Worker struct SkClosestSect {
SkClosestSectSkClosestSect1741*c8dee2aaSAndroid Build Coastguard Worker SkClosestSect()
1742*c8dee2aaSAndroid Build Coastguard Worker : fUsed(0) {
1743*c8dee2aaSAndroid Build Coastguard Worker fClosest.push_back().reset();
1744*c8dee2aaSAndroid Build Coastguard Worker }
1745*c8dee2aaSAndroid Build Coastguard Worker
findSkClosestSect1746*c8dee2aaSAndroid Build Coastguard Worker bool find(const SkTSpan* span1, const SkTSpan* span2
1747*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGPARAMS(SkIntersections* i)) {
1748*c8dee2aaSAndroid Build Coastguard Worker SkClosestRecord* record = &fClosest[fUsed];
1749*c8dee2aaSAndroid Build Coastguard Worker record->findEnd(span1, span2, 0, 0);
1750*c8dee2aaSAndroid Build Coastguard Worker record->findEnd(span1, span2, 0, span2->part().pointLast());
1751*c8dee2aaSAndroid Build Coastguard Worker record->findEnd(span1, span2, span1->part().pointLast(), 0);
1752*c8dee2aaSAndroid Build Coastguard Worker record->findEnd(span1, span2, span1->part().pointLast(), span2->part().pointLast());
1753*c8dee2aaSAndroid Build Coastguard Worker if (record->fClosest == FLT_MAX) {
1754*c8dee2aaSAndroid Build Coastguard Worker return false;
1755*c8dee2aaSAndroid Build Coastguard Worker }
1756*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < fUsed; ++index) {
1757*c8dee2aaSAndroid Build Coastguard Worker SkClosestRecord* test = &fClosest[index];
1758*c8dee2aaSAndroid Build Coastguard Worker if (test->matesWith(*record SkDEBUGPARAMS(i))) {
1759*c8dee2aaSAndroid Build Coastguard Worker if (test->fClosest > record->fClosest) {
1760*c8dee2aaSAndroid Build Coastguard Worker test->merge(*record);
1761*c8dee2aaSAndroid Build Coastguard Worker }
1762*c8dee2aaSAndroid Build Coastguard Worker test->update(*record);
1763*c8dee2aaSAndroid Build Coastguard Worker record->reset();
1764*c8dee2aaSAndroid Build Coastguard Worker return false;
1765*c8dee2aaSAndroid Build Coastguard Worker }
1766*c8dee2aaSAndroid Build Coastguard Worker }
1767*c8dee2aaSAndroid Build Coastguard Worker ++fUsed;
1768*c8dee2aaSAndroid Build Coastguard Worker fClosest.push_back().reset();
1769*c8dee2aaSAndroid Build Coastguard Worker return true;
1770*c8dee2aaSAndroid Build Coastguard Worker }
1771*c8dee2aaSAndroid Build Coastguard Worker
finishSkClosestSect1772*c8dee2aaSAndroid Build Coastguard Worker void finish(SkIntersections* intersections) const {
1773*c8dee2aaSAndroid Build Coastguard Worker STArray<SkDCubic::kMaxIntersections * 3,
1774*c8dee2aaSAndroid Build Coastguard Worker const SkClosestRecord*, true> closestPtrs;
1775*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < fUsed; ++index) {
1776*c8dee2aaSAndroid Build Coastguard Worker closestPtrs.push_back(&fClosest[index]);
1777*c8dee2aaSAndroid Build Coastguard Worker }
1778*c8dee2aaSAndroid Build Coastguard Worker SkTQSort<const SkClosestRecord>(closestPtrs.begin(), closestPtrs.end());
1779*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < fUsed; ++index) {
1780*c8dee2aaSAndroid Build Coastguard Worker const SkClosestRecord* test = closestPtrs[index];
1781*c8dee2aaSAndroid Build Coastguard Worker test->addIntersection(intersections);
1782*c8dee2aaSAndroid Build Coastguard Worker }
1783*c8dee2aaSAndroid Build Coastguard Worker }
1784*c8dee2aaSAndroid Build Coastguard Worker
1785*c8dee2aaSAndroid Build Coastguard Worker // this is oversized so that an extra records can merge into final one
1786*c8dee2aaSAndroid Build Coastguard Worker STArray<SkDCubic::kMaxIntersections * 2, SkClosestRecord, true> fClosest;
1787*c8dee2aaSAndroid Build Coastguard Worker int fUsed;
1788*c8dee2aaSAndroid Build Coastguard Worker };
1789*c8dee2aaSAndroid Build Coastguard Worker
1790*c8dee2aaSAndroid Build Coastguard Worker // returns true if the rect is too small to consider
1791*c8dee2aaSAndroid Build Coastguard Worker
BinarySearch(SkTSect * sect1,SkTSect * sect2,SkIntersections * intersections)1792*c8dee2aaSAndroid Build Coastguard Worker void SkTSect::BinarySearch(SkTSect* sect1,
1793*c8dee2aaSAndroid Build Coastguard Worker SkTSect* sect2, SkIntersections* intersections) {
1794*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT_DUMP > 1
1795*c8dee2aaSAndroid Build Coastguard Worker gDumpTSectNum = 0;
1796*c8dee2aaSAndroid Build Coastguard Worker #endif
1797*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(sect1->fOppSect = sect2);
1798*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(sect2->fOppSect = sect1);
1799*c8dee2aaSAndroid Build Coastguard Worker intersections->reset();
1800*c8dee2aaSAndroid Build Coastguard Worker intersections->setMax(sect1->fCurve.maxIntersections() + 4); // give extra for slop
1801*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* span1 = sect1->fHead;
1802*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* span2 = sect2->fHead;
1803*c8dee2aaSAndroid Build Coastguard Worker int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect);
1804*c8dee2aaSAndroid Build Coastguard Worker // SkASSERT(between(0, sect, 2));
1805*c8dee2aaSAndroid Build Coastguard Worker if (!sect) {
1806*c8dee2aaSAndroid Build Coastguard Worker return;
1807*c8dee2aaSAndroid Build Coastguard Worker }
1808*c8dee2aaSAndroid Build Coastguard Worker if (sect == 2 && oppSect == 2) {
1809*c8dee2aaSAndroid Build Coastguard Worker (void) EndsEqual(sect1, sect2, intersections);
1810*c8dee2aaSAndroid Build Coastguard Worker return;
1811*c8dee2aaSAndroid Build Coastguard Worker }
1812*c8dee2aaSAndroid Build Coastguard Worker span1->addBounded(span2, §1->fHeap);
1813*c8dee2aaSAndroid Build Coastguard Worker span2->addBounded(span1, §2->fHeap);
1814*c8dee2aaSAndroid Build Coastguard Worker const int kMaxCoinLoopCount = 8;
1815*c8dee2aaSAndroid Build Coastguard Worker int coinLoopCount = kMaxCoinLoopCount;
1816*c8dee2aaSAndroid Build Coastguard Worker double start1s SK_INIT_TO_AVOID_WARNING;
1817*c8dee2aaSAndroid Build Coastguard Worker double start1e SK_INIT_TO_AVOID_WARNING;
1818*c8dee2aaSAndroid Build Coastguard Worker do {
1819*c8dee2aaSAndroid Build Coastguard Worker // find the largest bounds
1820*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* largest1 = sect1->boundsMax();
1821*c8dee2aaSAndroid Build Coastguard Worker if (!largest1) {
1822*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fHung) {
1823*c8dee2aaSAndroid Build Coastguard Worker return;
1824*c8dee2aaSAndroid Build Coastguard Worker }
1825*c8dee2aaSAndroid Build Coastguard Worker break;
1826*c8dee2aaSAndroid Build Coastguard Worker }
1827*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* largest2 = sect2->boundsMax();
1828*c8dee2aaSAndroid Build Coastguard Worker // split it
1829*c8dee2aaSAndroid Build Coastguard Worker if (!largest2 || (largest1 && (largest1->fBoundsMax > largest2->fBoundsMax
1830*c8dee2aaSAndroid Build Coastguard Worker || (!largest1->fCollapsed && largest2->fCollapsed)))) {
1831*c8dee2aaSAndroid Build Coastguard Worker if (sect2->fHung) {
1832*c8dee2aaSAndroid Build Coastguard Worker return;
1833*c8dee2aaSAndroid Build Coastguard Worker }
1834*c8dee2aaSAndroid Build Coastguard Worker if (largest1->fCollapsed) {
1835*c8dee2aaSAndroid Build Coastguard Worker break;
1836*c8dee2aaSAndroid Build Coastguard Worker }
1837*c8dee2aaSAndroid Build Coastguard Worker sect1->resetRemovedEnds();
1838*c8dee2aaSAndroid Build Coastguard Worker sect2->resetRemovedEnds();
1839*c8dee2aaSAndroid Build Coastguard Worker // trim parts that don't intersect the opposite
1840*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* half1 = sect1->addOne();
1841*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(half1->debugSetGlobalState(sect1->globalState()));
1842*c8dee2aaSAndroid Build Coastguard Worker if (!half1->split(largest1, §1->fHeap)) {
1843*c8dee2aaSAndroid Build Coastguard Worker break;
1844*c8dee2aaSAndroid Build Coastguard Worker }
1845*c8dee2aaSAndroid Build Coastguard Worker if (!sect1->trim(largest1, sect2)) {
1846*c8dee2aaSAndroid Build Coastguard Worker SkOPOBJASSERT(intersections, 0);
1847*c8dee2aaSAndroid Build Coastguard Worker return;
1848*c8dee2aaSAndroid Build Coastguard Worker }
1849*c8dee2aaSAndroid Build Coastguard Worker if (!sect1->trim(half1, sect2)) {
1850*c8dee2aaSAndroid Build Coastguard Worker SkOPOBJASSERT(intersections, 0);
1851*c8dee2aaSAndroid Build Coastguard Worker return;
1852*c8dee2aaSAndroid Build Coastguard Worker }
1853*c8dee2aaSAndroid Build Coastguard Worker } else {
1854*c8dee2aaSAndroid Build Coastguard Worker if (largest2->fCollapsed) {
1855*c8dee2aaSAndroid Build Coastguard Worker break;
1856*c8dee2aaSAndroid Build Coastguard Worker }
1857*c8dee2aaSAndroid Build Coastguard Worker sect1->resetRemovedEnds();
1858*c8dee2aaSAndroid Build Coastguard Worker sect2->resetRemovedEnds();
1859*c8dee2aaSAndroid Build Coastguard Worker // trim parts that don't intersect the opposite
1860*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* half2 = sect2->addOne();
1861*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(half2->debugSetGlobalState(sect2->globalState()));
1862*c8dee2aaSAndroid Build Coastguard Worker if (!half2->split(largest2, §2->fHeap)) {
1863*c8dee2aaSAndroid Build Coastguard Worker break;
1864*c8dee2aaSAndroid Build Coastguard Worker }
1865*c8dee2aaSAndroid Build Coastguard Worker if (!sect2->trim(largest2, sect1)) {
1866*c8dee2aaSAndroid Build Coastguard Worker SkOPOBJASSERT(intersections, 0);
1867*c8dee2aaSAndroid Build Coastguard Worker return;
1868*c8dee2aaSAndroid Build Coastguard Worker }
1869*c8dee2aaSAndroid Build Coastguard Worker if (!sect2->trim(half2, sect1)) {
1870*c8dee2aaSAndroid Build Coastguard Worker SkOPOBJASSERT(intersections, 0);
1871*c8dee2aaSAndroid Build Coastguard Worker return;
1872*c8dee2aaSAndroid Build Coastguard Worker }
1873*c8dee2aaSAndroid Build Coastguard Worker }
1874*c8dee2aaSAndroid Build Coastguard Worker sect1->validate();
1875*c8dee2aaSAndroid Build Coastguard Worker sect2->validate();
1876*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT_LOOP_COUNT
1877*c8dee2aaSAndroid Build Coastguard Worker intersections->debugBumpLoopCount(SkIntersections::kIterations_DebugLoop);
1878*c8dee2aaSAndroid Build Coastguard Worker #endif
1879*c8dee2aaSAndroid Build Coastguard Worker // if there are 9 or more continuous spans on both sects, suspect coincidence
1880*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
1881*c8dee2aaSAndroid Build Coastguard Worker && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
1882*c8dee2aaSAndroid Build Coastguard Worker if (coinLoopCount == kMaxCoinLoopCount) {
1883*c8dee2aaSAndroid Build Coastguard Worker start1s = sect1->fHead->fStartT;
1884*c8dee2aaSAndroid Build Coastguard Worker start1e = sect1->tail()->fEndT;
1885*c8dee2aaSAndroid Build Coastguard Worker }
1886*c8dee2aaSAndroid Build Coastguard Worker if (!sect1->coincidentCheck(sect2)) {
1887*c8dee2aaSAndroid Build Coastguard Worker return;
1888*c8dee2aaSAndroid Build Coastguard Worker }
1889*c8dee2aaSAndroid Build Coastguard Worker sect1->validate();
1890*c8dee2aaSAndroid Build Coastguard Worker sect2->validate();
1891*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT_LOOP_COUNT
1892*c8dee2aaSAndroid Build Coastguard Worker intersections->debugBumpLoopCount(SkIntersections::kCoinCheck_DebugLoop);
1893*c8dee2aaSAndroid Build Coastguard Worker #endif
1894*c8dee2aaSAndroid Build Coastguard Worker if (!--coinLoopCount && sect1->fHead && sect2->fHead) {
1895*c8dee2aaSAndroid Build Coastguard Worker /* All known working cases resolve in two tries. Sadly, cubicConicTests[0]
1896*c8dee2aaSAndroid Build Coastguard Worker gets stuck in a loop. It adds an extension to allow a coincident end
1897*c8dee2aaSAndroid Build Coastguard Worker perpendicular to track its intersection in the opposite curve. However,
1898*c8dee2aaSAndroid Build Coastguard Worker the bounding box of the extension does not intersect the original curve,
1899*c8dee2aaSAndroid Build Coastguard Worker so the extension is discarded, only to be added again the next time around. */
1900*c8dee2aaSAndroid Build Coastguard Worker sect1->coincidentForce(sect2, start1s, start1e);
1901*c8dee2aaSAndroid Build Coastguard Worker sect1->validate();
1902*c8dee2aaSAndroid Build Coastguard Worker sect2->validate();
1903*c8dee2aaSAndroid Build Coastguard Worker }
1904*c8dee2aaSAndroid Build Coastguard Worker }
1905*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
1906*c8dee2aaSAndroid Build Coastguard Worker && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
1907*c8dee2aaSAndroid Build Coastguard Worker if (!sect1->fHead) {
1908*c8dee2aaSAndroid Build Coastguard Worker return;
1909*c8dee2aaSAndroid Build Coastguard Worker }
1910*c8dee2aaSAndroid Build Coastguard Worker sect1->computePerpendiculars(sect2, sect1->fHead, sect1->tail());
1911*c8dee2aaSAndroid Build Coastguard Worker if (!sect2->fHead) {
1912*c8dee2aaSAndroid Build Coastguard Worker return;
1913*c8dee2aaSAndroid Build Coastguard Worker }
1914*c8dee2aaSAndroid Build Coastguard Worker sect2->computePerpendiculars(sect1, sect2->fHead, sect2->tail());
1915*c8dee2aaSAndroid Build Coastguard Worker if (!sect1->removeByPerpendicular(sect2)) {
1916*c8dee2aaSAndroid Build Coastguard Worker return;
1917*c8dee2aaSAndroid Build Coastguard Worker }
1918*c8dee2aaSAndroid Build Coastguard Worker sect1->validate();
1919*c8dee2aaSAndroid Build Coastguard Worker sect2->validate();
1920*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT_LOOP_COUNT
1921*c8dee2aaSAndroid Build Coastguard Worker intersections->debugBumpLoopCount(SkIntersections::kComputePerp_DebugLoop);
1922*c8dee2aaSAndroid Build Coastguard Worker #endif
1923*c8dee2aaSAndroid Build Coastguard Worker if (sect1->collapsed() > sect1->fCurve.maxIntersections()) {
1924*c8dee2aaSAndroid Build Coastguard Worker break;
1925*c8dee2aaSAndroid Build Coastguard Worker }
1926*c8dee2aaSAndroid Build Coastguard Worker }
1927*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_T_SECT_DUMP
1928*c8dee2aaSAndroid Build Coastguard Worker sect1->dumpBoth(sect2);
1929*c8dee2aaSAndroid Build Coastguard Worker #endif
1930*c8dee2aaSAndroid Build Coastguard Worker if (!sect1->fHead || !sect2->fHead) {
1931*c8dee2aaSAndroid Build Coastguard Worker break;
1932*c8dee2aaSAndroid Build Coastguard Worker }
1933*c8dee2aaSAndroid Build Coastguard Worker } while (true);
1934*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* coincident = sect1->fCoincident;
1935*c8dee2aaSAndroid Build Coastguard Worker if (coincident) {
1936*c8dee2aaSAndroid Build Coastguard Worker // if there is more than one coincident span, check loosely to see if they should be joined
1937*c8dee2aaSAndroid Build Coastguard Worker if (coincident->fNext) {
1938*c8dee2aaSAndroid Build Coastguard Worker sect1->mergeCoincidence(sect2);
1939*c8dee2aaSAndroid Build Coastguard Worker coincident = sect1->fCoincident;
1940*c8dee2aaSAndroid Build Coastguard Worker }
1941*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(sect2->fCoincident); // courtesy check : coincidence only looks at sect 1
1942*c8dee2aaSAndroid Build Coastguard Worker do {
1943*c8dee2aaSAndroid Build Coastguard Worker if (!coincident) {
1944*c8dee2aaSAndroid Build Coastguard Worker return;
1945*c8dee2aaSAndroid Build Coastguard Worker }
1946*c8dee2aaSAndroid Build Coastguard Worker if (!coincident->fCoinStart.isMatch()) {
1947*c8dee2aaSAndroid Build Coastguard Worker continue;
1948*c8dee2aaSAndroid Build Coastguard Worker }
1949*c8dee2aaSAndroid Build Coastguard Worker if (!coincident->fCoinEnd.isMatch()) {
1950*c8dee2aaSAndroid Build Coastguard Worker continue;
1951*c8dee2aaSAndroid Build Coastguard Worker }
1952*c8dee2aaSAndroid Build Coastguard Worker double perpT = coincident->fCoinStart.perpT();
1953*c8dee2aaSAndroid Build Coastguard Worker if (perpT < 0) {
1954*c8dee2aaSAndroid Build Coastguard Worker return;
1955*c8dee2aaSAndroid Build Coastguard Worker }
1956*c8dee2aaSAndroid Build Coastguard Worker int index = intersections->insertCoincident(coincident->fStartT,
1957*c8dee2aaSAndroid Build Coastguard Worker perpT, coincident->pointFirst());
1958*c8dee2aaSAndroid Build Coastguard Worker if ((intersections->insertCoincident(coincident->fEndT,
1959*c8dee2aaSAndroid Build Coastguard Worker coincident->fCoinEnd.perpT(),
1960*c8dee2aaSAndroid Build Coastguard Worker coincident->pointLast()) < 0) && index >= 0) {
1961*c8dee2aaSAndroid Build Coastguard Worker intersections->clearCoincidence(index);
1962*c8dee2aaSAndroid Build Coastguard Worker }
1963*c8dee2aaSAndroid Build Coastguard Worker } while ((coincident = coincident->fNext));
1964*c8dee2aaSAndroid Build Coastguard Worker }
1965*c8dee2aaSAndroid Build Coastguard Worker int zeroOneSet = EndsEqual(sect1, sect2, intersections);
1966*c8dee2aaSAndroid Build Coastguard Worker // if (!sect1->fHead || !sect2->fHead) {
1967*c8dee2aaSAndroid Build Coastguard Worker // if the final iteration contains an end (0 or 1),
1968*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fRemovedStartT && !(zeroOneSet & kZeroS1Set)) {
1969*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident perp; // intersect perpendicular with opposite curve
1970*c8dee2aaSAndroid Build Coastguard Worker perp.setPerp(sect1->fCurve, 0, sect1->fCurve[0], sect2->fCurve);
1971*c8dee2aaSAndroid Build Coastguard Worker if (perp.isMatch()) {
1972*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(0, perp.perpT(), perp.perpPt());
1973*c8dee2aaSAndroid Build Coastguard Worker }
1974*c8dee2aaSAndroid Build Coastguard Worker }
1975*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) {
1976*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident perp;
1977*c8dee2aaSAndroid Build Coastguard Worker perp.setPerp(sect1->fCurve, 1, sect1->pointLast(), sect2->fCurve);
1978*c8dee2aaSAndroid Build Coastguard Worker if (perp.isMatch()) {
1979*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(1, perp.perpT(), perp.perpPt());
1980*c8dee2aaSAndroid Build Coastguard Worker }
1981*c8dee2aaSAndroid Build Coastguard Worker }
1982*c8dee2aaSAndroid Build Coastguard Worker if (sect2->fRemovedStartT && !(zeroOneSet & kZeroS2Set)) {
1983*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident perp;
1984*c8dee2aaSAndroid Build Coastguard Worker perp.setPerp(sect2->fCurve, 0, sect2->fCurve[0], sect1->fCurve);
1985*c8dee2aaSAndroid Build Coastguard Worker if (perp.isMatch()) {
1986*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(perp.perpT(), 0, perp.perpPt());
1987*c8dee2aaSAndroid Build Coastguard Worker }
1988*c8dee2aaSAndroid Build Coastguard Worker }
1989*c8dee2aaSAndroid Build Coastguard Worker if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) {
1990*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident perp;
1991*c8dee2aaSAndroid Build Coastguard Worker perp.setPerp(sect2->fCurve, 1, sect2->pointLast(), sect1->fCurve);
1992*c8dee2aaSAndroid Build Coastguard Worker if (perp.isMatch()) {
1993*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(perp.perpT(), 1, perp.perpPt());
1994*c8dee2aaSAndroid Build Coastguard Worker }
1995*c8dee2aaSAndroid Build Coastguard Worker }
1996*c8dee2aaSAndroid Build Coastguard Worker // }
1997*c8dee2aaSAndroid Build Coastguard Worker if (!sect1->fHead || !sect2->fHead) {
1998*c8dee2aaSAndroid Build Coastguard Worker return;
1999*c8dee2aaSAndroid Build Coastguard Worker }
2000*c8dee2aaSAndroid Build Coastguard Worker sect1->recoverCollapsed();
2001*c8dee2aaSAndroid Build Coastguard Worker sect2->recoverCollapsed();
2002*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* result1 = sect1->fHead;
2003*c8dee2aaSAndroid Build Coastguard Worker // check heads and tails for zero and ones and insert them if we haven't already done so
2004*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* head1 = result1;
2005*c8dee2aaSAndroid Build Coastguard Worker if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStartT)) {
2006*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint& start1 = sect1->fCurve[0];
2007*c8dee2aaSAndroid Build Coastguard Worker if (head1->isBounded()) {
2008*c8dee2aaSAndroid Build Coastguard Worker double t = head1->closestBoundedT(start1);
2009*c8dee2aaSAndroid Build Coastguard Worker if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) {
2010*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(0, t, start1);
2011*c8dee2aaSAndroid Build Coastguard Worker }
2012*c8dee2aaSAndroid Build Coastguard Worker }
2013*c8dee2aaSAndroid Build Coastguard Worker }
2014*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* head2 = sect2->fHead;
2015*c8dee2aaSAndroid Build Coastguard Worker if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStartT)) {
2016*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint& start2 = sect2->fCurve[0];
2017*c8dee2aaSAndroid Build Coastguard Worker if (head2->isBounded()) {
2018*c8dee2aaSAndroid Build Coastguard Worker double t = head2->closestBoundedT(start2);
2019*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) {
2020*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(t, 0, start2);
2021*c8dee2aaSAndroid Build Coastguard Worker }
2022*c8dee2aaSAndroid Build Coastguard Worker }
2023*c8dee2aaSAndroid Build Coastguard Worker }
2024*c8dee2aaSAndroid Build Coastguard Worker if (!(zeroOneSet & kOneS1Set)) {
2025*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* tail1 = sect1->tail();
2026*c8dee2aaSAndroid Build Coastguard Worker if (!tail1) {
2027*c8dee2aaSAndroid Build Coastguard Worker return;
2028*c8dee2aaSAndroid Build Coastguard Worker }
2029*c8dee2aaSAndroid Build Coastguard Worker if (approximately_greater_than_one(tail1->fEndT)) {
2030*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint& end1 = sect1->pointLast();
2031*c8dee2aaSAndroid Build Coastguard Worker if (tail1->isBounded()) {
2032*c8dee2aaSAndroid Build Coastguard Worker double t = tail1->closestBoundedT(end1);
2033*c8dee2aaSAndroid Build Coastguard Worker if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) {
2034*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(1, t, end1);
2035*c8dee2aaSAndroid Build Coastguard Worker }
2036*c8dee2aaSAndroid Build Coastguard Worker }
2037*c8dee2aaSAndroid Build Coastguard Worker }
2038*c8dee2aaSAndroid Build Coastguard Worker }
2039*c8dee2aaSAndroid Build Coastguard Worker if (!(zeroOneSet & kOneS2Set)) {
2040*c8dee2aaSAndroid Build Coastguard Worker const SkTSpan* tail2 = sect2->tail();
2041*c8dee2aaSAndroid Build Coastguard Worker if (!tail2) {
2042*c8dee2aaSAndroid Build Coastguard Worker return;
2043*c8dee2aaSAndroid Build Coastguard Worker }
2044*c8dee2aaSAndroid Build Coastguard Worker if (approximately_greater_than_one(tail2->fEndT)) {
2045*c8dee2aaSAndroid Build Coastguard Worker const SkDPoint& end2 = sect2->pointLast();
2046*c8dee2aaSAndroid Build Coastguard Worker if (tail2->isBounded()) {
2047*c8dee2aaSAndroid Build Coastguard Worker double t = tail2->closestBoundedT(end2);
2048*c8dee2aaSAndroid Build Coastguard Worker if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) {
2049*c8dee2aaSAndroid Build Coastguard Worker intersections->insert(t, 1, end2);
2050*c8dee2aaSAndroid Build Coastguard Worker }
2051*c8dee2aaSAndroid Build Coastguard Worker }
2052*c8dee2aaSAndroid Build Coastguard Worker }
2053*c8dee2aaSAndroid Build Coastguard Worker }
2054*c8dee2aaSAndroid Build Coastguard Worker SkClosestSect closest;
2055*c8dee2aaSAndroid Build Coastguard Worker do {
2056*c8dee2aaSAndroid Build Coastguard Worker while (result1 && result1->fCoinStart.isMatch() && result1->fCoinEnd.isMatch()) {
2057*c8dee2aaSAndroid Build Coastguard Worker result1 = result1->fNext;
2058*c8dee2aaSAndroid Build Coastguard Worker }
2059*c8dee2aaSAndroid Build Coastguard Worker if (!result1) {
2060*c8dee2aaSAndroid Build Coastguard Worker break;
2061*c8dee2aaSAndroid Build Coastguard Worker }
2062*c8dee2aaSAndroid Build Coastguard Worker SkTSpan* result2 = sect2->fHead;
2063*c8dee2aaSAndroid Build Coastguard Worker while (result2) {
2064*c8dee2aaSAndroid Build Coastguard Worker closest.find(result1, result2 SkDEBUGPARAMS(intersections));
2065*c8dee2aaSAndroid Build Coastguard Worker result2 = result2->fNext;
2066*c8dee2aaSAndroid Build Coastguard Worker }
2067*c8dee2aaSAndroid Build Coastguard Worker } while ((result1 = result1->fNext));
2068*c8dee2aaSAndroid Build Coastguard Worker closest.finish(intersections);
2069*c8dee2aaSAndroid Build Coastguard Worker // if there is more than one intersection and it isn't already coincident, check
2070*c8dee2aaSAndroid Build Coastguard Worker int last = intersections->used() - 1;
2071*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < last; ) {
2072*c8dee2aaSAndroid Build Coastguard Worker if (intersections->isCoincident(index) && intersections->isCoincident(index + 1)) {
2073*c8dee2aaSAndroid Build Coastguard Worker ++index;
2074*c8dee2aaSAndroid Build Coastguard Worker continue;
2075*c8dee2aaSAndroid Build Coastguard Worker }
2076*c8dee2aaSAndroid Build Coastguard Worker double midT = ((*intersections)[0][index] + (*intersections)[0][index + 1]) / 2;
2077*c8dee2aaSAndroid Build Coastguard Worker SkDPoint midPt = sect1->fCurve.ptAtT(midT);
2078*c8dee2aaSAndroid Build Coastguard Worker // intersect perpendicular with opposite curve
2079*c8dee2aaSAndroid Build Coastguard Worker SkTCoincident perp;
2080*c8dee2aaSAndroid Build Coastguard Worker perp.setPerp(sect1->fCurve, midT, midPt, sect2->fCurve);
2081*c8dee2aaSAndroid Build Coastguard Worker if (!perp.isMatch()) {
2082*c8dee2aaSAndroid Build Coastguard Worker ++index;
2083*c8dee2aaSAndroid Build Coastguard Worker continue;
2084*c8dee2aaSAndroid Build Coastguard Worker }
2085*c8dee2aaSAndroid Build Coastguard Worker if (intersections->isCoincident(index)) {
2086*c8dee2aaSAndroid Build Coastguard Worker intersections->removeOne(index);
2087*c8dee2aaSAndroid Build Coastguard Worker --last;
2088*c8dee2aaSAndroid Build Coastguard Worker } else if (intersections->isCoincident(index + 1)) {
2089*c8dee2aaSAndroid Build Coastguard Worker intersections->removeOne(index + 1);
2090*c8dee2aaSAndroid Build Coastguard Worker --last;
2091*c8dee2aaSAndroid Build Coastguard Worker } else {
2092*c8dee2aaSAndroid Build Coastguard Worker intersections->setCoincident(index++);
2093*c8dee2aaSAndroid Build Coastguard Worker }
2094*c8dee2aaSAndroid Build Coastguard Worker intersections->setCoincident(index);
2095*c8dee2aaSAndroid Build Coastguard Worker }
2096*c8dee2aaSAndroid Build Coastguard Worker SkOPOBJASSERT(intersections, intersections->used() <= sect1->fCurve.maxIntersections());
2097*c8dee2aaSAndroid Build Coastguard Worker }
2098*c8dee2aaSAndroid Build Coastguard Worker
intersect(const SkDQuad & q1,const SkDQuad & q2)2099*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
2100*c8dee2aaSAndroid Build Coastguard Worker SkTQuad quad1(q1);
2101*c8dee2aaSAndroid Build Coastguard Worker SkTQuad quad2(q2);
2102*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect1(quad1 SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2103*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect2(quad2 SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2104*c8dee2aaSAndroid Build Coastguard Worker SkTSect::BinarySearch(§1, §2, this);
2105*c8dee2aaSAndroid Build Coastguard Worker return used();
2106*c8dee2aaSAndroid Build Coastguard Worker }
2107*c8dee2aaSAndroid Build Coastguard Worker
intersect(const SkDConic & c,const SkDQuad & q)2108*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::intersect(const SkDConic& c, const SkDQuad& q) {
2109*c8dee2aaSAndroid Build Coastguard Worker SkTConic conic(c);
2110*c8dee2aaSAndroid Build Coastguard Worker SkTQuad quad(q);
2111*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect1(conic SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2112*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect2(quad SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2113*c8dee2aaSAndroid Build Coastguard Worker SkTSect::BinarySearch(§1, §2, this);
2114*c8dee2aaSAndroid Build Coastguard Worker return used();
2115*c8dee2aaSAndroid Build Coastguard Worker }
2116*c8dee2aaSAndroid Build Coastguard Worker
intersect(const SkDConic & c1,const SkDConic & c2)2117*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::intersect(const SkDConic& c1, const SkDConic& c2) {
2118*c8dee2aaSAndroid Build Coastguard Worker SkTConic conic1(c1);
2119*c8dee2aaSAndroid Build Coastguard Worker SkTConic conic2(c2);
2120*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect1(conic1 SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2121*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect2(conic2 SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2122*c8dee2aaSAndroid Build Coastguard Worker SkTSect::BinarySearch(§1, §2, this);
2123*c8dee2aaSAndroid Build Coastguard Worker return used();
2124*c8dee2aaSAndroid Build Coastguard Worker }
2125*c8dee2aaSAndroid Build Coastguard Worker
intersect(const SkDCubic & c,const SkDQuad & q)2126*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::intersect(const SkDCubic& c, const SkDQuad& q) {
2127*c8dee2aaSAndroid Build Coastguard Worker SkTCubic cubic(c);
2128*c8dee2aaSAndroid Build Coastguard Worker SkTQuad quad(q);
2129*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect1(cubic SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2130*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect2(quad SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2131*c8dee2aaSAndroid Build Coastguard Worker SkTSect::BinarySearch(§1, §2, this);
2132*c8dee2aaSAndroid Build Coastguard Worker return used();
2133*c8dee2aaSAndroid Build Coastguard Worker }
2134*c8dee2aaSAndroid Build Coastguard Worker
intersect(const SkDCubic & cu,const SkDConic & co)2135*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::intersect(const SkDCubic& cu, const SkDConic& co) {
2136*c8dee2aaSAndroid Build Coastguard Worker SkTCubic cubic(cu);
2137*c8dee2aaSAndroid Build Coastguard Worker SkTConic conic(co);
2138*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect1(cubic SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2139*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect2(conic SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2140*c8dee2aaSAndroid Build Coastguard Worker SkTSect::BinarySearch(§1, §2, this);
2141*c8dee2aaSAndroid Build Coastguard Worker return used();
2142*c8dee2aaSAndroid Build Coastguard Worker
2143*c8dee2aaSAndroid Build Coastguard Worker }
2144*c8dee2aaSAndroid Build Coastguard Worker
intersect(const SkDCubic & c1,const SkDCubic & c2)2145*c8dee2aaSAndroid Build Coastguard Worker int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) {
2146*c8dee2aaSAndroid Build Coastguard Worker SkTCubic cubic1(c1);
2147*c8dee2aaSAndroid Build Coastguard Worker SkTCubic cubic2(c2);
2148*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect1(cubic1 SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1));
2149*c8dee2aaSAndroid Build Coastguard Worker SkTSect sect2(cubic2 SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2));
2150*c8dee2aaSAndroid Build Coastguard Worker SkTSect::BinarySearch(§1, §2, this);
2151*c8dee2aaSAndroid Build Coastguard Worker return used();
2152*c8dee2aaSAndroid Build Coastguard Worker }
2153