ShapeOps.cpp revision fb51afb03e76c5701fffaa847584a8b7b2c18a7e
1235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com/* 2235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com * Copyright 2012 Google Inc. 3235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com * 4235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com * Use of this source code is governed by a BSD-style license that can be 5235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com * found in the LICENSE file. 6235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com */ 7235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#include "Simplify.h" 8235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com 9235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comnamespace Op { 10235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com 11235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#include "Simplify.cpp" 12235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com 13235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comstatic bool windingIsActive(int winding, int spanWinding, int oppWinding, 14235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com const ShapeOp op) { 15235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding) 16235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com && (!winding || !spanWinding || winding == -spanWinding); 17235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com} 18235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com 19055c7c299cb47eebd360b809ad58a0006e2e55f7skia.committer@gmail.comstatic void bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op, 20235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com const int aXorMask, const int bXorMask, SkPath& simple) { 21235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com bool firstContour = true; 22235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com do { 23fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com 24fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com#if SORTABLE_CONTOURS // old way 25235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Segment* topStart = findTopContour(contourList); 26235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (!topStart) { 27235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com break; 28235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 29235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // Start at the top. Above the top is outside, below is inside. 30235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // follow edges to intersection by changing the index by direction. 31235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int index, endIndex; 32235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Segment* current = topStart->findTop(index, endIndex); 33fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com#else // new way: iterate while top is unsortable 34fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com int index, endIndex; 35fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com Segment* current = findSortableTop(contourList, index, endIndex); 36fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com if (!current) { 37fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com break; 38fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com } 39fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com#endif 40235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int contourWinding; 41235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (firstContour) { 42235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com contourWinding = 0; 43235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com firstContour = false; 44235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } else { 45235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int sumWinding = current->windSum(SkMin32(index, endIndex)); 46235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // FIXME: don't I have to adjust windSum to get contourWinding? 47235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (sumWinding == SK_MinS32) { 48235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com sumWinding = current->computeSum(index, endIndex); 49235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 50235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (sumWinding == SK_MinS32) { 51235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com contourWinding = innerContourCheck(contourList, current, 52235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com index, endIndex); 53235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } else { 54235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com contourWinding = sumWinding; 55235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int spanWinding = current->spanSign(index, endIndex); 56235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com bool inner = useInnerWinding(sumWinding - spanWinding, sumWinding); 57235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (inner) { 58235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com contourWinding -= spanWinding; 59235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 60235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#if DEBUG_WINDING 61235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n", __FUNCTION__, 62235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com sumWinding, spanWinding, SkSign32(index - endIndex), 63235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com inner, contourWinding); 64235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#endif 65235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 66235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#if DEBUG_WINDING 67235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding)); 68235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding); 69235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#endif 70235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 71235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkPoint lastPt; 72235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int winding = contourWinding; 73235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int spanWinding = current->spanSign(index, endIndex); 74235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int oppWinding = current->oppSign(index, endIndex); 75235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com bool active = windingIsActive(winding, spanWinding, oppWinding, op); 76235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkTDArray<Span*> chaseArray; 77c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com bool unsortable = false; 78235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com do { 79235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com #if DEBUG_WINDING 80235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkDebugf("%s active=%s winding=%d spanWinding=%d\n", 81235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com __FUNCTION__, active ? "true" : "false", 82235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com winding, spanWinding); 83235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com #endif 84235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com const SkPoint* firstPt = NULL; 85235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com do { 86235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkASSERT(!current->done()); 87235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int nextStart = index; 88235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int nextEnd = endIndex; 89235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Segment* next = current->findNextOp(chaseArray, active, 90c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com nextStart, nextEnd, winding, spanWinding, unsortable, op, 91235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com aXorMask, bXorMask); 92235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (!next) { 93c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com // FIXME: if unsortable, allow partial paths to be later 94c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com // assembled 95c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com SkASSERT(!unsortable); 96235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (active && firstPt && current->verb() != SkPath::kLine_Verb && *firstPt != lastPt) { 97235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com lastPt = current->addCurveTo(index, endIndex, simple, true); 98235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkASSERT(*firstPt == lastPt); 99235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 100235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com break; 101235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 102235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (!firstPt) { 103235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com firstPt = ¤t->addMoveTo(index, simple, active); 104235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 105235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com lastPt = current->addCurveTo(index, endIndex, simple, active); 106235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com current = next; 107235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com index = nextStart; 108235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com endIndex = nextEnd; 109235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } while (*firstPt != lastPt && (active || !current->done())); 110235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (firstPt && active) { 111235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com #if DEBUG_PATH_CONSTRUCTION 112235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkDebugf("%s close\n", __FUNCTION__); 113235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com #endif 114235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com simple.close(); 115235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 116235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com current = findChase(chaseArray, index, endIndex, contourWinding); 117235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com #if DEBUG_ACTIVE_SPANS 118235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com debugShowActiveSpans(contourList); 119235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com #endif 120235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (!current) { 121235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com break; 122235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 123235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int lesser = SkMin32(index, endIndex); 124235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com spanWinding = current->spanSign(index, endIndex); 125235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com winding = current->windSum(lesser); 126235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com bool inner = useInnerWinding(winding - spanWinding, winding); 127235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com #if DEBUG_WINDING 128235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d" 129235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com " inner=%d result=%d\n", 130235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com __FUNCTION__, current->debugID(), current->t(lesser), 131235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com spanWinding, winding, SkSign32(index - endIndex), 132235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com useInnerWinding(winding - spanWinding, winding), 133235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com inner ? winding - spanWinding : winding); 134235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com #endif 135235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (inner) { 136235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com winding -= spanWinding; 137235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 138235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com int oppWinding = current->oppSign(index, endIndex); 139235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com active = windingIsActive(winding, spanWinding, oppWinding, op); 140235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } while (true); 141235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } while (true); 142235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com} 143235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com 144235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com} // end of Op namespace 145235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com 146235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com 147235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comvoid operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) { 148235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com result.reset(); 149235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com result.setFillType(SkPath::kEvenOdd_FillType); 150235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // turn path into list of segments 151235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkTArray<Op::Contour> contours; 152235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // FIXME: add self-intersecting cubics' T values to segment 153235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Op::EdgeBuilder builder(one, contours); 154235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com const int aXorMask = builder.xorMask(); 155235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com builder.addOperand(two); 156235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com const int bXorMask = builder.xorMask(); 157235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com builder.finish(); 158235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com SkTDArray<Op::Contour*> contourList; 159235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com makeContourList(contours, contourList); 160235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Op::Contour** currentPtr = contourList.begin(); 161235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com if (!currentPtr) { 162235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com return; 163235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } 164235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Op::Contour** listEnd = contourList.end(); 165235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // find all intersections between segments 166235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com do { 167235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Op::Contour** nextPtr = currentPtr; 168235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Op::Contour* current = *currentPtr++; 169235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com Op::Contour* next; 170235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com do { 171235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com next = *nextPtr++; 172235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } while (addIntersectTs(current, next) && nextPtr != listEnd); 173235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com } while (currentPtr != listEnd); 174235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // eat through coincident edges 175235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com coincidenceCheck(contourList); 176235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com fixOtherTIndex(contourList); 177235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com // construct closed contours 178235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com bridgeOp(contourList, op, aXorMask, bXorMask, result); 179235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com} 180