1170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
2170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com/*
3170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com * Copyright 2012 Google Inc.
4170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com *
5170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be
6170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com * found in the LICENSE file.
7170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com */
8170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
9170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com#include "GrReducedClip.h"
10170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
11170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.comtypedef SkClipStack::Element Element;
12170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
13170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
14170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.comnamespace GrReducedClip {
15170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
1634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com// helper function
1734cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.comvoid reduced_stack_walker(const SkClipStack& stack,
1834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                          const SkRect& queryBounds,
1934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                          ElementList* result,
20d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                          int32_t* resultGenID,
2134cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                          InitialState* initialState,
2234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                          bool* requiresAA);
2334cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com
24170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com/*
25c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.comThere are plenty of optimizations that could be added here. Maybe flips could be folded into
26170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.comearlier operations. Or would inserting flips and reversing earlier ops ever be a win? Perhaps
27170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.comfor the case where the bounds are kInsideOut_BoundsType. We could restrict earlier operations
28170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.combased on later intersect operations, and perhaps remove intersect-rects. We could optionally
29170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.comtake a rect in case the caller knows a bound on what is to be drawn through this clip.
30170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com*/
3134cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.comvoid ReduceClipStack(const SkClipStack& stack,
3234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                     const SkIRect& queryBounds,
3334cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                     ElementList* result,
34d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                     int32_t* resultGenID,
3534cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                     InitialState* initialState,
3634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                     SkIRect* tighterBounds,
3734cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                     bool* requiresAA) {
38170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    result->reset();
39170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
40d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    // The clip established by the element list might be cached based on the last
41d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    // generation id. When we make early returns, we do not know what was the generation
42d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    // id that lead to the state. Make a conservative guess.
43d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    *resultGenID = stack.getTopmostGenID();
44d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org
45170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    if (stack.isWideOpen()) {
46170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        *initialState = kAllIn_InitialState;
47170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        return;
48170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    }
49170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
5034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com
5134cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com    // We initially look at whether the bounds alone is sufficient. We also use the stack bounds to
5234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com    // attempt to compute the tighterBounds.
5334cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com
54170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    SkClipStack::BoundsType stackBoundsType;
55170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    SkRect stackBounds;
56170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    bool iior;
57170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    stack.getBounds(&stackBounds, &stackBoundsType, &iior);
58170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
5934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com    const SkIRect* bounds = &queryBounds;
6034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com
614469938e92d779dff05e745559e67907bbf21e78reed@google.com    SkRect scalarQueryBounds = SkRect::Make(queryBounds);
6234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com
63170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    if (iior) {
64170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
65170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        SkRect isectRect;
6634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com        if (stackBounds.contains(scalarQueryBounds)) {
67170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            *initialState = kAllIn_InitialState;
6834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            if (NULL != tighterBounds) {
6934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                *tighterBounds = queryBounds;
7034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            }
7134cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            if (NULL != requiresAA) {
7234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com               *requiresAA = false;
7334cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            }
7434cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com        } else if (isectRect.intersect(stackBounds, scalarQueryBounds)) {
75e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            // If the caller asked for tighter integer bounds we may be able to
76e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            // return kAllIn and give the bounds with no elements
7734cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            if (NULL != tighterBounds) {
7834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                isectRect.roundOut(tighterBounds);
794469938e92d779dff05e745559e67907bbf21e78reed@google.com                SkRect scalarTighterBounds = SkRect::Make(*tighterBounds);
8034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                if (scalarTighterBounds == isectRect) {
8134cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                    // the round-out didn't add any area outside the clip rect.
82d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                    if (NULL != requiresAA) {
83d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                        *requiresAA = false;
84d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                    }
8534cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                    *initialState = kAllIn_InitialState;
8634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                    return;
8734cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                }
88e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            }
89e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            *initialState = kAllOut_InitialState;
90e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            // iior should only be true if aa/non-aa status matches among all elements.
91e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
92e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            bool doAA = iter.prev()->isAA();
93e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            SkNEW_INSERT_AT_LLIST_HEAD(result, Element, (isectRect, SkRegion::kReplace_Op, doAA));
94e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            if (NULL != requiresAA) {
95e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                *requiresAA = doAA;
9634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            }
97170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        } else {
98170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            *initialState = kAllOut_InitialState;
9934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com             if (NULL != requiresAA) {
10034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                *requiresAA = false;
10134cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com             }
102170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        }
103170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        return;
104170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    } else {
105170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
10634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            if (!SkRect::Intersects(stackBounds, scalarQueryBounds)) {
107170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                *initialState = kAllOut_InitialState;
10834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                if (NULL != requiresAA) {
10934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                   *requiresAA = false;
11034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                }
111170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                return;
112170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            }
11334cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            if (NULL != tighterBounds) {
11434cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                SkIRect stackIBounds;
11534cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                stackBounds.roundOut(&stackIBounds);
11634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                tighterBounds->intersect(queryBounds, stackIBounds);
11734cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                bounds = tighterBounds;
11834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            }
119170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        } else {
12034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            if (stackBounds.contains(scalarQueryBounds)) {
121170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                *initialState = kAllOut_InitialState;
12234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                if (NULL != requiresAA) {
12334cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                   *requiresAA = false;
12434cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                }
125170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                return;
126170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            }
12734cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            if (NULL != tighterBounds) {
12834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                *tighterBounds = queryBounds;
12934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com            }
130170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        }
131170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    }
132170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
1334469938e92d779dff05e745559e67907bbf21e78reed@google.com    SkRect scalarBounds = SkRect::Make(*bounds);
134d21444aab7128c97f4e0eb5e9bf05111d5037292skia.committer@gmail.com
13534cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com    // Now that we have determined the bounds to use and filtered out the trivial cases, call the
13634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com    // helper that actually walks the stack.
137d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    reduced_stack_walker(stack, scalarBounds, result, resultGenID, initialState, requiresAA);
138d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org
139d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    // The list that was computed in this function may be cached based on the gen id of the last
140d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    // element.
141d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    SkASSERT(SkClipStack::kInvalidGenID != *resultGenID);
14234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com}
14334cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com
14434cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.comvoid reduced_stack_walker(const SkClipStack& stack,
14534cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                          const SkRect& queryBounds,
14634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                          ElementList* result,
147d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                          int32_t* resultGenID,
14834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                          InitialState* initialState,
14934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                          bool* requiresAA) {
15034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com
151170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    // walk backwards until we get to:
152170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    //  a) the beginning
153170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    //  b) an operation that is known to make the bounds all inside/outside
154170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    //  c) a replace operation
155170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
156170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    static const InitialState kUnknown_InitialState = static_cast<InitialState>(-1);
157170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    *initialState = kUnknown_InitialState;
158170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
159170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    // During our backwards walk, track whether we've seen ops that either grow or shrink the clip.
160170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    // TODO: track these per saved clip so that we can consider them on the forward pass.
161170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    bool embiggens = false;
162170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    bool emsmallens = false;
163170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
164170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
16534cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com    int numAAElements = 0;
166170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    while ((kUnknown_InitialState == *initialState)) {
167170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        const Element* element = iter.prev();
168170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        if (NULL == element) {
169170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            *initialState = kAllIn_InitialState;
170170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            break;
171170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        }
172170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        if (SkClipStack::kEmptyGenID == element->getGenID()) {
173170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            *initialState = kAllOut_InitialState;
174170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            break;
175170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        }
176170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        if (SkClipStack::kWideOpenGenID == element->getGenID()) {
177170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            *initialState = kAllIn_InitialState;
178170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            break;
179170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        }
180170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
181170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        bool skippable = false;
182170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
183170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
184170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        switch (element->getOp()) {
185170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            case SkRegion::kDifference_Op:
186170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // check if the shape subtracted either contains the entire bounds (and makes
187170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // the clip empty) or is outside the bounds and therefore can be skipped.
188170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (element->isInverseFilled()) {
189170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
190170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
191170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
192170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
193170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
194170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
195170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                } else {
196170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
197170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
198170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
199170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
200170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
201170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
202170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
203170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (!skippable) {
204170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    emsmallens = true;
205170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
206170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                break;
207170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            case SkRegion::kIntersect_Op:
208170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // check if the shape intersected contains the entire bounds and therefore can
209170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // be skipped or it is outside the entire bounds and therefore makes the clip
210170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // empty.
211170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (element->isInverseFilled()) {
212170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
213170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
214170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
215170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
216170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
217170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
218170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                } else {
219170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
220170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
221170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
222170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
223170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
224170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
225170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
226170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (!skippable) {
227170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    emsmallens = true;
228170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
229170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                break;
230170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            case SkRegion::kUnion_Op:
231170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // If the union-ed shape contains the entire bounds then after this element
232170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // the bounds is entirely inside the clip. If the union-ed shape is outside the
233170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // bounds then this op can be skipped.
234170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (element->isInverseFilled()) {
235170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
236170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
237170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
238170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllIn_InitialState;
239170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
240170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
241170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                } else {
242170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
243170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllIn_InitialState;
244170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
245170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
246170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
247170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
248170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
249170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (!skippable) {
250170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    embiggens = true;
251170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
252170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                break;
253170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            case SkRegion::kXOR_Op:
254170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // If the bounds is entirely inside the shape being xor-ed then the effect is
255170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // to flip the inside/outside state of every point in the bounds. We may be
256170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // able to take advantage of this in the forward pass. If the xor-ed shape
257170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // doesn't intersect the bounds then it can be skipped.
258170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (element->isInverseFilled()) {
259170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
260170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
261170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
262170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        isFlip = true;
263170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
264170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                } else {
265170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
266170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        isFlip = true;
267170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
268170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
269170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
270170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
271170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (!skippable) {
272170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    emsmallens = embiggens = true;
273170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
274170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                break;
275170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            case SkRegion::kReverseDifference_Op:
276170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // When the bounds is entirely within the rev-diff shape then this behaves like xor
277170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // and reverses every point inside the bounds. If the shape is completely outside
278170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // the bounds then we know after this element is applied that the bounds will be
279170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // all outside the current clip.B
280170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (element->isInverseFilled()) {
281170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
282170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
283170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
284170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
285170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        isFlip = true;
286170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
287170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                } else {
288170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
289170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        isFlip = true;
290170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
291170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
292170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
293170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
294170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
295170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (!skippable) {
296170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    emsmallens = embiggens = true;
297170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
298170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                break;
299170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            case SkRegion::kReplace_Op:
300170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // Replace will always terminate our walk. We will either begin the forward walk
301170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // at the replace op or detect here than the shape is either completely inside
302170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // or completely outside the bounds. In this latter case it can be skipped by
303170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                // setting the correct value for initialState.
304170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (element->isInverseFilled()) {
305170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
306170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
307170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
308170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
309170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllIn_InitialState;
310170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
311170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
312170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                } else {
313170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (element->contains(queryBounds)) {
314170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllIn_InitialState;
315170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
316170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else if (!SkRect::Intersects(element->getBounds(), queryBounds)) {
317170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
318170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
319170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
320170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
321170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                if (!skippable) {
322170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    *initialState = kAllOut_InitialState;
323170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    embiggens = emsmallens = true;
324170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                }
325170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                break;
326170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            default:
327170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                SkDEBUGFAIL("Unexpected op.");
328170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                break;
329170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        }
330170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        if (!skippable) {
331d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org            if (0 == result->count()) {
332d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                // This will be the last element. Record the stricter genID.
333d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                *resultGenID = element->getGenID();
334d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org            }
335d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org
336170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            // if it is a flip, change it to a bounds-filling rect
337170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            if (isFlip) {
338170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                SkASSERT(SkRegion::kXOR_Op == element->getOp() ||
339170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                         SkRegion::kReverseDifference_Op == element->getOp());
340170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                SkNEW_INSERT_AT_LLIST_HEAD(result,
341170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                                           Element,
342170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                                           (queryBounds, SkRegion::kReverseDifference_Op, false));
343170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            } else {
344c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                Element* newElement = result->addToHead(*element);
345c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                if (newElement->isAA()) {
34634cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                    ++numAAElements;
34734cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                }
348c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                // Intersecting an inverse shape is the same as differencing the non-inverse shape.
34945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                // Replacing with an inverse shape is the same as setting initialState=kAllIn and
350c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                // differencing the non-inverse shape.
351c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
352c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                if (newElement->isInverseFilled() &&
353c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                    (SkRegion::kIntersect_Op == newElement->getOp() || isReplace)) {
354c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                    newElement->invertShapeFillType();
355c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                    newElement->setOp(SkRegion::kDifference_Op);
356c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                    if (isReplace) {
357c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                        SkASSERT(kAllOut_InitialState == *initialState);
358c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                        *initialState = kAllIn_InitialState;
359c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                    }
360c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                }
361170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            }
362170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        }
363170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    }
364170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com
365170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    if ((kAllOut_InitialState == *initialState && !embiggens) ||
366170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        (kAllIn_InitialState == *initialState && !emsmallens)) {
367170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        result->reset();
368170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    } else {
369170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        Element* element = result->headIter().get();
370170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        while (NULL != element) {
371170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            bool skippable = false;
372170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            switch (element->getOp()) {
373170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                case SkRegion::kDifference_Op:
374170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    // subtracting from the empty set yields the empty set.
375170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    skippable = kAllOut_InitialState == *initialState;
376170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    break;
377170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                case SkRegion::kIntersect_Op:
378170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    // intersecting with the empty set yields the empty set
379db62709fc19522b39a645557e45417aa82708107commit-bot@chromium.org                    if (kAllOut_InitialState == *initialState) {
380db62709fc19522b39a645557e45417aa82708107commit-bot@chromium.org                        skippable = true;
381db62709fc19522b39a645557e45417aa82708107commit-bot@chromium.org                    } else {
382db62709fc19522b39a645557e45417aa82708107commit-bot@chromium.org                        // We can clear to zero and then simply draw the clip element.
383db62709fc19522b39a645557e45417aa82708107commit-bot@chromium.org                        *initialState = kAllOut_InitialState;
384db62709fc19522b39a645557e45417aa82708107commit-bot@chromium.org                        element->setOp(SkRegion::kReplace_Op);
385db62709fc19522b39a645557e45417aa82708107commit-bot@chromium.org                    }
386170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    break;
387170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                case SkRegion::kUnion_Op:
388170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (kAllIn_InitialState == *initialState) {
389170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        // unioning the infinite plane with anything is a no-op.
390170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
391170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else {
392170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        // unioning the empty set with a shape is the shape.
393170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        element->setOp(SkRegion::kReplace_Op);
394170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
395170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    break;
396170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                case SkRegion::kXOR_Op:
397170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (kAllOut_InitialState == *initialState) {
398170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        // xor could be changed to diff in the kAllIn case, not sure it's a win.
399170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        element->setOp(SkRegion::kReplace_Op);
400170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
401170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    break;
402170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                case SkRegion::kReverseDifference_Op:
403170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    if (kAllIn_InitialState == *initialState) {
404170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        // subtracting the whole plane will yield the empty set.
405170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = true;
406170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        *initialState = kAllOut_InitialState;
407170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    } else {
408170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        // this picks up flips inserted in the backwards pass.
409170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        skippable = element->isInverseFilled() ?
410170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                            !SkRect::Intersects(element->getBounds(), queryBounds) :
411170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                            element->contains(queryBounds);
412170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        if (skippable) {
413170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                            *initialState = kAllIn_InitialState;
414170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        } else {
415170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                            element->setOp(SkRegion::kReplace_Op);
416170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                        }
417170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    }
418170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    break;
419170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                case SkRegion::kReplace_Op:
420170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    skippable = false; // we would have skipped it in the backwards walk if we
421170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                                       // could've.
422170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    break;
423170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                default:
424170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    SkDEBUGFAIL("Unexpected op.");
425170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                    break;
426170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            }
427170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            if (!skippable) {
428170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                break;
429170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            } else {
43034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                if (element->isAA()) {
43134cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                    --numAAElements;
43234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com                }
433170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                result->popHead();
434170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com                element = result->headIter().get();
435170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com            }
436170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com        }
437170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com    }
43834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com    if (NULL != requiresAA) {
43934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com        *requiresAA = numAAElements > 0;
44034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com    }
441d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org
442d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    if (0 == result->count()) {
443d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org        if (*initialState == kAllIn_InitialState) {
444d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org            *resultGenID = SkClipStack::kWideOpenGenID;
445d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org        } else {
446d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org            *resultGenID = SkClipStack::kEmptyGenID;
447d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org        }
448d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    }
449170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com}
450170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com} // namespace GrReducedClip
451