Index: src/pathops/SkOpBuilder.cpp |
diff --git a/src/pathops/SkOpBuilder.cpp b/src/pathops/SkOpBuilder.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..489ad639c179b19046cf48941b1e7c7c2152cb99 |
--- /dev/null |
+++ b/src/pathops/SkOpBuilder.cpp |
@@ -0,0 +1,86 @@ |
+/* |
+ * Copyright 2014 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkMatrix.h" |
+#include "SkPath.h" |
+#include "SkPathOps.h" |
+ |
+void SkOpBuilder::add(const SkPath& path, SkPathOp op) { |
+ if (0 == fOps.count() && op != kUnion_PathOp) { |
+ fPathRefs.push_back() = SkPath(); |
+ *fOps.append() = kUnion_PathOp; |
+ } |
+ fPathRefs.push_back() = path; |
+ *fOps.append() = op; |
+} |
+ |
+void SkOpBuilder::reset() { |
+ fPathRefs.reset(); |
+ fOps.reset(); |
+} |
+ |
+/* OPTIMIZATION: Union doesn't need to be all-or-nothing. A run of three or more convex |
+ paths with union ops could be locally resolved and still improve over doing the |
+ ops one at a time. */ |
+bool SkOpBuilder::resolve(SkPath* result) { |
+ int count = fOps.count(); |
+ bool allUnion = true; |
+ SkPath::Direction firstDir; |
+ for (int index = 0; index < count; ++index) { |
+ SkPath* test = &fPathRefs[index]; |
+ if (kUnion_PathOp != fOps[index] || test->isInverseFillType()) { |
+ allUnion = false; |
+ break; |
+ } |
+ // If all paths are convex, track direction, reversing as needed. |
+ if (test->isConvex()) { |
+ SkPath::Direction dir; |
+ if (!test->cheapComputeDirection(&dir)) { |
+ allUnion = false; |
+ break; |
+ } |
+ if (index == 0) { |
+ firstDir = dir; |
+ } else if (firstDir != dir) { |
+ SkPath temp; |
+ temp.reverseAddPath(*test); |
+ *test = temp; |
+ } |
+ continue; |
+ } |
+ // If the path is not convex but its bounds do not intersect the others, simplify is enough. |
+ const SkRect& testBounds = test->getBounds(); |
+ for (int inner = 0; inner < index; ++inner) { |
+ // OPTIMIZE: check to see if the contour bounds do not intersect other contour bounds? |
+ if (SkRect::Intersects(fPathRefs[inner].getBounds(), testBounds)) { |
+ allUnion = false; |
+ break; |
+ } |
+ } |
+ } |
+ if (!allUnion) { |
+ *result = fPathRefs[0]; |
+ for (int index = 1; index < count; ++index) { |
+ if (!Op(*result, fPathRefs[index], fOps[index], result)) { |
+ reset(); |
+ return false; |
+ } |
+ } |
+ reset(); |
+ return true; |
+ } |
+ SkPath sum; |
+ for (int index = 0; index < count; ++index) { |
+ if (!Simplify(fPathRefs[index], &fPathRefs[index])) { |
+ reset(); |
+ return false; |
+ } |
+ sum.addPath(fPathRefs[index]); |
+ } |
+ reset(); |
+ return Simplify(sum, result); |
+} |