1/* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkMatrix.h" 9#include "SkPath.h" 10#include "SkPathOps.h" 11 12void SkOpBuilder::add(const SkPath& path, SkPathOp op) { 13 if (0 == fOps.count() && op != kUnion_SkPathOp) { 14 fPathRefs.push_back() = SkPath(); 15 *fOps.append() = kUnion_SkPathOp; 16 } 17 fPathRefs.push_back() = path; 18 *fOps.append() = op; 19} 20 21void SkOpBuilder::reset() { 22 fPathRefs.reset(); 23 fOps.reset(); 24} 25 26/* OPTIMIZATION: Union doesn't need to be all-or-nothing. A run of three or more convex 27 paths with union ops could be locally resolved and still improve over doing the 28 ops one at a time. */ 29bool SkOpBuilder::resolve(SkPath* result) { 30 SkPath original = *result; 31 int count = fOps.count(); 32 bool allUnion = true; 33 SkPath::Direction firstDir; 34 for (int index = 0; index < count; ++index) { 35 SkPath* test = &fPathRefs[index]; 36 if (kUnion_SkPathOp != fOps[index] || test->isInverseFillType()) { 37 allUnion = false; 38 break; 39 } 40 // If all paths are convex, track direction, reversing as needed. 41 if (test->isConvex()) { 42 SkPath::Direction dir; 43 if (!test->cheapComputeDirection(&dir)) { 44 allUnion = false; 45 break; 46 } 47 if (index == 0) { 48 firstDir = dir; 49 } else if (firstDir != dir) { 50 SkPath temp; 51 temp.reverseAddPath(*test); 52 *test = temp; 53 } 54 continue; 55 } 56 // If the path is not convex but its bounds do not intersect the others, simplify is enough. 57 const SkRect& testBounds = test->getBounds(); 58 for (int inner = 0; inner < index; ++inner) { 59 // OPTIMIZE: check to see if the contour bounds do not intersect other contour bounds? 60 if (SkRect::Intersects(fPathRefs[inner].getBounds(), testBounds)) { 61 allUnion = false; 62 break; 63 } 64 } 65 } 66 if (!allUnion) { 67 *result = fPathRefs[0]; 68 for (int index = 1; index < count; ++index) { 69 if (!Op(*result, fPathRefs[index], fOps[index], result)) { 70 reset(); 71 *result = original; 72 return false; 73 } 74 } 75 reset(); 76 return true; 77 } 78 SkPath sum; 79 for (int index = 0; index < count; ++index) { 80 if (!Simplify(fPathRefs[index], &fPathRefs[index])) { 81 reset(); 82 *result = original; 83 return false; 84 } 85 sum.addPath(fPathRefs[index]); 86 } 87 reset(); 88 sum.setFillType(SkPath::kEvenOdd_FillType); 89 bool success = Simplify(sum, result); 90 if (!success) { 91 *result = original; 92 } 93 return success; 94} 95