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