1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 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#include "src/core/SkGeometry.h" 8cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 9cb93a386Sopenharmony_ci#include "src/core/SkTSort.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h" 11cb93a386Sopenharmony_ci#include "src/pathops/SkReduceOrder.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_civoid SkOpEdgeBuilder::init() { 14cb93a386Sopenharmony_ci fOperand = false; 15cb93a386Sopenharmony_ci fXorMask[0] = fXorMask[1] = ((int)fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask 16cb93a386Sopenharmony_ci : kWinding_PathOpsMask; 17cb93a386Sopenharmony_ci fUnparseable = false; 18cb93a386Sopenharmony_ci fSecondHalf = preFetch(); 19cb93a386Sopenharmony_ci} 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci// very tiny points cause numerical instability : don't allow them 22cb93a386Sopenharmony_cistatic SkPoint force_small_to_zero(const SkPoint& pt) { 23cb93a386Sopenharmony_ci SkPoint ret = pt; 24cb93a386Sopenharmony_ci if (SkScalarAbs(ret.fX) < FLT_EPSILON_ORDERABLE_ERR) { 25cb93a386Sopenharmony_ci ret.fX = 0; 26cb93a386Sopenharmony_ci } 27cb93a386Sopenharmony_ci if (SkScalarAbs(ret.fY) < FLT_EPSILON_ORDERABLE_ERR) { 28cb93a386Sopenharmony_ci ret.fY = 0; 29cb93a386Sopenharmony_ci } 30cb93a386Sopenharmony_ci return ret; 31cb93a386Sopenharmony_ci} 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_cistatic bool can_add_curve(SkPath::Verb verb, SkPoint* curve) { 34cb93a386Sopenharmony_ci if (SkPath::kMove_Verb == verb) { 35cb93a386Sopenharmony_ci return false; 36cb93a386Sopenharmony_ci } 37cb93a386Sopenharmony_ci for (int index = 0; index <= SkPathOpsVerbToPoints(verb); ++index) { 38cb93a386Sopenharmony_ci curve[index] = force_small_to_zero(curve[index]); 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci return SkPath::kLine_Verb != verb || !SkDPoint::ApproximatelyEqual(curve[0], curve[1]); 41cb93a386Sopenharmony_ci} 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_civoid SkOpEdgeBuilder::addOperand(const SkPath& path) { 44cb93a386Sopenharmony_ci SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb); 45cb93a386Sopenharmony_ci fPathVerbs.pop(); 46cb93a386Sopenharmony_ci fPath = &path; 47cb93a386Sopenharmony_ci fXorMask[1] = ((int)fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask 48cb93a386Sopenharmony_ci : kWinding_PathOpsMask; 49cb93a386Sopenharmony_ci preFetch(); 50cb93a386Sopenharmony_ci} 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_cibool SkOpEdgeBuilder::finish() { 53cb93a386Sopenharmony_ci fOperand = false; 54cb93a386Sopenharmony_ci if (fUnparseable || !walk()) { 55cb93a386Sopenharmony_ci return false; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci complete(); 58cb93a386Sopenharmony_ci SkOpContour* contour = fContourBuilder.contour(); 59cb93a386Sopenharmony_ci if (contour && !contour->count()) { 60cb93a386Sopenharmony_ci fContoursHead->remove(contour); 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci return true; 63cb93a386Sopenharmony_ci} 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_civoid SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curveStart) { 66cb93a386Sopenharmony_ci if (!SkDPoint::ApproximatelyEqual(curveEnd, curveStart)) { 67cb93a386Sopenharmony_ci *fPathVerbs.append() = SkPath::kLine_Verb; 68cb93a386Sopenharmony_ci *fPathPts.append() = curveStart; 69cb93a386Sopenharmony_ci } else { 70cb93a386Sopenharmony_ci int verbCount = fPathVerbs.count(); 71cb93a386Sopenharmony_ci int ptsCount = fPathPts.count(); 72cb93a386Sopenharmony_ci if (SkPath::kLine_Verb == fPathVerbs[verbCount - 1] 73cb93a386Sopenharmony_ci && fPathPts[ptsCount - 2] == curveStart) { 74cb93a386Sopenharmony_ci fPathVerbs.pop(); 75cb93a386Sopenharmony_ci fPathPts.pop(); 76cb93a386Sopenharmony_ci } else { 77cb93a386Sopenharmony_ci fPathPts[ptsCount - 1] = curveStart; 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci } 80cb93a386Sopenharmony_ci *fPathVerbs.append() = SkPath::kClose_Verb; 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ciint SkOpEdgeBuilder::preFetch() { 84cb93a386Sopenharmony_ci if (!fPath->isFinite()) { 85cb93a386Sopenharmony_ci fUnparseable = true; 86cb93a386Sopenharmony_ci return 0; 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci SkPoint curveStart; 89cb93a386Sopenharmony_ci SkPoint curve[4]; 90cb93a386Sopenharmony_ci bool lastCurve = false; 91cb93a386Sopenharmony_ci for (auto [pathVerb, pts, w] : SkPathPriv::Iterate(*fPath)) { 92cb93a386Sopenharmony_ci auto verb = static_cast<SkPath::Verb>(pathVerb); 93cb93a386Sopenharmony_ci switch (verb) { 94cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 95cb93a386Sopenharmony_ci if (!fAllowOpenContours && lastCurve) { 96cb93a386Sopenharmony_ci closeContour(curve[0], curveStart); 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci *fPathVerbs.append() = verb; 99cb93a386Sopenharmony_ci curve[0] = force_small_to_zero(pts[0]); 100cb93a386Sopenharmony_ci *fPathPts.append() = curve[0]; 101cb93a386Sopenharmony_ci curveStart = curve[0]; 102cb93a386Sopenharmony_ci lastCurve = false; 103cb93a386Sopenharmony_ci continue; 104cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 105cb93a386Sopenharmony_ci curve[1] = force_small_to_zero(pts[1]); 106cb93a386Sopenharmony_ci if (SkDPoint::ApproximatelyEqual(curve[0], curve[1])) { 107cb93a386Sopenharmony_ci uint8_t lastVerb = fPathVerbs.top(); 108cb93a386Sopenharmony_ci if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) { 109cb93a386Sopenharmony_ci fPathPts.top() = curve[0] = curve[1]; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci continue; // skip degenerate points 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci break; 114cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 115cb93a386Sopenharmony_ci curve[1] = force_small_to_zero(pts[1]); 116cb93a386Sopenharmony_ci curve[2] = force_small_to_zero(pts[2]); 117cb93a386Sopenharmony_ci verb = SkReduceOrder::Quad(curve, curve); 118cb93a386Sopenharmony_ci if (verb == SkPath::kMove_Verb) { 119cb93a386Sopenharmony_ci continue; // skip degenerate points 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci break; 122cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 123cb93a386Sopenharmony_ci curve[1] = force_small_to_zero(pts[1]); 124cb93a386Sopenharmony_ci curve[2] = force_small_to_zero(pts[2]); 125cb93a386Sopenharmony_ci verb = SkReduceOrder::Quad(curve, curve); 126cb93a386Sopenharmony_ci if (SkPath::kQuad_Verb == verb && 1 != *w) { 127cb93a386Sopenharmony_ci verb = SkPath::kConic_Verb; 128cb93a386Sopenharmony_ci } else if (verb == SkPath::kMove_Verb) { 129cb93a386Sopenharmony_ci continue; // skip degenerate points 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci break; 132cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 133cb93a386Sopenharmony_ci curve[1] = force_small_to_zero(pts[1]); 134cb93a386Sopenharmony_ci curve[2] = force_small_to_zero(pts[2]); 135cb93a386Sopenharmony_ci curve[3] = force_small_to_zero(pts[3]); 136cb93a386Sopenharmony_ci verb = SkReduceOrder::Cubic(curve, curve); 137cb93a386Sopenharmony_ci if (verb == SkPath::kMove_Verb) { 138cb93a386Sopenharmony_ci continue; // skip degenerate points 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci break; 141cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 142cb93a386Sopenharmony_ci closeContour(curve[0], curveStart); 143cb93a386Sopenharmony_ci lastCurve = false; 144cb93a386Sopenharmony_ci continue; 145cb93a386Sopenharmony_ci case SkPath::kDone_Verb: 146cb93a386Sopenharmony_ci continue; 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci *fPathVerbs.append() = verb; 149cb93a386Sopenharmony_ci int ptCount = SkPathOpsVerbToPoints(verb); 150cb93a386Sopenharmony_ci fPathPts.append(ptCount, &curve[1]); 151cb93a386Sopenharmony_ci if (verb == SkPath::kConic_Verb) { 152cb93a386Sopenharmony_ci *fWeights.append() = *w; 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci curve[0] = curve[ptCount]; 155cb93a386Sopenharmony_ci lastCurve = true; 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci if (!fAllowOpenContours && lastCurve) { 158cb93a386Sopenharmony_ci closeContour(curve[0], curveStart); 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci *fPathVerbs.append() = SkPath::kDone_Verb; 161cb93a386Sopenharmony_ci return fPathVerbs.count() - 1; 162cb93a386Sopenharmony_ci} 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_cibool SkOpEdgeBuilder::close() { 165cb93a386Sopenharmony_ci complete(); 166cb93a386Sopenharmony_ci return true; 167cb93a386Sopenharmony_ci} 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_cibool SkOpEdgeBuilder::walk() { 170cb93a386Sopenharmony_ci uint8_t* verbPtr = fPathVerbs.begin(); 171cb93a386Sopenharmony_ci uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf]; 172cb93a386Sopenharmony_ci SkPoint* pointsPtr = fPathPts.begin(); 173cb93a386Sopenharmony_ci SkScalar* weightPtr = fWeights.begin(); 174cb93a386Sopenharmony_ci SkPath::Verb verb; 175cb93a386Sopenharmony_ci SkOpContour* contour = fContourBuilder.contour(); 176cb93a386Sopenharmony_ci int moveToPtrBump = 0; 177cb93a386Sopenharmony_ci while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) { 178cb93a386Sopenharmony_ci if (verbPtr == endOfFirstHalf) { 179cb93a386Sopenharmony_ci fOperand = true; 180cb93a386Sopenharmony_ci } 181cb93a386Sopenharmony_ci verbPtr++; 182cb93a386Sopenharmony_ci switch (verb) { 183cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 184cb93a386Sopenharmony_ci if (contour && contour->count()) { 185cb93a386Sopenharmony_ci if (fAllowOpenContours) { 186cb93a386Sopenharmony_ci complete(); 187cb93a386Sopenharmony_ci } else if (!close()) { 188cb93a386Sopenharmony_ci return false; 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci if (!contour) { 192cb93a386Sopenharmony_ci fContourBuilder.setContour(contour = fContoursHead->appendContour()); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci contour->init(fGlobalState, fOperand, 195cb93a386Sopenharmony_ci fXorMask[fOperand] == kEvenOdd_PathOpsMask); 196cb93a386Sopenharmony_ci pointsPtr += moveToPtrBump; 197cb93a386Sopenharmony_ci moveToPtrBump = 1; 198cb93a386Sopenharmony_ci continue; 199cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 200cb93a386Sopenharmony_ci fContourBuilder.addLine(pointsPtr); 201cb93a386Sopenharmony_ci break; 202cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 203cb93a386Sopenharmony_ci { 204cb93a386Sopenharmony_ci SkVector vec1 = pointsPtr[1] - pointsPtr[0]; 205cb93a386Sopenharmony_ci SkVector vec2 = pointsPtr[2] - pointsPtr[1]; 206cb93a386Sopenharmony_ci if (vec1.dot(vec2) < 0) { 207cb93a386Sopenharmony_ci SkPoint pair[5]; 208cb93a386Sopenharmony_ci if (SkChopQuadAtMaxCurvature(pointsPtr, pair) == 1) { 209cb93a386Sopenharmony_ci goto addOneQuad; 210cb93a386Sopenharmony_ci } 211cb93a386Sopenharmony_ci if (!SkScalarsAreFinite(&pair[0].fX, SK_ARRAY_COUNT(pair) * 2)) { 212cb93a386Sopenharmony_ci return false; 213cb93a386Sopenharmony_ci } 214cb93a386Sopenharmony_ci for (unsigned index = 0; index < SK_ARRAY_COUNT(pair); ++index) { 215cb93a386Sopenharmony_ci pair[index] = force_small_to_zero(pair[index]); 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci SkPoint cStorage[2][2]; 218cb93a386Sopenharmony_ci SkPath::Verb v1 = SkReduceOrder::Quad(&pair[0], cStorage[0]); 219cb93a386Sopenharmony_ci SkPath::Verb v2 = SkReduceOrder::Quad(&pair[2], cStorage[1]); 220cb93a386Sopenharmony_ci SkPoint* curve1 = v1 != SkPath::kLine_Verb ? &pair[0] : cStorage[0]; 221cb93a386Sopenharmony_ci SkPoint* curve2 = v2 != SkPath::kLine_Verb ? &pair[2] : cStorage[1]; 222cb93a386Sopenharmony_ci if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) { 223cb93a386Sopenharmony_ci fContourBuilder.addCurve(v1, curve1); 224cb93a386Sopenharmony_ci fContourBuilder.addCurve(v2, curve2); 225cb93a386Sopenharmony_ci break; 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci addOneQuad: 230cb93a386Sopenharmony_ci fContourBuilder.addQuad(pointsPtr); 231cb93a386Sopenharmony_ci break; 232cb93a386Sopenharmony_ci case SkPath::kConic_Verb: { 233cb93a386Sopenharmony_ci SkVector vec1 = pointsPtr[1] - pointsPtr[0]; 234cb93a386Sopenharmony_ci SkVector vec2 = pointsPtr[2] - pointsPtr[1]; 235cb93a386Sopenharmony_ci SkScalar weight = *weightPtr++; 236cb93a386Sopenharmony_ci if (vec1.dot(vec2) < 0) { 237cb93a386Sopenharmony_ci // FIXME: max curvature for conics hasn't been implemented; use placeholder 238cb93a386Sopenharmony_ci SkScalar maxCurvature = SkFindQuadMaxCurvature(pointsPtr); 239cb93a386Sopenharmony_ci if (0 < maxCurvature && maxCurvature < 1) { 240cb93a386Sopenharmony_ci SkConic conic(pointsPtr, weight); 241cb93a386Sopenharmony_ci SkConic pair[2]; 242cb93a386Sopenharmony_ci if (!conic.chopAt(maxCurvature, pair)) { 243cb93a386Sopenharmony_ci // if result can't be computed, use original 244cb93a386Sopenharmony_ci fContourBuilder.addConic(pointsPtr, weight); 245cb93a386Sopenharmony_ci break; 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci SkPoint cStorage[2][3]; 248cb93a386Sopenharmony_ci SkPath::Verb v1 = SkReduceOrder::Conic(pair[0], cStorage[0]); 249cb93a386Sopenharmony_ci SkPath::Verb v2 = SkReduceOrder::Conic(pair[1], cStorage[1]); 250cb93a386Sopenharmony_ci SkPoint* curve1 = v1 != SkPath::kLine_Verb ? pair[0].fPts : cStorage[0]; 251cb93a386Sopenharmony_ci SkPoint* curve2 = v2 != SkPath::kLine_Verb ? pair[1].fPts : cStorage[1]; 252cb93a386Sopenharmony_ci if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) { 253cb93a386Sopenharmony_ci fContourBuilder.addCurve(v1, curve1, pair[0].fW); 254cb93a386Sopenharmony_ci fContourBuilder.addCurve(v2, curve2, pair[1].fW); 255cb93a386Sopenharmony_ci break; 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci fContourBuilder.addConic(pointsPtr, weight); 260cb93a386Sopenharmony_ci } break; 261cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 262cb93a386Sopenharmony_ci { 263cb93a386Sopenharmony_ci // Split complex cubics (such as self-intersecting curves or 264cb93a386Sopenharmony_ci // ones with difficult curvature) in two before proceeding. 265cb93a386Sopenharmony_ci // This can be required for intersection to succeed. 266cb93a386Sopenharmony_ci SkScalar splitT[3]; 267cb93a386Sopenharmony_ci int breaks = SkDCubic::ComplexBreak(pointsPtr, splitT); 268cb93a386Sopenharmony_ci if (!breaks) { 269cb93a386Sopenharmony_ci fContourBuilder.addCubic(pointsPtr); 270cb93a386Sopenharmony_ci break; 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci SkASSERT(breaks <= (int) SK_ARRAY_COUNT(splitT)); 273cb93a386Sopenharmony_ci struct Splitsville { 274cb93a386Sopenharmony_ci double fT[2]; 275cb93a386Sopenharmony_ci SkPoint fPts[4]; 276cb93a386Sopenharmony_ci SkPoint fReduced[4]; 277cb93a386Sopenharmony_ci SkPath::Verb fVerb; 278cb93a386Sopenharmony_ci bool fCanAdd; 279cb93a386Sopenharmony_ci } splits[4]; 280cb93a386Sopenharmony_ci SkASSERT(SK_ARRAY_COUNT(splits) == SK_ARRAY_COUNT(splitT) + 1); 281cb93a386Sopenharmony_ci SkTQSort(splitT, splitT + breaks); 282cb93a386Sopenharmony_ci for (int index = 0; index <= breaks; ++index) { 283cb93a386Sopenharmony_ci Splitsville* split = &splits[index]; 284cb93a386Sopenharmony_ci split->fT[0] = index ? splitT[index - 1] : 0; 285cb93a386Sopenharmony_ci split->fT[1] = index < breaks ? splitT[index] : 1; 286cb93a386Sopenharmony_ci SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0], split->fT[1]); 287cb93a386Sopenharmony_ci if (!part.toFloatPoints(split->fPts)) { 288cb93a386Sopenharmony_ci return false; 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced); 291cb93a386Sopenharmony_ci SkPoint* curve = SkPath::kCubic_Verb == split->fVerb 292cb93a386Sopenharmony_ci ? split->fPts : split->fReduced; 293cb93a386Sopenharmony_ci split->fCanAdd = can_add_curve(split->fVerb, curve); 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci for (int index = 0; index <= breaks; ++index) { 296cb93a386Sopenharmony_ci Splitsville* split = &splits[index]; 297cb93a386Sopenharmony_ci if (!split->fCanAdd) { 298cb93a386Sopenharmony_ci continue; 299cb93a386Sopenharmony_ci } 300cb93a386Sopenharmony_ci int prior = index; 301cb93a386Sopenharmony_ci while (prior > 0 && !splits[prior - 1].fCanAdd) { 302cb93a386Sopenharmony_ci --prior; 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci if (prior < index) { 305cb93a386Sopenharmony_ci split->fT[0] = splits[prior].fT[0]; 306cb93a386Sopenharmony_ci split->fPts[0] = splits[prior].fPts[0]; 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci int next = index; 309cb93a386Sopenharmony_ci int breakLimit = std::min(breaks, (int) SK_ARRAY_COUNT(splits) - 1); 310cb93a386Sopenharmony_ci while (next < breakLimit && !splits[next + 1].fCanAdd) { 311cb93a386Sopenharmony_ci ++next; 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci if (next > index) { 314cb93a386Sopenharmony_ci split->fT[1] = splits[next].fT[1]; 315cb93a386Sopenharmony_ci split->fPts[3] = splits[next].fPts[3]; 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci if (prior < index || next > index) { 318cb93a386Sopenharmony_ci split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced); 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci SkPoint* curve = SkPath::kCubic_Verb == split->fVerb 321cb93a386Sopenharmony_ci ? split->fPts : split->fReduced; 322cb93a386Sopenharmony_ci if (!can_add_curve(split->fVerb, curve)) { 323cb93a386Sopenharmony_ci return false; 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci fContourBuilder.addCurve(split->fVerb, curve); 326cb93a386Sopenharmony_ci } 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci break; 329cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 330cb93a386Sopenharmony_ci SkASSERT(contour); 331cb93a386Sopenharmony_ci if (!close()) { 332cb93a386Sopenharmony_ci return false; 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci contour = nullptr; 335cb93a386Sopenharmony_ci continue; 336cb93a386Sopenharmony_ci default: 337cb93a386Sopenharmony_ci SkDEBUGFAIL("bad verb"); 338cb93a386Sopenharmony_ci return false; 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci SkASSERT(contour); 341cb93a386Sopenharmony_ci if (contour->count()) { 342cb93a386Sopenharmony_ci contour->debugValidate(); 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci pointsPtr += SkPathOpsVerbToPoints(verb); 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci fContourBuilder.flush(); 347cb93a386Sopenharmony_ci if (contour && contour->count() &&!fAllowOpenContours && !close()) { 348cb93a386Sopenharmony_ci return false; 349cb93a386Sopenharmony_ci } 350cb93a386Sopenharmony_ci return true; 351cb93a386Sopenharmony_ci} 352