1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 9cb93a386Sopenharmony_ci#include "include/pathops/SkPathOps.h" 10cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h" 11cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 12cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h" 13cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCommon.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_cistatic bool one_contour(const SkPath& path) { 16cb93a386Sopenharmony_ci SkSTArenaAlloc<256> allocator; 17cb93a386Sopenharmony_ci int verbCount = path.countVerbs(); 18cb93a386Sopenharmony_ci uint8_t* verbs = (uint8_t*) allocator.makeArrayDefault<uint8_t>(verbCount); 19cb93a386Sopenharmony_ci (void) path.getVerbs(verbs, verbCount); 20cb93a386Sopenharmony_ci for (int index = 1; index < verbCount; ++index) { 21cb93a386Sopenharmony_ci if (verbs[index] == SkPath::kMove_Verb) { 22cb93a386Sopenharmony_ci return false; 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci return true; 26cb93a386Sopenharmony_ci} 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_civoid SkOpBuilder::ReversePath(SkPath* path) { 29cb93a386Sopenharmony_ci SkPath temp; 30cb93a386Sopenharmony_ci SkPoint lastPt; 31cb93a386Sopenharmony_ci SkAssertResult(path->getLastPt(&lastPt)); 32cb93a386Sopenharmony_ci temp.moveTo(lastPt); 33cb93a386Sopenharmony_ci temp.reversePathTo(*path); 34cb93a386Sopenharmony_ci temp.close(); 35cb93a386Sopenharmony_ci *path = temp; 36cb93a386Sopenharmony_ci} 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_cibool SkOpBuilder::FixWinding(SkPath* path) { 39cb93a386Sopenharmony_ci SkPathFillType fillType = path->getFillType(); 40cb93a386Sopenharmony_ci if (fillType == SkPathFillType::kInverseEvenOdd) { 41cb93a386Sopenharmony_ci fillType = SkPathFillType::kInverseWinding; 42cb93a386Sopenharmony_ci } else if (fillType == SkPathFillType::kEvenOdd) { 43cb93a386Sopenharmony_ci fillType = SkPathFillType::kWinding; 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci if (one_contour(*path)) { 46cb93a386Sopenharmony_ci SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(*path); 47cb93a386Sopenharmony_ci if (dir != SkPathFirstDirection::kUnknown) { 48cb93a386Sopenharmony_ci if (dir == SkPathFirstDirection::kCW) { 49cb93a386Sopenharmony_ci ReversePath(path); 50cb93a386Sopenharmony_ci } 51cb93a386Sopenharmony_ci path->setFillType(fillType); 52cb93a386Sopenharmony_ci return true; 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci SkSTArenaAlloc<4096> allocator; 56cb93a386Sopenharmony_ci SkOpContourHead contourHead; 57cb93a386Sopenharmony_ci SkOpGlobalState globalState(&contourHead, &allocator SkDEBUGPARAMS(false) 58cb93a386Sopenharmony_ci SkDEBUGPARAMS(nullptr)); 59cb93a386Sopenharmony_ci SkOpEdgeBuilder builder(*path, &contourHead, &globalState); 60cb93a386Sopenharmony_ci if (builder.unparseable() || !builder.finish()) { 61cb93a386Sopenharmony_ci return false; 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci if (!contourHead.count()) { 64cb93a386Sopenharmony_ci return true; 65cb93a386Sopenharmony_ci } 66cb93a386Sopenharmony_ci if (!contourHead.next()) { 67cb93a386Sopenharmony_ci return false; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci contourHead.joinAllSegments(); 70cb93a386Sopenharmony_ci contourHead.resetReverse(); 71cb93a386Sopenharmony_ci bool writePath = false; 72cb93a386Sopenharmony_ci SkOpSpan* topSpan; 73cb93a386Sopenharmony_ci globalState.setPhase(SkOpPhase::kFixWinding); 74cb93a386Sopenharmony_ci while ((topSpan = FindSortableTop(&contourHead))) { 75cb93a386Sopenharmony_ci SkOpSegment* topSegment = topSpan->segment(); 76cb93a386Sopenharmony_ci SkOpContour* topContour = topSegment->contour(); 77cb93a386Sopenharmony_ci SkASSERT(topContour->isCcw() >= 0); 78cb93a386Sopenharmony_ci#if DEBUG_WINDING 79cb93a386Sopenharmony_ci SkDebugf("%s id=%d nested=%d ccw=%d\n", __FUNCTION__, 80cb93a386Sopenharmony_ci topSegment->debugID(), globalState.nested(), topContour->isCcw()); 81cb93a386Sopenharmony_ci#endif 82cb93a386Sopenharmony_ci if ((globalState.nested() & 1) != SkToBool(topContour->isCcw())) { 83cb93a386Sopenharmony_ci topContour->setReverse(); 84cb93a386Sopenharmony_ci writePath = true; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci topContour->markAllDone(); 87cb93a386Sopenharmony_ci globalState.clearNested(); 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci if (!writePath) { 90cb93a386Sopenharmony_ci path->setFillType(fillType); 91cb93a386Sopenharmony_ci return true; 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci SkPath empty; 94cb93a386Sopenharmony_ci SkPathWriter woundPath(empty); 95cb93a386Sopenharmony_ci SkOpContour* test = &contourHead; 96cb93a386Sopenharmony_ci do { 97cb93a386Sopenharmony_ci if (!test->count()) { 98cb93a386Sopenharmony_ci continue; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci if (test->reversed()) { 101cb93a386Sopenharmony_ci test->toReversePath(&woundPath); 102cb93a386Sopenharmony_ci } else { 103cb93a386Sopenharmony_ci test->toPath(&woundPath); 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci } while ((test = test->next())); 106cb93a386Sopenharmony_ci *path = *woundPath.nativePath(); 107cb93a386Sopenharmony_ci path->setFillType(fillType); 108cb93a386Sopenharmony_ci return true; 109cb93a386Sopenharmony_ci} 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_civoid SkOpBuilder::add(const SkPath& path, SkPathOp op) { 112cb93a386Sopenharmony_ci if (0 == fOps.count() && op != kUnion_SkPathOp) { 113cb93a386Sopenharmony_ci fPathRefs.push_back() = SkPath(); 114cb93a386Sopenharmony_ci *fOps.append() = kUnion_SkPathOp; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci fPathRefs.push_back() = path; 117cb93a386Sopenharmony_ci *fOps.append() = op; 118cb93a386Sopenharmony_ci} 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_civoid SkOpBuilder::reset() { 121cb93a386Sopenharmony_ci fPathRefs.reset(); 122cb93a386Sopenharmony_ci fOps.reset(); 123cb93a386Sopenharmony_ci} 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci/* OPTIMIZATION: Union doesn't need to be all-or-nothing. A run of three or more convex 126cb93a386Sopenharmony_ci paths with union ops could be locally resolved and still improve over doing the 127cb93a386Sopenharmony_ci ops one at a time. */ 128cb93a386Sopenharmony_cibool SkOpBuilder::resolve(SkPath* result) { 129cb93a386Sopenharmony_ci SkPath original = *result; 130cb93a386Sopenharmony_ci int count = fOps.count(); 131cb93a386Sopenharmony_ci bool allUnion = true; 132cb93a386Sopenharmony_ci SkPathFirstDirection firstDir = SkPathFirstDirection::kUnknown; 133cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 134cb93a386Sopenharmony_ci SkPath* test = &fPathRefs[index]; 135cb93a386Sopenharmony_ci if (kUnion_SkPathOp != fOps[index] || test->isInverseFillType()) { 136cb93a386Sopenharmony_ci allUnion = false; 137cb93a386Sopenharmony_ci break; 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci // If all paths are convex, track direction, reversing as needed. 140cb93a386Sopenharmony_ci if (test->isConvex()) { 141cb93a386Sopenharmony_ci SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(*test); 142cb93a386Sopenharmony_ci if (dir == SkPathFirstDirection::kUnknown) { 143cb93a386Sopenharmony_ci allUnion = false; 144cb93a386Sopenharmony_ci break; 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci if (firstDir == SkPathFirstDirection::kUnknown) { 147cb93a386Sopenharmony_ci firstDir = dir; 148cb93a386Sopenharmony_ci } else if (firstDir != dir) { 149cb93a386Sopenharmony_ci ReversePath(test); 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci continue; 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci // If the path is not convex but its bounds do not intersect the others, simplify is enough. 154cb93a386Sopenharmony_ci const SkRect& testBounds = test->getBounds(); 155cb93a386Sopenharmony_ci for (int inner = 0; inner < index; ++inner) { 156cb93a386Sopenharmony_ci // OPTIMIZE: check to see if the contour bounds do not intersect other contour bounds? 157cb93a386Sopenharmony_ci if (SkRect::Intersects(fPathRefs[inner].getBounds(), testBounds)) { 158cb93a386Sopenharmony_ci allUnion = false; 159cb93a386Sopenharmony_ci break; 160cb93a386Sopenharmony_ci } 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci if (!allUnion) { 164cb93a386Sopenharmony_ci *result = fPathRefs[0]; 165cb93a386Sopenharmony_ci for (int index = 1; index < count; ++index) { 166cb93a386Sopenharmony_ci if (!Op(*result, fPathRefs[index], fOps[index], result)) { 167cb93a386Sopenharmony_ci reset(); 168cb93a386Sopenharmony_ci *result = original; 169cb93a386Sopenharmony_ci return false; 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci reset(); 173cb93a386Sopenharmony_ci return true; 174cb93a386Sopenharmony_ci } 175cb93a386Sopenharmony_ci SkPath sum; 176cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 177cb93a386Sopenharmony_ci if (!Simplify(fPathRefs[index], &fPathRefs[index])) { 178cb93a386Sopenharmony_ci reset(); 179cb93a386Sopenharmony_ci *result = original; 180cb93a386Sopenharmony_ci return false; 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci if (!fPathRefs[index].isEmpty()) { 183cb93a386Sopenharmony_ci // convert the even odd result back to winding form before accumulating it 184cb93a386Sopenharmony_ci if (!FixWinding(&fPathRefs[index])) { 185cb93a386Sopenharmony_ci *result = original; 186cb93a386Sopenharmony_ci return false; 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci sum.addPath(fPathRefs[index]); 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci reset(); 192cb93a386Sopenharmony_ci bool success = Simplify(sum, result); 193cb93a386Sopenharmony_ci if (!success) { 194cb93a386Sopenharmony_ci *result = original; 195cb93a386Sopenharmony_ci } 196cb93a386Sopenharmony_ci return success; 197cb93a386Sopenharmony_ci} 198