ShapeOps.cpp revision 7ba591eb7a7ff71127172bbf140491e18298a97a
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 */
77ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.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
2031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.comstatic Segment* findChaseOp(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
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;
2631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        tIndex = backPtr.fOtherIndex;
2731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkTDArray<Angle> angles;
2831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int done = 0;
2931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (segment->activeAngle(tIndex, done, angles)) {
3031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            Angle* last = angles.end() - 1;
3131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            tIndex = last->start();
3231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            endIndex = 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);
4531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#if DEBUG_SORT
4631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
4731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#endif
4831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (!sortable) {
4931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            continue;
5031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
5131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // find first angle, initialize winding to computed fWindSum
5231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int firstIndex = -1;
5331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        const Angle* angle;
5431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int winding;
5531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        do {
5631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            angle = sorted[++firstIndex];
5731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            segment = angle->segment();
5831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            winding = segment->windSum(angle);
5931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        } while (winding == SK_MinS32);
6031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int spanWinding = segment->spanSign(angle->start(), angle->end());
6131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #if DEBUG_WINDING
6231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        SkDebugf("%s winding=%d spanWinding=%d\n",
6331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                __FUNCTION__, winding, spanWinding);
6431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #endif
6531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // turn span winding into contour winding
6631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        if (spanWinding * winding < 0) {
6731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            winding += spanWinding;
6831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        }
6931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // we care about first sign and whether wind sum indicates this
7031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // edge is inside or outside. Maybe need to pass span winding
7131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // or first winding or something into this function?
7231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // advance to first undone angle, then return it and winding
7331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        // (to set whether edges are active or not)
7431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int nextIndex = firstIndex + 1;
7531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int angleCount = sorted.count();
7631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
7731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        angle = sorted[firstIndex];
7831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        segment = angle->segment();
7931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int oWinding = segment->oppSum(angle);
8031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #if DEBUG_SORT
8131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
8231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #endif
8331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        winding -= segment->spanSign(angle);
8457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        oWinding -= segment->oppSign(angle);
8531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        bool firstOperand = segment->operand();
8631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        do {
8731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkASSERT(nextIndex != firstIndex);
8831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            if (nextIndex == angleCount) {
8931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                nextIndex = 0;
9031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            }
9131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            angle = sorted[nextIndex];
9231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            segment = angle->segment();
9331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            int deltaSum = segment->spanSign(angle);
9457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            int deltaOppSum = segment->oppSign(angle);
9531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            bool angleIsOp = segment->operand() ^ firstOperand;
9631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            int maxWinding;
9731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            if (angleIsOp) {
9831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                maxWinding = oWinding;
9931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                oWinding -= deltaSum;
10057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                winding -= deltaOppSum;
10131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            } else {
10231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                maxWinding = winding;
10331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                winding -= deltaSum;
10457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                oWinding -= deltaOppSum;
10531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            }
10631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #if DEBUG_SORT
10731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            SkDebugf("%s id=%d maxWinding=%d winding=%d oWinding=%d sign=%d\n", __FUNCTION__,
10831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    segment->debugID(), maxWinding, winding, oWinding, angle->sign());
10931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    #endif
11031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            tIndex = angle->start();
11131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            endIndex = angle->end();
11231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            int lesser = SkMin32(tIndex, endIndex);
11331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            const Span& nextSpan = segment->span(lesser);
11431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            if (!nextSpan.fDone) {
11531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                if (angleIsOp) {
11631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    SkTSwap(winding, oWinding);
11731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                }
11831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                if (useInnerWinding(maxWinding, winding)) {
11931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    maxWinding = winding;
12031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                }
12131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                segment->markWinding(lesser, maxWinding, oWinding);
12231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                break;
12331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            }
12431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        } while (++nextIndex != lastIndex);
12531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #if TRY_ROTATE
12631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        *chase.insert(0) = span;
12731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #else
12831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        *chase.append() = span;
12931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com   #endif
13031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return segment;
13131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
13231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    return NULL;
133235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
134235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
13557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.comstatic bool windingIsActive(int winding, int oppWinding, int spanWinding, int oppSpanWinding,
13631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        bool windingIsOp, ShapeOp op) {
13731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool active = windingIsActive(winding, spanWinding);
13831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    if (!active) {
13931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        return false;
14031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    }
14157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    if (oppSpanWinding && windingIsActive(oppWinding, oppSpanWinding)) {
14257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        return op == kIntersect_Op || op == kUnion_Op;
14357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    }
14431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool opActive = oppWinding != 0;
14531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    return gOpLookup[op][opActive][windingIsOp];
14631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com}
14731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com
14857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.comstatic int updateWindings(const Segment* current, int index, int endIndex,
14957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        int& spanWinding, int& oppWinding, int& oppSpanWinding) {
15057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    int winding = updateWindings(current, index, endIndex, spanWinding);
15157cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    int lesser = SkMin32(index, endIndex);
15257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    oppWinding = current->oppSum(lesser);
15357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    oppSpanWinding = current->oppSign(index, endIndex);
15457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
15557cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        oppWinding -= oppSpanWinding;
15657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    }
15757cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    return winding;
15857cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com}
15957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com
16031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.comstatic bool bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
161f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        const int aXorMask, const int bXorMask, PathWrapper& simple) {
162235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    bool firstContour = true;
16331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool unsortable = false;
16431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    bool closable = true;
165f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
166235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    do {
167fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        int index, endIndex;
168f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com        Segment* current = findSortableTop(contourList, index, endIndex, topLeft);
169fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (!current) {
170fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            break;
171fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
17231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int contourWinding, oppContourWinding;
173235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        if (firstContour) {
17431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            contourWinding = oppContourWinding = 0;
175235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            firstContour = false;
176235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        } else {
1776ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com            int minIndex = SkMin32(index, endIndex);
1786ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com            int sumWinding = current->windSum(minIndex);
1796ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com            int oppSumWinding = current->oppSum(minIndex);
180235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            // FIXME: don't I have to adjust windSum to get contourWinding?
181235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (sumWinding == SK_MinS32) {
1826ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com                sumWinding = current->computeSum(index, endIndex, &oppSumWinding);
183235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
184235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (sumWinding == SK_MinS32) {
185235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                contourWinding = innerContourCheck(contourList, current,
18631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                        index, endIndex, false);
18731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                oppContourWinding = innerContourCheck(contourList, current,
18831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                        index, endIndex, true);
189235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            } else {
1906ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com                int spanWinding, oppWinding;
1917ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                contourWinding = updateWindings(current, index, endIndex, spanWinding,
1927ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com                        oppContourWinding, oppWinding);
193235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#if DEBUG_WINDING
1946ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com                SkDebugf("%s contourWinding=%d oppContourWinding=%d spanWinding=%d oppWinding=%d\n",
1956ec1526680bcc05b8b8b2c7ad9f78ba247e123b7caryclark@google.com                        __FUNCTION__, contourWinding, oppContourWinding, spanWinding, oppWinding);
196235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#endif
197235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
198235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#if DEBUG_WINDING
199235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com         //   SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding));
200235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding);
201235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com#endif
202235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        }
203235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        int winding = contourWinding;
20431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        int oppWinding = oppContourWinding;
205235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        int spanWinding = current->spanSign(index, endIndex);
20657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com        int oppSpanWinding = current->oppSign(index, endIndex);
207235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        SkTDArray<Span*> chaseArray;
208235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        do {
20957cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            bool active = windingIsActive(winding, oppWinding, spanWinding, oppSpanWinding,
21031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    current->operand(), op);
211235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        #if DEBUG_WINDING
21257cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            SkDebugf("%s active=%s winding=%d oppWinding=%d spanWinding=%d oppSpanWinding=%d\n",
213235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                    __FUNCTION__, active ? "true" : "false",
21457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                    winding, oppWinding, spanWinding, oppSpanWinding);
215235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        #endif
216235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            do {
21731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        #if DEBUG_ACTIVE_SPANS
21831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                if (!unsortable && current->done()) {
21931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    debugShowActiveSpans(contourList);
22031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                }
22131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com        #endif
22231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                SkASSERT(unsortable || !current->done());
223235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                int nextStart = index;
224235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                int nextEnd = endIndex;
225235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                Segment* next = current->findNextOp(chaseArray, active,
22657cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                        nextStart, nextEnd, winding, oppWinding, spanWinding, oppSpanWinding,
22731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                        unsortable, op, aXorMask, bXorMask);
228235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                if (!next) {
229c91dfe417a51f73c28ecf2708df1e0bee942c6eacaryclark@google.com                    SkASSERT(!unsortable);
23031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    if (active && !unsortable && simple.hasMove()
231f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                            && current->verb() != SkPath::kLine_Verb
232f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                            && !simple.isClosed()) {
23331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                        current->addCurveTo(index, endIndex, simple, true);
234f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com                        SkASSERT(simple.isClosed());
235235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                    }
236235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                    break;
237235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                }
23831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                current->addCurveTo(index, endIndex, simple, active);
239235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                current = next;
240235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                index = nextStart;
241235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                endIndex = nextEnd;
24231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            } while (!simple.isClosed()
24331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    && ((active && !unsortable) || !current->done()));
24431143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            if (active) {
24531143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                if (!simple.isClosed()) {
24631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    SkASSERT(unsortable);
24731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    int min = SkMin32(index, endIndex);
24831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    if (!current->done(min)) {
24931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                        current->addCurveTo(index, endIndex, simple, true);
25031143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                        current->markDone(SkMin32(index, endIndex), winding ? winding : spanWinding);
25131143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    }
25231143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                    closable = false;
25331143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com                }
254235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                simple.close();
255235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
25631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com            current = findChaseOp(chaseArray, index, endIndex);
257235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        #if DEBUG_ACTIVE_SPANS
258235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            debugShowActiveSpans(contourList);
259235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        #endif
260235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            if (!current) {
261235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com                break;
262235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            }
26357cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com            winding = updateWindings(current, index, endIndex, spanWinding, oppWinding,
26457cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com                    oppSpanWinding);
265235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        } while (true);
266235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    } while (true);
26731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    return closable;
268235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
269235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
270235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com} // end of Op namespace
271235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
272235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
273235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comvoid operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) {
274235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    result.reset();
275235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    result.setFillType(SkPath::kEvenOdd_FillType);
276235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // turn path into list of segments
277235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkTArray<Op::Contour> contours;
278235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // FIXME: add self-intersecting cubics' T values to segment
279235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::EdgeBuilder builder(one, contours);
280235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    const int aXorMask = builder.xorMask();
281235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    builder.addOperand(two);
282235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    const int bXorMask = builder.xorMask();
283235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    builder.finish();
284235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    SkTDArray<Op::Contour*> contourList;
285235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    makeContourList(contours, contourList);
286235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::Contour** currentPtr = contourList.begin();
287235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    if (!currentPtr) {
288235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return;
289235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
290235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    Op::Contour** listEnd = contourList.end();
291235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // find all intersections between segments
292235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    do {
293235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour** nextPtr = currentPtr;
294235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour* current = *currentPtr++;
295235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        Op::Contour* next;
296235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        do {
297235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com            next = *nextPtr++;
298235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        } while (addIntersectTs(current, next) && nextPtr != listEnd);
299235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    } while (currentPtr != listEnd);
300235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // eat through coincident edges
3017ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com
3027ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    int total = 0;
3037ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    int index;
3047ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    for (index = 0; index < contourList.count(); ++index) {
3057ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com        total += contourList[index]->segments().count();
3067ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    }
3077ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#if DEBUG_WINDING
3087ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    Op::Contour::debugShowWindingValues(contourList);
3097ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#endif
31057cff8dbdfb32b3fea426519a4fdc05f13be69d9caryclark@google.com    coincidenceCheck(contourList, (aXorMask == kEvenOdd_Mask)
3117ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com            ^ (bXorMask == kEvenOdd_Mask), total);
3127ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#if DEBUG_WINDING
3137ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com    Op::Contour::debugShowWindingValues(contourList);
3147ba591eb7a7ff71127172bbf140491e18298a97acaryclark@google.com#endif
315235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    fixOtherTIndex(contourList);
31631143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    sortSegments(contourList);
31731143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#if DEBUG_ACTIVE_SPANS
31831143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com    debugShowActiveSpans(contourList);
31931143cf37fa38dc98f71c71e518ecc21c83b5e27caryclark@google.com#endif
320235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    // construct closed contours
321f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    Op::PathWrapper wrapper(result);
322f839c0359c308fd06895d9f73fc12c4f3869e399caryclark@google.com    bridgeOp(contourList, op, aXorMask, bXorMask, wrapper);
323235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
324