| Index: src/pathops/SkOpBuilder.cpp
|
| diff --git a/src/pathops/SkOpBuilder.cpp b/src/pathops/SkOpBuilder.cpp
|
| index 1a446f15b61c2f16217b88bf6ae1f26bc4895691..39da2efbcee7a727b70b08b192de52112323b30f 100644
|
| --- a/src/pathops/SkOpBuilder.cpp
|
| +++ b/src/pathops/SkOpBuilder.cpp
|
| @@ -6,8 +6,80 @@
|
| */
|
|
|
| #include "SkMatrix.h"
|
| +#include "SkOpEdgeBuilder.h"
|
| #include "SkPath.h"
|
| #include "SkPathOps.h"
|
| +#include "SkPathOpsCommon.h"
|
| +
|
| +static bool one_contour(const SkPath& path) {
|
| + SkChunkAlloc allocator(256);
|
| + int verbCount = path.countVerbs();
|
| + uint8_t* verbs = (uint8_t*) allocator.alloc(sizeof(uint8_t) * verbCount,
|
| + SkChunkAlloc::kThrow_AllocFailType);
|
| + (void) path.getVerbs(verbs, verbCount);
|
| + for (int index = 1; index < verbCount; ++index) {
|
| + if (verbs[index] == SkPath::kMove_Verb) {
|
| + return false;
|
| + }
|
| + }
|
| + 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;
|
| + }
|
| + SkPath::Direction dir;
|
| + if (one_contour(*path) && path->cheapComputeDirection(&dir)) {
|
| + if (dir != SkPath::kCCW_Direction) {
|
| + SkPath temp;
|
| + temp.reverseAddPath(*path);
|
| + *path = temp;
|
| + }
|
| + path->setFillType(fillType);
|
| + return;
|
| + }
|
| + SkChunkAlloc allocator(4096);
|
| + SkOpContourHead contourHead;
|
| + SkOpGlobalState globalState(NULL, &contourHead);
|
| + 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();
|
| + bool active = topSegment->activeWinding(topSpan, topSpan->next());
|
| + SkASSERT(topContour->isCcw() >= 0);
|
| + if (active != SkToBool(topContour->isCcw())) {
|
| + topContour->setReverse();
|
| + writePath = true;
|
| + }
|
| + topContour->markDone();
|
| + }
|
| + 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);
|
| +}
|
|
|
| void SkOpBuilder::add(const SkPath& path, SkPathOp op) {
|
| if (0 == fOps.count() && op != kUnion_SkPathOp) {
|
| @@ -82,10 +154,11 @@ bool SkOpBuilder::resolve(SkPath* result) {
|
| *result = original;
|
| return false;
|
| }
|
| + // convert the even odd result back to winding form before accumulating it
|
| + FixWinding(&fPathRefs[index]);
|
| sum.addPath(fPathRefs[index]);
|
| }
|
| reset();
|
| - sum.setFillType(SkPath::kEvenOdd_FillType);
|
| bool success = Simplify(sum, result);
|
| if (!success) {
|
| *result = original;
|
|
|