void operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) { result.reset(); result.setFillType(SkPath::kEvenOdd_FillType); // turn path into list of segments SkTArray<Op::Contour> contours; // FIXME: add self-intersecting cubics' T values to segment Op::EdgeBuilder builder(one, contours); const int aXorMask = builder.xorMask(); builder.addOperand(two); const int bXorMask = builder.xorMask(); builder.finish(); SkTDArray<Op::Contour*> contourList; makeContourList(contours, contourList); Op::Contour** currentPtr = contourList.begin(); if (!currentPtr) { return; } Op::Contour** listEnd = contourList.end(); // find all intersections between segments do { Op::Contour** nextPtr = currentPtr; Op::Contour* current = *currentPtr++; Op::Contour* next; do { next = *nextPtr++; } while (addIntersectTs(current, next) && nextPtr != listEnd); } while (currentPtr != listEnd); // eat through coincident edges coincidenceCheck(contourList); fixOtherTIndex(contourList); // construct closed contours Op::PathWrapper wrapper(result); bridgeOp(contourList, op, aXorMask, bXorMask, wrapper); }
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; }