// FIXME : add this as a member of SkPath void Simplify(const SkPath& path, SkPath* result) { #if DEBUG_SORT || DEBUG_SWAP_TOP gDebugSortCount = gDebugSortCountDefault; #endif // returns 1 for evenodd, -1 for winding, regardless of inverse-ness result->reset(); result->setFillType(SkPath::kEvenOdd_FillType); SkPathWriter simple(*result); // turn path into list of segments SkTArray<SkOpContour> contours; SkOpEdgeBuilder builder(path, contours); builder.finish(); SkTDArray<SkOpContour*> contourList; MakeContourList(contours, contourList, false, false); SkOpContour** currentPtr = contourList.begin(); if (!currentPtr) { return; } SkOpContour** listEnd = contourList.end(); // find all intersections between segments do { SkOpContour** nextPtr = currentPtr; SkOpContour* current = *currentPtr++; if (current->containsCubics()) { AddSelfIntersectTs(current); } SkOpContour* next; do { next = *nextPtr++; } while (AddIntersectTs(current, next) && nextPtr != listEnd); } while (currentPtr != listEnd); // eat through coincident edges CoincidenceCheck(&contourList, 0); FixOtherTIndex(&contourList); SortSegments(&contourList); #if DEBUG_ACTIVE_SPANS DebugShowActiveSpans(contourList); #endif // construct closed contours if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, &simple) : !bridgeXor(contourList, &simple)) { // if some edges could not be resolved, assemble remaining fragments SkPath temp; temp.setFillType(SkPath::kEvenOdd_FillType); SkPathWriter assembled(temp); Assemble(simple, &assembled); *result = *assembled.nativePath(); } }
bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { #if DEBUG_SHOW_TEST_NAME char* debugName = DEBUG_FILENAME_STRING; if (debugName && debugName[0]) { SkPathOpsDebug::BumpTestName(debugName); SkPathOpsDebug::ShowPath(one, two, op, debugName); } #endif op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()]; SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()] ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType; const SkPath* minuend = &one; const SkPath* subtrahend = &two; if (op == kReverseDifference_PathOp) { minuend = &two; subtrahend = &one; op = kDifference_PathOp; } #if DEBUG_SORT || DEBUG_SWAP_TOP SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault; #endif // turn path into list of segments SkTArray<SkOpContour> contours; // FIXME: add self-intersecting cubics' T values to segment SkOpEdgeBuilder builder(*minuend, contours); const int xorMask = builder.xorMask(); builder.addOperand(*subtrahend); if (!builder.finish()) { return false; } result->reset(); result->setFillType(fillType); const int xorOpMask = builder.xorMask(); SkTArray<SkOpContour*, true> contourList; MakeContourList(contours, contourList, xorMask == kEvenOdd_PathOpsMask, xorOpMask == kEvenOdd_PathOpsMask); SkOpContour** currentPtr = contourList.begin(); if (!currentPtr) { return true; } SkOpContour** listEnd = contourList.end(); // find all intersections between segments do { SkOpContour** nextPtr = currentPtr; SkOpContour* current = *currentPtr++; if (current->containsCubics()) { AddSelfIntersectTs(current); } SkOpContour* next; do { next = *nextPtr++; } while (AddIntersectTs(current, next) && nextPtr != listEnd); } while (currentPtr != listEnd); // eat through coincident edges int total = 0; int index; for (index = 0; index < contourList.count(); ++index) { total += contourList[index]->segments().count(); } HandleCoincidence(&contourList, total); // construct closed contours SkPathWriter wrapper(*result); bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper); { // if some edges could not be resolved, assemble remaining fragments SkPath temp; temp.setFillType(fillType); SkPathWriter assembled(temp); Assemble(wrapper, &assembled); *result = *assembled.nativePath(); result->setFillType(fillType); } return true; }