ShapeOps.cpp revision db0b3e099f888213535c4ad4c785b84544309033
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            }
7531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            angle = sorted[nextIndex];
7631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            segment = angle->segment();
777fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            int start = angle->start();
787fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            int end = angle->end();
79db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
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
13231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.comstatic bool bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
1337fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com        const int xorMask, const int xorOpMask, PathWrapper& simple) {
134235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool firstContour = true;
13531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool unsortable = false;
136e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    bool topUnsortable = false;
137e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com    bool firstRetry = false;
13831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool closable = true;
139f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
140235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    do {
141fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        int index, endIndex;
142db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com        bool done;
143e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com        Segment* current = findSortableTopNew(contourList, firstContour, index, endIndex, topLeft,
144db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com                topUnsortable, done, true);
145fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (!current) {
146db0b3e099f888213535c4ad4c785b84544309033caryclark@google.com            if (topUnsortable || !done) {
147e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                topUnsortable = false;
148e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                SkASSERT(!firstRetry);
149e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                firstRetry = true;
150e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                topLeft.fX = topLeft.fY = SK_ScalarMin;
151e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com                continue;
152235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
153e7bd5f4041701cbab87f6e779eb18fbb9fe74216caryclark@google.com            break;
154235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
155235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkTDArray<Span*> chaseArray;
156235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        do {
1577fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) {
1587fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                bool active = true;
1597fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                do {
1607fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            #if DEBUG_ACTIVE_SPANS
1617fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    if (!unsortable && current->done()) {
1627fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        debugShowActiveSpans(contourList);
163235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                    }
1647fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            #endif
1657fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    SkASSERT(unsortable || !current->done());
1667fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    int nextStart = index;
1677fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    int nextEnd = endIndex;
1687fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    Segment* next = current->findNextOp(chaseArray, nextStart, nextEnd,
1697fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                            unsortable, op, xorMask, xorOpMask);
1707fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    if (!next) {
1717fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        SkASSERT(!unsortable);
1727fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        if (!unsortable && simple.hasMove()
1737fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                                && current->verb() != SkPath::kLine_Verb
1747fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                                && !simple.isClosed()) {
1757fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                            current->addCurveTo(index, endIndex, simple, true);
1767fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                            SkASSERT(simple.isClosed());
1777fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        }
1787fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        active = false;
1797fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        break;
1807fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    }
1817fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    current->addCurveTo(index, endIndex, simple, true);
1827fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    current = next;
1837fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    index = nextStart;
1847fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    endIndex = nextEnd;
1857fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                } while (!simple.isClosed() && ((!unsortable) || !current->done()));
1867fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                if (active && !simple.isClosed()) {
18731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    SkASSERT(unsortable);
18831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    int min = SkMin32(index, endIndex);
18931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    if (!current->done(min)) {
19031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                        current->addCurveTo(index, endIndex, simple, true);
1917fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                        current->markDoneBinary(min);
19231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    }
19331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    closable = false;
19431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                }
195235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                simple.close();
1967fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com            } else {
1977fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                Span* last = current->markAndChaseDoneBinary(index, endIndex);
1987fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                if (last) {
1997fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                    *chaseArray.append() = last;
2007fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com                }
201235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
20231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            current = findChaseOp(chaseArray, index, endIndex);
203235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        #if DEBUG_ACTIVE_SPANS
204235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            debugShowActiveSpans(contourList);
205235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        #endif
206235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (!current) {
207235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                break;
208235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
209235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        } while (true);
210235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    } while (true);
21131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    return closable;
212235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
213235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
214235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com} // end of Op namespace
215235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
216235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
217235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comvoid operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) {
218235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    result.reset();
219235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    result.setFillType(SkPath::kEvenOdd_FillType);
220235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // turn path into list of segments
221235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkTArray<Op::Contour> contours;
222235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // FIXME: add self-intersecting cubics' T values to segment
223235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::EdgeBuilder builder(one, contours);
2247fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    const int xorMask = builder.xorMask();
225235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    builder.addOperand(two);
226235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    builder.finish();
2277fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    const int xorOpMask = builder.xorMask();
228235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkTDArray<Op::Contour*> contourList;
2294eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    makeContourList(contours, contourList, xorMask == kEvenOdd_Mask,
2304eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com            xorOpMask == kEvenOdd_Mask);
231235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::Contour** currentPtr = contourList.begin();
232235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    if (!currentPtr) {
233235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return;
234235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
235235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::Contour** listEnd = contourList.end();
236235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // find all intersections between segments
237235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    do {
238235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour** nextPtr = currentPtr;
239235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour* current = *currentPtr++;
240235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour* next;
241235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        do {
242235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            next = *nextPtr++;
243235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        } while (addIntersectTs(current, next) && nextPtr != listEnd);
244235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    } while (currentPtr != listEnd);
245235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // eat through coincident edges
246b0a327e9390da5865d4c56db5e5259adc3380d37skia.committer@gmail.com
2477ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    int total = 0;
2487ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    int index;
2497ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    for (index = 0; index < contourList.count(); ++index) {
2507ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        total += contourList[index]->segments().count();
2517ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    }
252729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#if DEBUG_SHOW_WINDING
2537ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    Op::Contour::debugShowWindingValues(contourList);
2547ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#endif
2554eeda37a7456876cb8d509a4ea43c7f4c684477acaryclark@google.com    coincidenceCheck(contourList, total);
256729e1c46cea63dfaa6e4a05608b8f3be41e19dcecaryclark@google.com#if DEBUG_SHOW_WINDING
2577ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    Op::Contour::debugShowWindingValues(contourList);
2587ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#endif
259235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    fixOtherTIndex(contourList);
26031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    sortSegments(contourList);
26131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#if DEBUG_ACTIVE_SPANS
26231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    debugShowActiveSpans(contourList);
26331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#endif
264235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // construct closed contours
265f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    Op::PathWrapper wrapper(result);
2667fce0de0b9674ca6cc65ebbb40b924b615d9fc9ecaryclark@google.com    bridgeOp(contourList, op, xorMask, xorOpMask, wrapper);
267235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
268