1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 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#include "include/core/SkPath.h" 9cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 10cb93a386Sopenharmony_ci#include "src/core/SkAnalyticEdge.h" 11cb93a386Sopenharmony_ci#include "src/core/SkEdge.h" 12cb93a386Sopenharmony_ci#include "src/core/SkEdgeBuilder.h" 13cb93a386Sopenharmony_ci#include "src/core/SkEdgeClipper.h" 14cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 15cb93a386Sopenharmony_ci#include "src/core/SkLineClipper.h" 16cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 17cb93a386Sopenharmony_ci#include "src/core/SkSafeMath.h" 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ciSkEdgeBuilder::Combine SkBasicEdgeBuilder::combineVertical(const SkEdge* edge, SkEdge* last) { 20cb93a386Sopenharmony_ci if (last->fCurveCount || last->fDX || edge->fX != last->fX) { 21cb93a386Sopenharmony_ci return kNo_Combine; 22cb93a386Sopenharmony_ci } 23cb93a386Sopenharmony_ci if (edge->fWinding == last->fWinding) { 24cb93a386Sopenharmony_ci if (edge->fLastY + 1 == last->fFirstY) { 25cb93a386Sopenharmony_ci last->fFirstY = edge->fFirstY; 26cb93a386Sopenharmony_ci return kPartial_Combine; 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci if (edge->fFirstY == last->fLastY + 1) { 29cb93a386Sopenharmony_ci last->fLastY = edge->fLastY; 30cb93a386Sopenharmony_ci return kPartial_Combine; 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci return kNo_Combine; 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci if (edge->fFirstY == last->fFirstY) { 35cb93a386Sopenharmony_ci if (edge->fLastY == last->fLastY) { 36cb93a386Sopenharmony_ci return kTotal_Combine; 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci if (edge->fLastY < last->fLastY) { 39cb93a386Sopenharmony_ci last->fFirstY = edge->fLastY + 1; 40cb93a386Sopenharmony_ci return kPartial_Combine; 41cb93a386Sopenharmony_ci } 42cb93a386Sopenharmony_ci last->fFirstY = last->fLastY + 1; 43cb93a386Sopenharmony_ci last->fLastY = edge->fLastY; 44cb93a386Sopenharmony_ci last->fWinding = edge->fWinding; 45cb93a386Sopenharmony_ci return kPartial_Combine; 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci if (edge->fLastY == last->fLastY) { 48cb93a386Sopenharmony_ci if (edge->fFirstY > last->fFirstY) { 49cb93a386Sopenharmony_ci last->fLastY = edge->fFirstY - 1; 50cb93a386Sopenharmony_ci return kPartial_Combine; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci last->fLastY = last->fFirstY - 1; 53cb93a386Sopenharmony_ci last->fFirstY = edge->fFirstY; 54cb93a386Sopenharmony_ci last->fWinding = edge->fWinding; 55cb93a386Sopenharmony_ci return kPartial_Combine; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci return kNo_Combine; 58cb93a386Sopenharmony_ci} 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ciSkEdgeBuilder::Combine SkAnalyticEdgeBuilder::combineVertical(const SkAnalyticEdge* edge, 61cb93a386Sopenharmony_ci SkAnalyticEdge* last) { 62cb93a386Sopenharmony_ci auto approximately_equal = [](SkFixed a, SkFixed b) { 63cb93a386Sopenharmony_ci return SkAbs32(a - b) < 0x100; 64cb93a386Sopenharmony_ci }; 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci if (last->fCurveCount || last->fDX || edge->fX != last->fX) { 67cb93a386Sopenharmony_ci return kNo_Combine; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci if (edge->fWinding == last->fWinding) { 70cb93a386Sopenharmony_ci if (edge->fLowerY == last->fUpperY) { 71cb93a386Sopenharmony_ci last->fUpperY = edge->fUpperY; 72cb93a386Sopenharmony_ci last->fY = last->fUpperY; 73cb93a386Sopenharmony_ci return kPartial_Combine; 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci if (approximately_equal(edge->fUpperY, last->fLowerY)) { 76cb93a386Sopenharmony_ci last->fLowerY = edge->fLowerY; 77cb93a386Sopenharmony_ci return kPartial_Combine; 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci return kNo_Combine; 80cb93a386Sopenharmony_ci } 81cb93a386Sopenharmony_ci if (approximately_equal(edge->fUpperY, last->fUpperY)) { 82cb93a386Sopenharmony_ci if (approximately_equal(edge->fLowerY, last->fLowerY)) { 83cb93a386Sopenharmony_ci return kTotal_Combine; 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci if (edge->fLowerY < last->fLowerY) { 86cb93a386Sopenharmony_ci last->fUpperY = edge->fLowerY; 87cb93a386Sopenharmony_ci last->fY = last->fUpperY; 88cb93a386Sopenharmony_ci return kPartial_Combine; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci last->fUpperY = last->fLowerY; 91cb93a386Sopenharmony_ci last->fY = last->fUpperY; 92cb93a386Sopenharmony_ci last->fLowerY = edge->fLowerY; 93cb93a386Sopenharmony_ci last->fWinding = edge->fWinding; 94cb93a386Sopenharmony_ci return kPartial_Combine; 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci if (approximately_equal(edge->fLowerY, last->fLowerY)) { 97cb93a386Sopenharmony_ci if (edge->fUpperY > last->fUpperY) { 98cb93a386Sopenharmony_ci last->fLowerY = edge->fUpperY; 99cb93a386Sopenharmony_ci return kPartial_Combine; 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci last->fLowerY = last->fUpperY; 102cb93a386Sopenharmony_ci last->fUpperY = edge->fUpperY; 103cb93a386Sopenharmony_ci last->fY = last->fUpperY; 104cb93a386Sopenharmony_ci last->fWinding = edge->fWinding; 105cb93a386Sopenharmony_ci return kPartial_Combine; 106cb93a386Sopenharmony_ci } 107cb93a386Sopenharmony_ci return kNo_Combine; 108cb93a386Sopenharmony_ci} 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_citemplate <typename Edge> 111cb93a386Sopenharmony_cistatic bool is_vertical(const Edge* edge) { 112cb93a386Sopenharmony_ci return edge->fDX == 0 113cb93a386Sopenharmony_ci && edge->fCurveCount == 0; 114cb93a386Sopenharmony_ci} 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci// TODO: we can deallocate the edge if edge->setFoo() fails 117cb93a386Sopenharmony_ci// or when we don't use it (kPartial_Combine or kTotal_Combine). 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_civoid SkBasicEdgeBuilder::addLine(const SkPoint pts[]) { 120cb93a386Sopenharmony_ci SkEdge* edge = fAlloc.make<SkEdge>(); 121cb93a386Sopenharmony_ci if (edge->setLine(pts[0], pts[1], fClipShift)) { 122cb93a386Sopenharmony_ci Combine combine = is_vertical(edge) && !fList.empty() 123cb93a386Sopenharmony_ci ? this->combineVertical(edge, (SkEdge*)fList.top()) 124cb93a386Sopenharmony_ci : kNo_Combine; 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci switch (combine) { 127cb93a386Sopenharmony_ci case kTotal_Combine: fList.pop(); break; 128cb93a386Sopenharmony_ci case kPartial_Combine: break; 129cb93a386Sopenharmony_ci case kNo_Combine: fList.push_back(edge); break; 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci} 133cb93a386Sopenharmony_civoid SkAnalyticEdgeBuilder::addLine(const SkPoint pts[]) { 134cb93a386Sopenharmony_ci SkAnalyticEdge* edge = fAlloc.make<SkAnalyticEdge>(); 135cb93a386Sopenharmony_ci if (edge->setLine(pts[0], pts[1])) { 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci Combine combine = is_vertical(edge) && !fList.empty() 138cb93a386Sopenharmony_ci ? this->combineVertical(edge, (SkAnalyticEdge*)fList.top()) 139cb93a386Sopenharmony_ci : kNo_Combine; 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci switch (combine) { 142cb93a386Sopenharmony_ci case kTotal_Combine: fList.pop(); break; 143cb93a386Sopenharmony_ci case kPartial_Combine: break; 144cb93a386Sopenharmony_ci case kNo_Combine: fList.push_back(edge); break; 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci } 147cb93a386Sopenharmony_ci} 148cb93a386Sopenharmony_civoid SkBasicEdgeBuilder::addQuad(const SkPoint pts[]) { 149cb93a386Sopenharmony_ci SkQuadraticEdge* edge = fAlloc.make<SkQuadraticEdge>(); 150cb93a386Sopenharmony_ci if (edge->setQuadratic(pts, fClipShift)) { 151cb93a386Sopenharmony_ci fList.push_back(edge); 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci} 154cb93a386Sopenharmony_civoid SkAnalyticEdgeBuilder::addQuad(const SkPoint pts[]) { 155cb93a386Sopenharmony_ci SkAnalyticQuadraticEdge* edge = fAlloc.make<SkAnalyticQuadraticEdge>(); 156cb93a386Sopenharmony_ci if (edge->setQuadratic(pts)) { 157cb93a386Sopenharmony_ci fList.push_back(edge); 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci} 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_civoid SkBasicEdgeBuilder::addCubic(const SkPoint pts[]) { 162cb93a386Sopenharmony_ci SkCubicEdge* edge = fAlloc.make<SkCubicEdge>(); 163cb93a386Sopenharmony_ci if (edge->setCubic(pts, fClipShift)) { 164cb93a386Sopenharmony_ci fList.push_back(edge); 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci} 167cb93a386Sopenharmony_civoid SkAnalyticEdgeBuilder::addCubic(const SkPoint pts[]) { 168cb93a386Sopenharmony_ci SkAnalyticCubicEdge* edge = fAlloc.make<SkAnalyticCubicEdge>(); 169cb93a386Sopenharmony_ci if (edge->setCubic(pts)) { 170cb93a386Sopenharmony_ci fList.push_back(edge); 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci} 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci// TODO: merge addLine() and addPolyLine()? 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ciSkEdgeBuilder::Combine SkBasicEdgeBuilder::addPolyLine(const SkPoint pts[], 177cb93a386Sopenharmony_ci char* arg_edge, char** arg_edgePtr) { 178cb93a386Sopenharmony_ci auto edge = (SkEdge*) arg_edge; 179cb93a386Sopenharmony_ci auto edgePtr = (SkEdge**)arg_edgePtr; 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci if (edge->setLine(pts[0], pts[1], fClipShift)) { 182cb93a386Sopenharmony_ci return is_vertical(edge) && edgePtr > (SkEdge**)fEdgeList 183cb93a386Sopenharmony_ci ? this->combineVertical(edge, edgePtr[-1]) 184cb93a386Sopenharmony_ci : kNo_Combine; 185cb93a386Sopenharmony_ci } 186cb93a386Sopenharmony_ci return SkEdgeBuilder::kPartial_Combine; // A convenient lie. Same do-nothing behavior. 187cb93a386Sopenharmony_ci} 188cb93a386Sopenharmony_ciSkEdgeBuilder::Combine SkAnalyticEdgeBuilder::addPolyLine(const SkPoint pts[], 189cb93a386Sopenharmony_ci char* arg_edge, char** arg_edgePtr) { 190cb93a386Sopenharmony_ci auto edge = (SkAnalyticEdge*) arg_edge; 191cb93a386Sopenharmony_ci auto edgePtr = (SkAnalyticEdge**)arg_edgePtr; 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_ci if (edge->setLine(pts[0], pts[1])) { 194cb93a386Sopenharmony_ci return is_vertical(edge) && edgePtr > (SkAnalyticEdge**)fEdgeList 195cb93a386Sopenharmony_ci ? this->combineVertical(edge, edgePtr[-1]) 196cb93a386Sopenharmony_ci : kNo_Combine; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci return SkEdgeBuilder::kPartial_Combine; // As above. 199cb93a386Sopenharmony_ci} 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ciSkRect SkBasicEdgeBuilder::recoverClip(const SkIRect& src) const { 202cb93a386Sopenharmony_ci return { SkIntToScalar(src.fLeft >> fClipShift), 203cb93a386Sopenharmony_ci SkIntToScalar(src.fTop >> fClipShift), 204cb93a386Sopenharmony_ci SkIntToScalar(src.fRight >> fClipShift), 205cb93a386Sopenharmony_ci SkIntToScalar(src.fBottom >> fClipShift), }; 206cb93a386Sopenharmony_ci} 207cb93a386Sopenharmony_ciSkRect SkAnalyticEdgeBuilder::recoverClip(const SkIRect& src) const { 208cb93a386Sopenharmony_ci return SkRect::Make(src); 209cb93a386Sopenharmony_ci} 210cb93a386Sopenharmony_ci 211cb93a386Sopenharmony_cichar* SkBasicEdgeBuilder::allocEdges(size_t n, size_t* size) { 212cb93a386Sopenharmony_ci *size = sizeof(SkEdge); 213cb93a386Sopenharmony_ci return (char*)fAlloc.makeArrayDefault<SkEdge>(n); 214cb93a386Sopenharmony_ci} 215cb93a386Sopenharmony_cichar* SkAnalyticEdgeBuilder::allocEdges(size_t n, size_t* size) { 216cb93a386Sopenharmony_ci *size = sizeof(SkAnalyticEdge); 217cb93a386Sopenharmony_ci return (char*)fAlloc.makeArrayDefault<SkAnalyticEdge>(n); 218cb93a386Sopenharmony_ci} 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci// TODO: maybe get rid of buildPoly() entirely? 221cb93a386Sopenharmony_ciint SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, bool canCullToTheRight) { 222cb93a386Sopenharmony_ci size_t maxEdgeCount = path.countPoints(); 223cb93a386Sopenharmony_ci if (iclip) { 224cb93a386Sopenharmony_ci // clipping can turn 1 line into (up to) kMaxClippedLineSegments, since 225cb93a386Sopenharmony_ci // we turn portions that are clipped out on the left/right into vertical 226cb93a386Sopenharmony_ci // segments. 227cb93a386Sopenharmony_ci SkSafeMath safe; 228cb93a386Sopenharmony_ci maxEdgeCount = safe.mul(maxEdgeCount, SkLineClipper::kMaxClippedLineSegments); 229cb93a386Sopenharmony_ci if (!safe) { 230cb93a386Sopenharmony_ci return 0; 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci size_t edgeSize; 235cb93a386Sopenharmony_ci char* edge = this->allocEdges(maxEdgeCount, &edgeSize); 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci SkDEBUGCODE(char* edgeStart = edge); 238cb93a386Sopenharmony_ci char** edgePtr = fAlloc.makeArrayDefault<char*>(maxEdgeCount); 239cb93a386Sopenharmony_ci fEdgeList = (void**)edgePtr; 240cb93a386Sopenharmony_ci 241cb93a386Sopenharmony_ci SkPathEdgeIter iter(path); 242cb93a386Sopenharmony_ci if (iclip) { 243cb93a386Sopenharmony_ci SkRect clip = this->recoverClip(*iclip); 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci while (auto e = iter.next()) { 246cb93a386Sopenharmony_ci switch (e.fEdge) { 247cb93a386Sopenharmony_ci case SkPathEdgeIter::Edge::kLine: { 248cb93a386Sopenharmony_ci SkPoint lines[SkLineClipper::kMaxPoints]; 249cb93a386Sopenharmony_ci int lineCount = SkLineClipper::ClipLine(e.fPts, clip, lines, canCullToTheRight); 250cb93a386Sopenharmony_ci SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments); 251cb93a386Sopenharmony_ci for (int i = 0; i < lineCount; i++) { 252cb93a386Sopenharmony_ci switch( this->addPolyLine(lines + i, edge, edgePtr) ) { 253cb93a386Sopenharmony_ci case kTotal_Combine: edgePtr--; break; 254cb93a386Sopenharmony_ci case kPartial_Combine: break; 255cb93a386Sopenharmony_ci case kNo_Combine: *edgePtr++ = edge; 256cb93a386Sopenharmony_ci edge += edgeSize; 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci break; 260cb93a386Sopenharmony_ci } 261cb93a386Sopenharmony_ci default: 262cb93a386Sopenharmony_ci SkDEBUGFAIL("unexpected verb"); 263cb93a386Sopenharmony_ci break; 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci } else { 267cb93a386Sopenharmony_ci while (auto e = iter.next()) { 268cb93a386Sopenharmony_ci switch (e.fEdge) { 269cb93a386Sopenharmony_ci case SkPathEdgeIter::Edge::kLine: { 270cb93a386Sopenharmony_ci switch( this->addPolyLine(e.fPts, edge, edgePtr) ) { 271cb93a386Sopenharmony_ci case kTotal_Combine: edgePtr--; break; 272cb93a386Sopenharmony_ci case kPartial_Combine: break; 273cb93a386Sopenharmony_ci case kNo_Combine: *edgePtr++ = edge; 274cb93a386Sopenharmony_ci edge += edgeSize; 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci break; 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci default: 279cb93a386Sopenharmony_ci SkDEBUGFAIL("unexpected verb"); 280cb93a386Sopenharmony_ci break; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci SkASSERT((size_t)(edge - edgeStart) <= maxEdgeCount * edgeSize); 285cb93a386Sopenharmony_ci SkASSERT((size_t)(edgePtr - (char**)fEdgeList) <= maxEdgeCount); 286cb93a386Sopenharmony_ci return SkToInt(edgePtr - (char**)fEdgeList); 287cb93a386Sopenharmony_ci} 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ciint SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, bool canCullToTheRight) { 290cb93a386Sopenharmony_ci SkAutoConicToQuads quadder; 291cb93a386Sopenharmony_ci const SkScalar conicTol = SK_Scalar1 / 4; 292cb93a386Sopenharmony_ci bool is_finite = true; 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_ci SkPathEdgeIter iter(path); 295cb93a386Sopenharmony_ci if (iclip) { 296cb93a386Sopenharmony_ci SkRect clip = this->recoverClip(*iclip); 297cb93a386Sopenharmony_ci struct Rec { 298cb93a386Sopenharmony_ci SkEdgeBuilder* fBuilder; 299cb93a386Sopenharmony_ci bool fIsFinite; 300cb93a386Sopenharmony_ci } rec = { this, true }; 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_ci SkEdgeClipper::ClipPath(path, clip, canCullToTheRight, 303cb93a386Sopenharmony_ci [](SkEdgeClipper* clipper, bool, void* ctx) { 304cb93a386Sopenharmony_ci Rec* rec = (Rec*)ctx; 305cb93a386Sopenharmony_ci SkPoint pts[4]; 306cb93a386Sopenharmony_ci SkPath::Verb verb; 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) { 309cb93a386Sopenharmony_ci const int count = SkPathPriv::PtsInIter(verb); 310cb93a386Sopenharmony_ci if (!SkScalarsAreFinite(&pts[0].fX, count*2)) { 311cb93a386Sopenharmony_ci rec->fIsFinite = false; 312cb93a386Sopenharmony_ci return; 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci switch (verb) { 315cb93a386Sopenharmony_ci case SkPath::kLine_Verb: rec->fBuilder->addLine (pts); break; 316cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: rec->fBuilder->addQuad (pts); break; 317cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: rec->fBuilder->addCubic(pts); break; 318cb93a386Sopenharmony_ci default: break; 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci } 321cb93a386Sopenharmony_ci }, &rec); 322cb93a386Sopenharmony_ci is_finite = rec.fIsFinite; 323cb93a386Sopenharmony_ci } else { 324cb93a386Sopenharmony_ci auto handle_quad = [this](const SkPoint pts[3]) { 325cb93a386Sopenharmony_ci SkPoint monoX[5]; 326cb93a386Sopenharmony_ci int n = SkChopQuadAtYExtrema(pts, monoX); 327cb93a386Sopenharmony_ci for (int i = 0; i <= n; i++) { 328cb93a386Sopenharmony_ci this->addQuad(&monoX[i * 2]); 329cb93a386Sopenharmony_ci } 330cb93a386Sopenharmony_ci }; 331cb93a386Sopenharmony_ci while (auto e = iter.next()) { 332cb93a386Sopenharmony_ci switch (e.fEdge) { 333cb93a386Sopenharmony_ci case SkPathEdgeIter::Edge::kLine: 334cb93a386Sopenharmony_ci this->addLine(e.fPts); 335cb93a386Sopenharmony_ci break; 336cb93a386Sopenharmony_ci case SkPathEdgeIter::Edge::kQuad: { 337cb93a386Sopenharmony_ci handle_quad(e.fPts); 338cb93a386Sopenharmony_ci break; 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci case SkPathEdgeIter::Edge::kConic: { 341cb93a386Sopenharmony_ci const SkPoint* quadPts = quadder.computeQuads( 342cb93a386Sopenharmony_ci e.fPts, iter.conicWeight(), conicTol); 343cb93a386Sopenharmony_ci for (int i = 0; i < quadder.countQuads(); ++i) { 344cb93a386Sopenharmony_ci handle_quad(quadPts); 345cb93a386Sopenharmony_ci quadPts += 2; 346cb93a386Sopenharmony_ci } 347cb93a386Sopenharmony_ci } break; 348cb93a386Sopenharmony_ci case SkPathEdgeIter::Edge::kCubic: { 349cb93a386Sopenharmony_ci SkPoint monoY[10]; 350cb93a386Sopenharmony_ci int n = SkChopCubicAtYExtrema(e.fPts, monoY); 351cb93a386Sopenharmony_ci for (int i = 0; i <= n; i++) { 352cb93a386Sopenharmony_ci this->addCubic(&monoY[i * 3]); 353cb93a386Sopenharmony_ci } 354cb93a386Sopenharmony_ci break; 355cb93a386Sopenharmony_ci } 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci } 359cb93a386Sopenharmony_ci fEdgeList = fList.begin(); 360cb93a386Sopenharmony_ci return is_finite ? fList.count() : 0; 361cb93a386Sopenharmony_ci} 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_ciint SkEdgeBuilder::buildEdges(const SkPath& path, 364cb93a386Sopenharmony_ci const SkIRect* shiftedClip) { 365cb93a386Sopenharmony_ci // If we're convex, then we need both edges, even if the right edge is past the clip. 366cb93a386Sopenharmony_ci const bool canCullToTheRight = !path.isConvex(); 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci // We can use our buildPoly() optimization if all the segments are lines. 369cb93a386Sopenharmony_ci // (Edges are homogeneous and stored contiguously in memory, no need for indirection.) 370cb93a386Sopenharmony_ci const int count = SkPath::kLine_SegmentMask == path.getSegmentMasks() 371cb93a386Sopenharmony_ci ? this->buildPoly(path, shiftedClip, canCullToTheRight) 372cb93a386Sopenharmony_ci : this->build (path, shiftedClip, canCullToTheRight); 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci SkASSERT(count >= 0); 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ci // If we can't cull to the right, we should have count > 1 (or 0). 377cb93a386Sopenharmony_ci if (!canCullToTheRight) { 378cb93a386Sopenharmony_ci SkASSERT(count != 1); 379cb93a386Sopenharmony_ci } 380cb93a386Sopenharmony_ci return count; 381cb93a386Sopenharmony_ci} 382