ShapeOps.cpp revision e7bd5f4041701cbab87f6e779eb18fbb9fe74216
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 */
7b0a327e9390da5865d4c56db5e5259adc3380d37skia.committer@gmail.com
8235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#include "Simplify.h"
9235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
10235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comnamespace Op {
11235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
127ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#define INCLUDED_BY_SHAPE_OPS 1
137ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com
14235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#include "Simplify.cpp"
15235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
1631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com// FIXME: this and find chase should be merge together, along with
1731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com// other code that walks winding in angles
1831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com// OPTIMIZATION: Probably, the walked winding should be rolled into the angle structure
1931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com// so it isn't duplicated by walkers like this one
207fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.comstatic Segment* findChaseOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd) {
2131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    while (chase.count()) {
2231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        Span* span;
2331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        chase.pop(&span);
2431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        const Span& backPtr = span->fOther->span(span->fOtherIndex);
2531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        Segment* segment = backPtr.fOther;
267fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        nextStart = backPtr.fOtherIndex;
2731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkTDArray<Angle> angles;
2831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int done = 0;
297fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (segment->activeAngle(nextStart, done, angles)) {
3031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            Angle* last = angles.end() - 1;
317fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            nextStart = last->start();
327fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            nextEnd = last->end();
3331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #if TRY_ROTATE
3431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            *chase.insert(0) = span;
3531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #else
3631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            *chase.append() = span;
3731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #endif
3831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            return last->segment();
3931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
4031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (done == angles.count()) {
4131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            continue;
4231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
4331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkTDArray<Angle*> sorted;
4431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        bool sortable = Segment::SortAngles(angles, sorted);
457fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int angleCount = sorted.count();
4631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#if DEBUG_SORT
477fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0);
4831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#endif
4931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (!sortable) {
5031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            continue;
5131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
5231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // find first angle, initialize winding to computed fWindSum
5331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int firstIndex = -1;
5431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        const Angle* angle;
5531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        do {
5631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            angle = sorted[++firstIndex];
5731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            segment = angle->segment();
587fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        } while (segment->windSum(angle) == SK_MinS32);
597fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    #if DEBUG_SORT
607fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
6131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #endif
627fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int sumMiWinding = segment->updateWindingReverse(angle);
637fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        int sumSuWinding = segment->updateOppWindingReverse(angle);
647fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (segment->operand()) {
657fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            SkTSwap<int>(sumMiWinding, sumSuWinding);
6631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
6731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int nextIndex = firstIndex + 1;
6831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
697fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        Segment* first = NULL;
7031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        do {
7131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkASSERT(nextIndex != firstIndex);
7231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            if (nextIndex == angleCount) {
7331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                nextIndex = 0;
7431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            }
757fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
7631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            angle = sorted[nextIndex];
7731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            segment = angle->segment();
787fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            int start = angle->start();
797fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            int end = angle->end();
807fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            segment->setUpWindings(start, end, sumMiWinding, sumSuWinding,
817fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
827fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            if (!segment->done(angle)) {
837fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                if (!first) {
847fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    first = segment;
857fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    nextStart = start;
867fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    nextEnd = end;
8731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                }
887fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding,
897fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    oppSumWinding, true, angle);
9031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            }
9131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        } while (++nextIndex != lastIndex);
927fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        if (first) {
937fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com       #if TRY_ROTATE
947fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            *chase.insert(0) = span;
957fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com       #else
967fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            *chase.append() = span;
977fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com       #endif
987fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            return first;
997fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
10031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
10131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    return NULL;
102235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
103235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
1047fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com/*
10557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.comstatic bool windingIsActive(int winding, int oppWinding, int spanWinding, int oppSpanWinding,
10631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        bool windingIsOp, ShapeOp op) {
10731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool active = windingIsActive(winding, spanWinding);
10831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    if (!active) {
10931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return false;
11031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
11157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    if (oppSpanWinding && windingIsActive(oppWinding, oppSpanWinding)) {
1127fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        switch (op) {
1137fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            case kIntersect_Op:
1147fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            case kUnion_Op:
1157fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                return true;
1167fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            case kDifference_Op: {
1177fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                int absSpan = abs(spanWinding);
1187fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                int absOpp = abs(oppSpanWinding);
1197fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                return windingIsOp ? absSpan < absOpp : absSpan > absOpp;
1207fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            }
1217fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            case kXor_Op:
1227fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                return spanWinding != oppSpanWinding;
1237fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            default:
1247fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                SkASSERT(0);
1257fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        }
12657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    }
12731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool opActive = oppWinding != 0;
12831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    return gOpLookup[op][opActive][windingIsOp];
12931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com}
1307fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com*/
13157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com
132e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.comstatic Segment* findSortableTopNew(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
133e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int& endIndex, SkPoint& topLeft, bool& unsortable) {
134e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    Segment* current;
135e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    bool allowTies = true;
136e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    bool first = true;
137e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    do {
138e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, allowTies,
139e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                true);
140e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (!current) {
141e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            if (first) {
142e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                return NULL;
143e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            }
144e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            break;
145e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
146e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        first = false;
147e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (firstContour) {
148e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            current->initWinding(index, endIndex, 0, 0);
149e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            firstContour = false;
150e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            return current;
151e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
152e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int minIndex = SkMin32(index, endIndex);
153e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int sumWinding = current->windSum(minIndex);
154e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (sumWinding == SK_MinS32) {
155e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            sumWinding = current->computeSum(index, endIndex, true);
156e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            if (sumWinding != SK_MinS32) {
157e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                return current;
158e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            }
159e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
160e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        allowTies = false;
161e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int contourWinding = innerContourCheck(contourList, current, index, endIndex, false);
162e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (contourWinding == SK_MinS32) {
163e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            continue;
164e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
165e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        int oppContourWinding = innerContourCheck(contourList, current, index, endIndex, true);
166e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        if (oppContourWinding == SK_MinS32) {
167e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            continue;
168e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        }
169e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        current->initWinding(index, endIndex, contourWinding, oppContourWinding);
170e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        return current;
171e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    } while (true);
172e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    // the simple upward projection of the unresolved points hit unsortable angles
173e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    // shoot rays at right angles to the segment to find its winding, ignoring angle cases
174e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    SkASSERT(0); // steal code from findSortableTopOld and put it here
175e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    return current;
176e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com}
177e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com
17831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.comstatic bool bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
1797fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        const int xorMask, const int xorOpMask, PathWrapper& simple) {
180235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool firstContour = true;
18131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool unsortable = false;
182e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    bool topUnsortable = false;
183e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    bool firstRetry = false;
18431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool closable = true;
185f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
186235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    do {
187fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        int index, endIndex;
188e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        Segment* current = findSortableTopNew(contourList, firstContour, index, endIndex, topLeft,
189e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                topUnsortable);
190fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (!current) {
191e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            if (topUnsortable) {
192e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                topUnsortable = false;
193e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                SkASSERT(!firstRetry);
194e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                firstRetry = true;
195e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                topLeft.fX = topLeft.fY = SK_ScalarMin;
196e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                continue;
197235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
198e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            break;
199235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
200235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkTDArray<Span*> chaseArray;
201235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        do {
2027fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) {
2037fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                bool active = true;
2047fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                do {
2057fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            #if DEBUG_ACTIVE_SPANS
2067fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    if (!unsortable && current->done()) {
2077fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        debugShowActiveSpans(contourList);
208235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                    }
2097fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            #endif
2107fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    SkASSERT(unsortable || !current->done());
2117fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    int nextStart = index;
2127fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    int nextEnd = endIndex;
2137fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    Segment* next = current->findNextOp(chaseArray, nextStart, nextEnd,
2147fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                            unsortable, op, xorMask, xorOpMask);
2157fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    if (!next) {
2167fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        SkASSERT(!unsortable);
2177fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        if (!unsortable && simple.hasMove()
2187fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                                && current->verb() != SkPath::kLine_Verb
2197fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                                && !simple.isClosed()) {
2207fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                            current->addCurveTo(index, endIndex, simple, true);
2217fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                            SkASSERT(simple.isClosed());
2227fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        }
2237fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        active = false;
2247fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        break;
2257fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    }
2267fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    current->addCurveTo(index, endIndex, simple, true);
2277fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    current = next;
2287fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    index = nextStart;
2297fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    endIndex = nextEnd;
2307fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                } while (!simple.isClosed() && ((!unsortable) || !current->done()));
2317fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                if (active && !simple.isClosed()) {
23231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    SkASSERT(unsortable);
23331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    int min = SkMin32(index, endIndex);
23431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    if (!current->done(min)) {
23531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                        current->addCurveTo(index, endIndex, simple, true);
2367fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        current->markDoneBinary(min);
23731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    }
23831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    closable = false;
23931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                }
240235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                simple.close();
2417fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            } else {
2427fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                Span* last = current->markAndChaseDoneBinary(index, endIndex);
2437fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                if (last) {
2447fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    *chaseArray.append() = last;
2457fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                }
246235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
24731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            current = findChaseOp(chaseArray, index, endIndex);
248235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        #if DEBUG_ACTIVE_SPANS
249235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            debugShowActiveSpans(contourList);
250235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        #endif
251235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (!current) {
252235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                break;
253235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
254235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        } while (true);
255235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    } while (true);
25631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    return closable;
257235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
258235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
259235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com} // end of Op namespace
260235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
261235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
262235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comvoid operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) {
263235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    result.reset();
264235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    result.setFillType(SkPath::kEvenOdd_FillType);
265235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // turn path into list of segments
266235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkTArray<Op::Contour> contours;
267235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // FIXME: add self-intersecting cubics' T values to segment
268235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::EdgeBuilder builder(one, contours);
2697fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    const int xorMask = builder.xorMask();
270235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    builder.addOperand(two);
271235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    builder.finish();
2727fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    const int xorOpMask = builder.xorMask();
273235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkTDArray<Op::Contour*> contourList;
2744eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    makeContourList(contours, contourList, xorMask == kEvenOdd_Mask,
2754eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            xorOpMask == kEvenOdd_Mask);
276235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::Contour** currentPtr = contourList.begin();
277235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    if (!currentPtr) {
278235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return;
279235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
280235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::Contour** listEnd = contourList.end();
281235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // find all intersections between segments
282235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    do {
283235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour** nextPtr = currentPtr;
284235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour* current = *currentPtr++;
285235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour* next;
286235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        do {
287235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            next = *nextPtr++;
288235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        } while (addIntersectTs(current, next) && nextPtr != listEnd);
289235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    } while (currentPtr != listEnd);
290235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // eat through coincident edges
291b0a327e9390da5865d4c56db5e5259adc3380d37skia.committer@gmail.com
2927ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    int total = 0;
2937ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    int index;
2947ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    for (index = 0; index < contourList.count(); ++index) {
2957ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        total += contourList[index]->segments().count();
2967ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    }
297729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#if DEBUG_SHOW_WINDING
2987ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    Op::Contour::debugShowWindingValues(contourList);
2997ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#endif
3004eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    coincidenceCheck(contourList, total);
301729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#if DEBUG_SHOW_WINDING
3027ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    Op::Contour::debugShowWindingValues(contourList);
3037ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#endif
304235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    fixOtherTIndex(contourList);
30531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    sortSegments(contourList);
30631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#if DEBUG_ACTIVE_SPANS
30731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    debugShowActiveSpans(contourList);
30831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#endif
309235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // construct closed contours
310f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    Op::PathWrapper wrapper(result);
3117fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    bridgeOp(contourList, op, xorMask, xorOpMask, wrapper);
312235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
313