bool TightBounds(const SkPath& path, SkRect* result) { SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune SkOpContour contour; SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); SkOpGlobalState globalState(contourList, &allocator SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)); // turn path into list of segments SkScalar scaleFactor = ScaleFactor(path); SkPath scaledPath; const SkPath* workingPath; if (scaleFactor > SK_Scalar1) { ScalePath(path, 1.f / scaleFactor, &scaledPath); workingPath = &scaledPath; } else { workingPath = &path; } SkOpEdgeBuilder builder(*workingPath, &contour, &globalState); if (!builder.finish()) { return false; } if (!SortContourList(&contourList, false, false)) { result->setEmpty(); return true; } SkOpContour* current = contourList; SkPathOpsBounds bounds = current->bounds(); while ((current = current->next())) { bounds.add(current->bounds()); } *result = bounds; return true; }
bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOdd) { SkTDArray<SkOpContour* > list; SkOpContour* contour = *contourList; do { if (contour->count()) { contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd); *list.append() = contour; } } while ((contour = contour->next())); int count = list.count(); if (!count) { return false; } if (count > 1) { SkTQSort<SkOpContour>(list.begin(), list.end() - 1); } contour = list[0]; SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour); contour->globalState()->setContourHead(contourHead); *contourList = contourHead; for (int index = 1; index < count; ++index) { SkOpContour* next = list[index]; contour->setNext(next); contour = next; } contour->setNext(nullptr); return true; }
void FixWinding(SkPath* path) { SkPath::FillType fillType = path->getFillType(); if (fillType == SkPath::kInverseEvenOdd_FillType) { fillType = SkPath::kInverseWinding_FillType; } else if (fillType == SkPath::kEvenOdd_FillType) { fillType = SkPath::kWinding_FillType; } SkPathPriv::FirstDirection dir; if (one_contour(*path) && SkPathPriv::CheapComputeFirstDirection(*path, &dir)) { if (dir != SkPathPriv::kCCW_FirstDirection) { SkPath temp; temp.reverseAddPath(*path); *path = temp; } path->setFillType(fillType); return; } SkChunkAlloc allocator(4096); SkOpContourHead contourHead; SkOpGlobalState globalState(nullptr, &contourHead SkDEBUGPARAMS(nullptr)); SkOpEdgeBuilder builder(*path, &contourHead, &allocator, &globalState); builder.finish(&allocator); SkASSERT(contourHead.next()); contourHead.resetReverse(); bool writePath = false; SkOpSpan* topSpan; globalState.setPhase(SkOpGlobalState::kFixWinding); while ((topSpan = FindSortableTop(&contourHead))) { SkOpSegment* topSegment = topSpan->segment(); SkOpContour* topContour = topSegment->contour(); SkASSERT(topContour->isCcw() >= 0); #if DEBUG_WINDING SkDebugf("%s id=%d nested=%d ccw=%d\n", __FUNCTION__, topSegment->debugID(), globalState.nested(), topContour->isCcw()); #endif if ((globalState.nested() & 1) != SkToBool(topContour->isCcw())) { topContour->setReverse(); writePath = true; } topContour->markDone(); globalState.clearNested(); } if (!writePath) { path->setFillType(fillType); return; } SkPath empty; SkPathWriter woundPath(empty); SkOpContour* test = &contourHead; do { if (test->reversed()) { test->toReversePath(&woundPath); } else { test->toPath(&woundPath); } } while ((test = test->next())); *path = *woundPath.nativePath(); path->setFillType(fillType); }
static bool missingCoincidence(SkOpContourHead* contourList) { SkOpContour* contour = contourList; bool result = false; do { result |= contour->missingCoincidence(); } while ((contour = contour->next())); return result; }
static bool missingCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence, SkChunkAlloc* allocator) { SkOpContour* contour = contourList; bool result = false; do { result |= contour->missingCoincidence(coincidence, allocator); } while ((contour = contour->next())); return result; }
static bool moveMultiples(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { if (!contour->moveMultiples()) { return false; } } while ((contour = contour->next())); return true; }
SkOpSegment* FindUndone(SkOpContourHead* contourList, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr) { SkOpSegment* result; SkOpContour* contour = contourList; do { result = contour->undoneSegment(startPtr, endPtr); if (result) { return result; } } while ((contour = contour->next())); return nullptr; }
bool TightBounds(const SkPath& path, SkRect* result) { SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune SkOpContour contour; SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); SkOpGlobalState globalState(nullptr, contourList SkDEBUGPARAMS(nullptr)); // turn path into list of segments SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); if (!builder.finish(&allocator)) { return false; } if (!SortContourList(&contourList, false, false)) { result->setEmpty(); return true; } SkOpContour* current = contourList; SkPathOpsBounds bounds = current->bounds(); while ((current = current->next())) { bounds.add(current->bounds()); } *result = bounds; return true; }
static void sortAngles(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { contour->sortAngles(); } while ((contour = contour->next())); }
static void moveNearby(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { contour->moveNearby(); } while ((contour = contour->next())); }
static void moveMultiples(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { contour->moveMultiples(); } while ((contour = contour->next())); }
static void findCollapsed(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { contour->findCollapsed(); } while ((contour = contour->next())); }
static void calcAngles(SkOpContourHead* contourList, SkChunkAlloc* allocator) { SkOpContour* contour = contourList; do { contour->calcAngles(allocator); } while ((contour = contour->next())); }
static void addAlignIntersections(SkOpContourHead* contourList, SkChunkAlloc* allocator) { SkOpContour* contour = contourList; do { contour->addAlignIntersections(contourList, allocator); } while ((contour = contour->next())); }
static void align(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { contour->align(); } while ((contour = contour->next())); }
void DebugShowActiveSpans(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { contour->debugShowActiveSpans(); } while ((contour = contour->next())); }