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/pathops/SkAddIntersections.h" 8cb93a386Sopenharmony_ci#include "src/pathops/SkOpCoincidence.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCommon.h" 11cb93a386Sopenharmony_ci#include "src/pathops/SkPathWriter.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci#include <utility> 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_cistatic bool findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase** startPtr, 16cb93a386Sopenharmony_ci SkOpSpanBase** endPtr, SkOpSegment** result) { 17cb93a386Sopenharmony_ci while (chase.count()) { 18cb93a386Sopenharmony_ci SkOpSpanBase* span; 19cb93a386Sopenharmony_ci chase.pop(&span); 20cb93a386Sopenharmony_ci // OPTIMIZE: prev makes this compatible with old code -- but is it necessary? 21cb93a386Sopenharmony_ci *startPtr = span->ptT()->prev()->span(); 22cb93a386Sopenharmony_ci SkOpSegment* segment = (*startPtr)->segment(); 23cb93a386Sopenharmony_ci bool done = true; 24cb93a386Sopenharmony_ci *endPtr = nullptr; 25cb93a386Sopenharmony_ci if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) { 26cb93a386Sopenharmony_ci *startPtr = last->start(); 27cb93a386Sopenharmony_ci *endPtr = last->end(); 28cb93a386Sopenharmony_ci #if TRY_ROTATE 29cb93a386Sopenharmony_ci *chase.insert(0) = span; 30cb93a386Sopenharmony_ci #else 31cb93a386Sopenharmony_ci *chase.append() = span; 32cb93a386Sopenharmony_ci #endif 33cb93a386Sopenharmony_ci *result = last->segment(); 34cb93a386Sopenharmony_ci return true; 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci if (done) { 37cb93a386Sopenharmony_ci continue; 38cb93a386Sopenharmony_ci } 39cb93a386Sopenharmony_ci int winding; 40cb93a386Sopenharmony_ci bool sortable; 41cb93a386Sopenharmony_ci const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable); 42cb93a386Sopenharmony_ci if (!angle) { 43cb93a386Sopenharmony_ci *result = nullptr; 44cb93a386Sopenharmony_ci return true; 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci if (winding == SK_MinS32) { 47cb93a386Sopenharmony_ci continue; 48cb93a386Sopenharmony_ci } 49cb93a386Sopenharmony_ci int sumMiWinding, sumSuWinding; 50cb93a386Sopenharmony_ci if (sortable) { 51cb93a386Sopenharmony_ci segment = angle->segment(); 52cb93a386Sopenharmony_ci sumMiWinding = segment->updateWindingReverse(angle); 53cb93a386Sopenharmony_ci if (sumMiWinding == SK_MinS32) { 54cb93a386Sopenharmony_ci SkASSERT(segment->globalState()->debugSkipAssert()); 55cb93a386Sopenharmony_ci *result = nullptr; 56cb93a386Sopenharmony_ci return true; 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci sumSuWinding = segment->updateOppWindingReverse(angle); 59cb93a386Sopenharmony_ci if (sumSuWinding == SK_MinS32) { 60cb93a386Sopenharmony_ci SkASSERT(segment->globalState()->debugSkipAssert()); 61cb93a386Sopenharmony_ci *result = nullptr; 62cb93a386Sopenharmony_ci return true; 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci if (segment->operand()) { 65cb93a386Sopenharmony_ci using std::swap; 66cb93a386Sopenharmony_ci swap(sumMiWinding, sumSuWinding); 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci SkOpSegment* first = nullptr; 70cb93a386Sopenharmony_ci const SkOpAngle* firstAngle = angle; 71cb93a386Sopenharmony_ci while ((angle = angle->next()) != firstAngle) { 72cb93a386Sopenharmony_ci segment = angle->segment(); 73cb93a386Sopenharmony_ci SkOpSpanBase* start = angle->start(); 74cb93a386Sopenharmony_ci SkOpSpanBase* end = angle->end(); 75cb93a386Sopenharmony_ci int maxWinding = 0, sumWinding = 0, oppMaxWinding = 0, oppSumWinding = 0; 76cb93a386Sopenharmony_ci if (sortable) { 77cb93a386Sopenharmony_ci segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding, 78cb93a386Sopenharmony_ci &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 79cb93a386Sopenharmony_ci } 80cb93a386Sopenharmony_ci if (!segment->done(angle)) { 81cb93a386Sopenharmony_ci if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) { 82cb93a386Sopenharmony_ci first = segment; 83cb93a386Sopenharmony_ci *startPtr = start; 84cb93a386Sopenharmony_ci *endPtr = end; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci // OPTIMIZATION: should this also add to the chase? 87cb93a386Sopenharmony_ci if (sortable) { 88cb93a386Sopenharmony_ci if (!segment->markAngle(maxWinding, sumWinding, oppMaxWinding, 89cb93a386Sopenharmony_ci oppSumWinding, angle, nullptr)) { 90cb93a386Sopenharmony_ci return false; 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci if (first) { 96cb93a386Sopenharmony_ci #if TRY_ROTATE 97cb93a386Sopenharmony_ci *chase.insert(0) = span; 98cb93a386Sopenharmony_ci #else 99cb93a386Sopenharmony_ci *chase.append() = span; 100cb93a386Sopenharmony_ci #endif 101cb93a386Sopenharmony_ci *result = first; 102cb93a386Sopenharmony_ci return true; 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci *result = nullptr; 106cb93a386Sopenharmony_ci return true; 107cb93a386Sopenharmony_ci} 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_cistatic bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op, 110cb93a386Sopenharmony_ci const int xorMask, const int xorOpMask, SkPathWriter* writer) { 111cb93a386Sopenharmony_ci bool unsortable = false; 112cb93a386Sopenharmony_ci bool lastSimple = false; 113cb93a386Sopenharmony_ci bool simple = false; 114cb93a386Sopenharmony_ci do { 115cb93a386Sopenharmony_ci SkOpSpan* span = FindSortableTop(contourList); 116cb93a386Sopenharmony_ci if (!span) { 117cb93a386Sopenharmony_ci break; 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci SkOpSegment* current = span->segment(); 120cb93a386Sopenharmony_ci SkOpSpanBase* start = span->next(); 121cb93a386Sopenharmony_ci SkOpSpanBase* end = span; 122cb93a386Sopenharmony_ci SkTDArray<SkOpSpanBase*> chase; 123cb93a386Sopenharmony_ci do { 124cb93a386Sopenharmony_ci if (current->activeOp(start, end, xorMask, xorOpMask, op)) { 125cb93a386Sopenharmony_ci do { 126cb93a386Sopenharmony_ci if (!unsortable && current->done()) { 127cb93a386Sopenharmony_ci break; 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci SkASSERT(unsortable || !current->done()); 130cb93a386Sopenharmony_ci SkOpSpanBase* nextStart = start; 131cb93a386Sopenharmony_ci SkOpSpanBase* nextEnd = end; 132cb93a386Sopenharmony_ci lastSimple = simple; 133cb93a386Sopenharmony_ci SkOpSegment* next = current->findNextOp(&chase, &nextStart, &nextEnd, 134cb93a386Sopenharmony_ci &unsortable, &simple, op, xorMask, xorOpMask); 135cb93a386Sopenharmony_ci if (!next) { 136cb93a386Sopenharmony_ci if (!unsortable && writer->hasMove() 137cb93a386Sopenharmony_ci && current->verb() != SkPath::kLine_Verb 138cb93a386Sopenharmony_ci && !writer->isClosed()) { 139cb93a386Sopenharmony_ci if (!current->addCurveTo(start, end, writer)) { 140cb93a386Sopenharmony_ci return false; 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci if (!writer->isClosed()) { 143cb93a386Sopenharmony_ci SkPathOpsDebug::ShowActiveSpans(contourList); 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci } else if (lastSimple) { 146cb93a386Sopenharmony_ci if (!current->addCurveTo(start, end, writer)) { 147cb93a386Sopenharmony_ci return false; 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci break; 151cb93a386Sopenharmony_ci } 152cb93a386Sopenharmony_ci #if DEBUG_FLOW 153cb93a386Sopenharmony_ci SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__, 154cb93a386Sopenharmony_ci current->debugID(), start->pt().fX, start->pt().fY, 155cb93a386Sopenharmony_ci end->pt().fX, end->pt().fY); 156cb93a386Sopenharmony_ci #endif 157cb93a386Sopenharmony_ci if (!current->addCurveTo(start, end, writer)) { 158cb93a386Sopenharmony_ci return false; 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci current = next; 161cb93a386Sopenharmony_ci start = nextStart; 162cb93a386Sopenharmony_ci end = nextEnd; 163cb93a386Sopenharmony_ci } while (!writer->isClosed() && (!unsortable || !start->starter(end)->done())); 164cb93a386Sopenharmony_ci if (current->activeWinding(start, end) && !writer->isClosed()) { 165cb93a386Sopenharmony_ci SkOpSpan* spanStart = start->starter(end); 166cb93a386Sopenharmony_ci if (!spanStart->done()) { 167cb93a386Sopenharmony_ci if (!current->addCurveTo(start, end, writer)) { 168cb93a386Sopenharmony_ci return false; 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci current->markDone(spanStart); 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci } 173cb93a386Sopenharmony_ci writer->finishContour(); 174cb93a386Sopenharmony_ci } else { 175cb93a386Sopenharmony_ci SkOpSpanBase* last; 176cb93a386Sopenharmony_ci if (!current->markAndChaseDone(start, end, &last)) { 177cb93a386Sopenharmony_ci return false; 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci if (last && !last->chased()) { 180cb93a386Sopenharmony_ci last->setChased(true); 181cb93a386Sopenharmony_ci SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last)); 182cb93a386Sopenharmony_ci *chase.append() = last; 183cb93a386Sopenharmony_ci#if DEBUG_WINDING 184cb93a386Sopenharmony_ci SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segment()->debugID()); 185cb93a386Sopenharmony_ci if (!last->final()) { 186cb93a386Sopenharmony_ci SkDebugf(" windSum=%d", last->upCast()->windSum()); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci SkDebugf("\n"); 189cb93a386Sopenharmony_ci#endif 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci } 192cb93a386Sopenharmony_ci if (!findChaseOp(chase, &start, &end, ¤t)) { 193cb93a386Sopenharmony_ci return false; 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci SkPathOpsDebug::ShowActiveSpans(contourList); 196cb93a386Sopenharmony_ci if (!current) { 197cb93a386Sopenharmony_ci break; 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci } while (true); 200cb93a386Sopenharmony_ci } while (true); 201cb93a386Sopenharmony_ci return true; 202cb93a386Sopenharmony_ci} 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci// diagram of why this simplifcation is possible is here: 205cb93a386Sopenharmony_ci// https://skia.org/dev/present/pathops link at bottom of the page 206cb93a386Sopenharmony_ci// https://drive.google.com/file/d/0BwoLUwz9PYkHLWpsaXd0UDdaN00/view?usp=sharing 207cb93a386Sopenharmony_cistatic const SkPathOp gOpInverse[kReverseDifference_SkPathOp + 1][2][2] = { 208cb93a386Sopenharmony_ci// inside minuend outside minuend 209cb93a386Sopenharmony_ci// inside subtrahend outside subtrahend inside subtrahend outside subtrahend 210cb93a386Sopenharmony_ci{{ kDifference_SkPathOp, kIntersect_SkPathOp }, { kUnion_SkPathOp, kReverseDifference_SkPathOp }}, 211cb93a386Sopenharmony_ci{{ kIntersect_SkPathOp, kDifference_SkPathOp }, { kReverseDifference_SkPathOp, kUnion_SkPathOp }}, 212cb93a386Sopenharmony_ci{{ kUnion_SkPathOp, kReverseDifference_SkPathOp }, { kDifference_SkPathOp, kIntersect_SkPathOp }}, 213cb93a386Sopenharmony_ci{{ kXOR_SkPathOp, kXOR_SkPathOp }, { kXOR_SkPathOp, kXOR_SkPathOp }}, 214cb93a386Sopenharmony_ci{{ kReverseDifference_SkPathOp, kUnion_SkPathOp }, { kIntersect_SkPathOp, kDifference_SkPathOp }}, 215cb93a386Sopenharmony_ci}; 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_cistatic const bool gOutInverse[kReverseDifference_SkPathOp + 1][2][2] = { 218cb93a386Sopenharmony_ci {{ false, false }, { true, false }}, // diff 219cb93a386Sopenharmony_ci {{ false, false }, { false, true }}, // sect 220cb93a386Sopenharmony_ci {{ false, true }, { true, true }}, // union 221cb93a386Sopenharmony_ci {{ false, true }, { true, false }}, // xor 222cb93a386Sopenharmony_ci {{ false, true }, { false, false }}, // rev diff 223cb93a386Sopenharmony_ci}; 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci#if DEBUG_T_SECT_LOOP_COUNT 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci#include "include/private/SkMutex.h" 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ciSkOpGlobalState debugWorstState(nullptr, nullptr SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)); 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_civoid ReportPathOpsDebugging() { 232cb93a386Sopenharmony_ci debugWorstState.debugLoopReport(); 233cb93a386Sopenharmony_ci} 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_ciextern void (*gVerboseFinalize)(); 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci#endif 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_cibool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result 240cb93a386Sopenharmony_ci SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)) { 241cb93a386Sopenharmony_ci#if DEBUG_DUMP_VERIFY 242cb93a386Sopenharmony_ci#ifndef SK_DEBUG 243cb93a386Sopenharmony_ci const char* testName = "release"; 244cb93a386Sopenharmony_ci#endif 245cb93a386Sopenharmony_ci if (SkPathOpsDebug::gDumpOp) { 246cb93a386Sopenharmony_ci SkPathOpsDebug::DumpOp(one, two, op, testName); 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci#endif 249cb93a386Sopenharmony_ci op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()]; 250cb93a386Sopenharmony_ci bool inverseFill = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()]; 251cb93a386Sopenharmony_ci SkPathFillType fillType = inverseFill ? SkPathFillType::kInverseEvenOdd : 252cb93a386Sopenharmony_ci SkPathFillType::kEvenOdd; 253cb93a386Sopenharmony_ci SkRect rect1, rect2; 254cb93a386Sopenharmony_ci if (kIntersect_SkPathOp == op && one.isRect(&rect1) && two.isRect(&rect2)) { 255cb93a386Sopenharmony_ci result->reset(); 256cb93a386Sopenharmony_ci result->setFillType(fillType); 257cb93a386Sopenharmony_ci if (rect1.intersect(rect2)) { 258cb93a386Sopenharmony_ci result->addRect(rect1); 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci return true; 261cb93a386Sopenharmony_ci } 262cb93a386Sopenharmony_ci if (one.isEmpty() || two.isEmpty()) { 263cb93a386Sopenharmony_ci SkPath work; 264cb93a386Sopenharmony_ci switch (op) { 265cb93a386Sopenharmony_ci case kIntersect_SkPathOp: 266cb93a386Sopenharmony_ci break; 267cb93a386Sopenharmony_ci case kUnion_SkPathOp: 268cb93a386Sopenharmony_ci case kXOR_SkPathOp: 269cb93a386Sopenharmony_ci work = one.isEmpty() ? two : one; 270cb93a386Sopenharmony_ci break; 271cb93a386Sopenharmony_ci case kDifference_SkPathOp: 272cb93a386Sopenharmony_ci if (!one.isEmpty()) { 273cb93a386Sopenharmony_ci work = one; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci break; 276cb93a386Sopenharmony_ci case kReverseDifference_SkPathOp: 277cb93a386Sopenharmony_ci if (!two.isEmpty()) { 278cb93a386Sopenharmony_ci work = two; 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci break; 281cb93a386Sopenharmony_ci default: 282cb93a386Sopenharmony_ci SkASSERT(0); // unhandled case 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci if (inverseFill != work.isInverseFillType()) { 285cb93a386Sopenharmony_ci work.toggleInverseFillType(); 286cb93a386Sopenharmony_ci } 287cb93a386Sopenharmony_ci return Simplify(work, result); 288cb93a386Sopenharmony_ci } 289cb93a386Sopenharmony_ci SkSTArenaAlloc<4096> allocator; // FIXME: add a constant expression here, tune 290cb93a386Sopenharmony_ci SkOpContour contour; 291cb93a386Sopenharmony_ci SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); 292cb93a386Sopenharmony_ci SkOpGlobalState globalState(contourList, &allocator 293cb93a386Sopenharmony_ci SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName)); 294cb93a386Sopenharmony_ci SkOpCoincidence coincidence(&globalState); 295cb93a386Sopenharmony_ci const SkPath* minuend = &one; 296cb93a386Sopenharmony_ci const SkPath* subtrahend = &two; 297cb93a386Sopenharmony_ci if (op == kReverseDifference_SkPathOp) { 298cb93a386Sopenharmony_ci using std::swap; 299cb93a386Sopenharmony_ci swap(minuend, subtrahend); 300cb93a386Sopenharmony_ci op = kDifference_SkPathOp; 301cb93a386Sopenharmony_ci } 302cb93a386Sopenharmony_ci#if DEBUG_SORT 303cb93a386Sopenharmony_ci SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; 304cb93a386Sopenharmony_ci#endif 305cb93a386Sopenharmony_ci // turn path into list of segments 306cb93a386Sopenharmony_ci SkOpEdgeBuilder builder(*minuend, contourList, &globalState); 307cb93a386Sopenharmony_ci if (builder.unparseable()) { 308cb93a386Sopenharmony_ci return false; 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci const int xorMask = builder.xorMask(); 311cb93a386Sopenharmony_ci builder.addOperand(*subtrahend); 312cb93a386Sopenharmony_ci if (!builder.finish()) { 313cb93a386Sopenharmony_ci return false; 314cb93a386Sopenharmony_ci } 315cb93a386Sopenharmony_ci#if DEBUG_DUMP_SEGMENTS 316cb93a386Sopenharmony_ci contourList->dumpSegments("seg", op); 317cb93a386Sopenharmony_ci#endif 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci const int xorOpMask = builder.xorMask(); 320cb93a386Sopenharmony_ci if (!SortContourList(&contourList, xorMask == kEvenOdd_PathOpsMask, 321cb93a386Sopenharmony_ci xorOpMask == kEvenOdd_PathOpsMask)) { 322cb93a386Sopenharmony_ci result->reset(); 323cb93a386Sopenharmony_ci result->setFillType(fillType); 324cb93a386Sopenharmony_ci return true; 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci // find all intersections between segments 327cb93a386Sopenharmony_ci SkOpContour* current = contourList; 328cb93a386Sopenharmony_ci do { 329cb93a386Sopenharmony_ci SkOpContour* next = current; 330cb93a386Sopenharmony_ci while (AddIntersectTs(current, next, &coincidence) 331cb93a386Sopenharmony_ci && (next = next->next())) 332cb93a386Sopenharmony_ci ; 333cb93a386Sopenharmony_ci } while ((current = current->next())); 334cb93a386Sopenharmony_ci#if DEBUG_VALIDATE 335cb93a386Sopenharmony_ci globalState.setPhase(SkOpPhase::kWalking); 336cb93a386Sopenharmony_ci#endif 337cb93a386Sopenharmony_ci bool success = HandleCoincidence(contourList, &coincidence); 338cb93a386Sopenharmony_ci#if DEBUG_COIN 339cb93a386Sopenharmony_ci globalState.debugAddToGlobalCoinDicts(); 340cb93a386Sopenharmony_ci#endif 341cb93a386Sopenharmony_ci if (!success) { 342cb93a386Sopenharmony_ci return false; 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci#if DEBUG_ALIGNMENT 345cb93a386Sopenharmony_ci contourList->dumpSegments("aligned"); 346cb93a386Sopenharmony_ci#endif 347cb93a386Sopenharmony_ci // construct closed contours 348cb93a386Sopenharmony_ci SkPath original = *result; 349cb93a386Sopenharmony_ci result->reset(); 350cb93a386Sopenharmony_ci result->setFillType(fillType); 351cb93a386Sopenharmony_ci SkPathWriter wrapper(*result); 352cb93a386Sopenharmony_ci if (!bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper)) { 353cb93a386Sopenharmony_ci *result = original; 354cb93a386Sopenharmony_ci return false; 355cb93a386Sopenharmony_ci } 356cb93a386Sopenharmony_ci wrapper.assemble(); // if some edges could not be resolved, assemble remaining 357cb93a386Sopenharmony_ci#if DEBUG_T_SECT_LOOP_COUNT 358cb93a386Sopenharmony_ci static SkMutex& debugWorstLoop = *(new SkMutex); 359cb93a386Sopenharmony_ci { 360cb93a386Sopenharmony_ci SkAutoMutexExclusive autoM(debugWorstLoop); 361cb93a386Sopenharmony_ci if (!gVerboseFinalize) { 362cb93a386Sopenharmony_ci gVerboseFinalize = &ReportPathOpsDebugging; 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci debugWorstState.debugDoYourWorst(&globalState); 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci#endif 367cb93a386Sopenharmony_ci return true; 368cb93a386Sopenharmony_ci} 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_cibool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { 371cb93a386Sopenharmony_ci#if DEBUG_DUMP_VERIFY 372cb93a386Sopenharmony_ci if (SkPathOpsDebug::gVerifyOp) { 373cb93a386Sopenharmony_ci if (!OpDebug(one, two, op, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) { 374cb93a386Sopenharmony_ci SkPathOpsDebug::ReportOpFail(one, two, op); 375cb93a386Sopenharmony_ci return false; 376cb93a386Sopenharmony_ci } 377cb93a386Sopenharmony_ci SkPathOpsDebug::VerifyOp(one, two, op, *result); 378cb93a386Sopenharmony_ci return true; 379cb93a386Sopenharmony_ci } 380cb93a386Sopenharmony_ci#endif 381cb93a386Sopenharmony_ci return OpDebug(one, two, op, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr)); 382cb93a386Sopenharmony_ci} 383