this->initPath(0, path, op, doAA);
}
+ bool operator== (const Element& element) const {
+ if (this == &element) {
+ return true;
+ }
+ if (fOp != element.fOp ||
+ fType != element.fType ||
+ fDoAA != element.fDoAA ||
+ fSaveCount != element.fSaveCount) {
+ return false;
+ }
+ switch (fType) {
+ case kPath_Type:
+ return fPath == element.fPath;
+ case kRect_Type:
+ return fRect == element.fRect;
+ case kEmpty_Type:
+ return true;
+ default:
+ SkDEBUGFAIL("Unexpected type.");
+ return false;
+ }
+ }
+ bool operator!= (const Element& element) const { return !(*this == element); }
+
//!< Call to get the type of the clip element.
Type getType() const { return fType; }
when it is rasterized. */
bool isAA() const { return fDoAA; }
+ void setOp(SkRegion::Op op) { fOp = op; }
+
/** The GenID can be used by clip stack clients to cache representations of the clip. The
ID corresponds to the set of clip elements up to and including this element within the
stack not to the element itself. That is the same clip path in different stacks will
their stacks. */
int32_t getGenID() const { return fGenID; }
+ /**
+ * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape
+ * is inverse filled is not considered.)
+ */
+ const SkRect& getBounds() const {
+ static const SkRect kEmpty = { 0, 0, 0, 0 };
+ switch (fType) {
+ case kRect_Type:
+ return fRect;
+ case kPath_Type:
+ return fPath.getBounds();
+ case kEmpty_Type:
+ return kEmpty;
+ default:
+ SkDEBUGFAIL("Unexpected type.");
+ return kEmpty;
+ }
+ }
+
+ /**
+ * Conservatively checks whether the clip shape contains the rect param. (Whether the shape
+ * is inverse filled is not considered.)
+ */
+ bool contains(const SkRect& rect) const {
+ switch (fType) {
+ case kRect_Type:
+ return fRect.contains(rect);
+ case kPath_Type:
+ return fPath.conservativelyContainsRect(rect);
+ case kEmpty_Type:
+ return false;
+ default:
+ SkDEBUGFAIL("Unexpected type.");
+ return false;
+ }
+ }
+
+ /**
+ * Is the clip shape inverse filled.
+ */
+ bool isInverseFilled() const {
+ return kPath_Type == fType && fPath.isInverseFillType();
+ }
+
private:
friend class SkClipStack;
// All Element methods below are only used within SkClipStack.cpp
inline void checkEmpty() const;
- inline bool operator==(const Element& b) const;
- inline bool operator!=(const Element& b) const;
inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const;
/* This method checks to see if two rect clips can be safely merged into one. The issue here
is that to be strictly correct all the edges of the resulting rect must have the same
Iter(const SkClipStack& stack, IterStart startLoc);
- struct Clip {
- Clip() : fRect(NULL), fPath(NULL), fOp(SkRegion::kIntersect_Op),
- fDoAA(false), fGenID(kInvalidGenID) {}
- friend bool operator==(const Clip& a, const Clip& b);
- friend bool operator!=(const Clip& a, const Clip& b);
- /**
- * Gets the bounds of the clip element, either the rect or path bounds. (Whether the
- * shape is inverse filled is not considered)
- */
- const SkRect& getBounds() const;
-
- /**
- * Conservatively checks whether the clip shape (rect/path) contains the rect param.
- * (Whether the shape is inverse filled is not considered)
- */
- bool contains(const SkRect&) const;
-
- /**
- * Is the clip shape inverse filled.
- */
- bool isInverseFilled() const;
-
- const SkRect* fRect; // if non-null, this is a rect clip
- const SkPath* fPath; // if non-null, this is a path clip
- SkRegion::Op fOp;
- bool fDoAA;
- int32_t fGenID;
- };
-
/**
- * Return the clip for this element in the iterator. If next() returns
- * NULL, then the iterator is done. The type of clip is determined by
- * the pointers fRect and fPath:
- *
- * fRect==NULL fPath!=NULL path clip
- * fRect!=NULL fPath==NULL rect clip
- * fRect==NULL fPath==NULL empty clip
+ * Return the clip element for this iterator. If next()/prev() returns NULL, then the
+ * iterator is done.
*/
- const Clip* next();
- const Clip* prev();
+ const Element* next();
+ const Element* prev();
/**
- * Moves the iterator to the topmost clip with the specified RegionOp
- * and returns that clip. If no clip with that op is found,
- * returns NULL.
+ * Moves the iterator to the topmost element with the specified RegionOp and returns that
+ * element. If no clip element with that op is found, the first element is returned.
*/
- const Clip* skipToTopmost(SkRegion::Op op);
+ const Element* skipToTopmost(SkRegion::Op op);
/**
* Restarts the iterator on a clip stack.
private:
const SkClipStack* fStack;
- Clip fClip;
SkDeque::Iter fIter;
- /**
- * updateClip updates fClip to the current state of fIter. It unifies
- * functionality needed by both next() and prev().
- */
- const Clip* updateClip(const SkClipStack::Element* element);
};
/**
: INHERITED(stack, kBottom_IterStart) {
}
- using Iter::Clip;
using Iter::next;
/**
#define GR_AA_CLIP 1
#define GR_SW_CLIP 1
+typedef SkClipStack::Element Element;
////////////////////////////////////////////////////////////////////////////////
namespace GrReducedClip {
take a rect in case the caller knows a bound on what is to be drawn through this clip.
*/
void GrReduceClipStack(const SkClipStack& stack,
- SkTDArray<SkClipStack::Iter::Clip>* resultClips,
+ ElementList* result,
SkRect* resultBounds,
bool* resultsAreBounded,
InitialState* initialState) {
- resultClips->reset();
+ result->reset();
if (stack.isWideOpen()) {
*initialState = kAllIn_InitialState;
if (iior) {
*resultsAreBounded = true;
*initialState = kAllOut_InitialState;
- SkClipStack::Iter::Clip* clip = resultClips->append();
- // append doesn't call the default cons.
- *clip = SkClipStack::Iter::Clip();
-
- // iior should only be true if aa/non-aa status matches.
SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
- clip->fDoAA = iter.prev()->fDoAA;
- clip->fOp = SkRegion::kReplace_Op;
- clip->fRect = resultBounds;
+ // iior should only be true if aa/non-aa status matches among all elements.
+ bool doAA = iter.prev()->isAA();
+ SkNEW_INSERT_AT_LLIST_TAIL(result, Element, (*resultBounds, SkRegion::kReplace_Op, doAA));
return;
}
SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
while ((kUnknown_InitialState == *initialState)) {
- const SkClipStack::Iter::Clip* clip = iter.prev();
- if (NULL == clip) {
+ const Element* element = iter.prev();
+ if (NULL == element) {
*initialState = kAllIn_InitialState;
break;
}
- if (SkClipStack::kEmptyGenID == clip->fGenID) {
+ if (SkClipStack::kEmptyGenID == element->getGenID()) {
*initialState = kAllOut_InitialState;
break;
}
- if (SkClipStack::kWideOpenGenID == clip->fGenID) {
+ if (SkClipStack::kWideOpenGenID == element->getGenID()) {
*initialState = kAllIn_InitialState;
break;
}
bool skippable = false;
bool isFlip = false; // does this op just flip the in/out state of every point in the bounds
- switch (clip->fOp) {
+ switch (element->getOp()) {
case SkRegion::kDifference_Op:
if (*resultsAreBounded) {
// check if the shape subtracted either contains the entire bounds (and makes
// the clip empty) or is outside the bounds and therefore can be skipped.
- if (clip->isInverseFilled()) {
- if (clip->contains(*resultBounds)) {
+ if (element->isInverseFilled()) {
+ if (element->contains(*resultBounds)) {
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
*initialState = kAllOut_InitialState;
skippable = true;
}
} else {
- if (clip->contains(*resultBounds)) {
+ if (element->contains(*resultBounds)) {
*initialState = kAllOut_InitialState;
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
skippable = true;
}
}
// check if the shape intersected contains the entire bounds and therefore can
// be skipped or it is outside the entire bounds and therefore makes the clip
// empty.
- if (clip->isInverseFilled()) {
- if (clip->contains(*resultBounds)) {
+ if (element->isInverseFilled()) {
+ if (element->contains(*resultBounds)) {
*initialState = kAllOut_InitialState;
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
skippable = true;
}
} else {
- if (clip->contains(*resultBounds)) {
+ if (element->contains(*resultBounds)) {
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
*initialState = kAllOut_InitialState;
skippable = true;
}
// If the union-ed shape contains the entire bounds then after this element
// the bounds is entirely inside the clip. If the union-ed shape is outside the
// bounds then this op can be skipped.
- if (clip->isInverseFilled()) {
- if (clip->contains(*resultBounds)) {
+ if (element->isInverseFilled()) {
+ if (element->contains(*resultBounds)) {
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
*initialState = kAllIn_InitialState;
skippable = true;
}
} else {
- if (clip->contains(*resultBounds)) {
+ if (element->contains(*resultBounds)) {
*initialState = kAllIn_InitialState;
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
skippable = true;
}
}
// to flip the inside/outside state of every point in the bounds. We may be
// able to take advantage of this in the forward pass. If the xor-ed shape
// doesn't intersect the bounds then it can be skipped.
- if (clip->isInverseFilled()) {
- if (clip->contains(*resultBounds)) {
+ if (element->isInverseFilled()) {
+ if (element->contains(*resultBounds)) {
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
isFlip = true;
}
} else {
- if (clip->contains(*resultBounds)) {
+ if (element->contains(*resultBounds)) {
isFlip = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
skippable = true;
}
}
// the bounds then we know after this element is applied that the bounds will be
// all outside the current clip.B
if (*resultsAreBounded) {
- if (clip->isInverseFilled()) {
- if (clip->contains(*resultBounds)) {
+ if (element->isInverseFilled()) {
+ if (element->contains(*resultBounds)) {
*initialState = kAllOut_InitialState;
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
isFlip = true;
}
} else {
- if (clip->contains(*resultBounds)) {
+ if (element->contains(*resultBounds)) {
isFlip = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
*initialState = kAllOut_InitialState;
skippable = true;
}
// or completely outside the bounds. In this latter case it can be skipped by
// setting the correct value for initialState.
if (*resultsAreBounded) {
- if (clip->isInverseFilled()) {
- if (clip->contains(*resultBounds)) {
+ if (element->isInverseFilled()) {
+ if (element->contains(*resultBounds)) {
*initialState = kAllOut_InitialState;
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
*initialState = kAllIn_InitialState;
skippable = true;
}
} else {
- if (clip->contains(*resultBounds)) {
+ if (element->contains(*resultBounds)) {
*initialState = kAllIn_InitialState;
skippable = true;
- } else if (!SkRect::Intersects(clip->getBounds(), *resultBounds)) {
+ } else if (!SkRect::Intersects(element->getBounds(), *resultBounds)) {
*initialState = kAllOut_InitialState;
skippable = true;
}
break;
}
if (!skippable) {
- SkClipStack::Iter::Clip* newClip = resultClips->prepend();
// if it is a flip, change it to a bounds-filling rect
if (isFlip) {
- SkASSERT(SkRegion::kXOR_Op == clip->fOp ||
- SkRegion::kReverseDifference_Op == clip->fOp);
- newClip->fPath = NULL;
- newClip->fRect = resultBounds;
- // assuming this is faster to perform on GPU with stenciling than xor.
- newClip->fOp = SkRegion::kReverseDifference_Op;
- newClip->fDoAA = false;
- newClip->fGenID = SkClipStack::kInvalidGenID;
+ SkASSERT(SkRegion::kXOR_Op == element->getOp() ||
+ SkRegion::kReverseDifference_Op == element->getOp());
+ SkNEW_INSERT_AT_LLIST_HEAD(result,
+ Element,
+ (*resultBounds, SkRegion::kReverseDifference_Op, false));
} else {
- *newClip = *clip;
+ result->addToHead(*element);
}
}
}
if ((kAllOut_InitialState == *initialState && !embiggens) ||
(kAllIn_InitialState == *initialState && !emsmallens)) {
- resultClips->reset();
+ result->reset();
} else {
int clipsToSkip = 0;
- while (1) {
- SkClipStack::Iter::Clip* clip = &(*resultClips)[clipsToSkip];
+ Element* element = result->headIter().get();
+ while (NULL != element) {
bool skippable = false;
- switch (clip->fOp) {
+ switch (element->getOp()) {
case SkRegion::kDifference_Op:
// subtracting from the empty set yields the empty set.
skippable = kAllOut_InitialState == *initialState;
skippable = true;
} else {
// unioning the empty set with a shape is the shape.
- clip->fOp = SkRegion::kReplace_Op;
+ element->setOp(SkRegion::kReplace_Op);
}
break;
case SkRegion::kXOR_Op:
if (kAllOut_InitialState == *initialState) {
// xor could be changed to diff in the kAllIn case, not sure it's a win.
- clip->fOp = SkRegion::kReplace_Op;
+ element->setOp(SkRegion::kReplace_Op);
}
break;
case SkRegion::kReverseDifference_Op:
*initialState = kAllOut_InitialState;
} else {
// this picks up flips inserted in the backwards pass.
- if (*resultsAreBounded && NULL != clip->fRect) {
- skippable = clip->isInverseFilled() ?
- !SkRect::Intersects(clip->getBounds(), *resultBounds) :
- clip->contains(*resultBounds);
+ if (*resultsAreBounded) {
+ skippable = element->isInverseFilled() ?
+ !SkRect::Intersects(element->getBounds(), *resultBounds) :
+ element->contains(*resultBounds);
}
if (skippable) {
*initialState = kAllIn_InitialState;
} else {
- clip->fOp = SkRegion::kReplace_Op;
+ element->setOp(SkRegion::kReplace_Op);
}
}
break;
if (!skippable) {
break;
} else {
- ++clipsToSkip;
- if (clipsToSkip == resultClips->count()) {
- break;
- }
+ result->popHead();
+ element = result->headIter().get();
}
}
- resultClips->remove(0, clipsToSkip);
}
}
} // namespace GrReducedClip
SkClipStack::Iter iter;
iter.reset(clipIn, SkClipStack::Iter::kBottom_IterStart);
- const SkClipStack::Iter::Clip* clip = NULL;
- for (clip = iter.skipToTopmost(SkRegion::kReplace_Op);
- NULL != clip;
- clip = iter.next()) {
+ const Element* element = NULL;
+ for (element = iter.skipToTopmost(SkRegion::kReplace_Op);
+ NULL != element;
+ element = iter.next()) {
- if (clip->fDoAA) {
+ if (element->isAA()) {
return true;
}
}
bool useSW = false;
SkClipStack::Iter iter(clipIn, SkClipStack::Iter::kBottom_IterStart);
- const SkClipStack::Iter::Clip* clip = NULL;
+ const Element* element = NULL;
- for (clip = iter.skipToTopmost(SkRegion::kReplace_Op);
- NULL != clip;
- clip = iter.next()) {
+ for (element = iter.skipToTopmost(SkRegion::kReplace_Op);
+ NULL != element;
+ element = iter.next()) {
// rects can always be drawn directly w/o using the software path
// so only paths need to be checked
- if (NULL != clip->fPath &&
+ if (Element::kPath_Type == element->getType() &&
path_needs_SW_renderer(this->getContext(), fGpu,
- *clip->fPath,
- get_path_fill(*clip->fPath),
- clip->fDoAA)) {
+ element->getPath(),
+ get_path_fill(element->getPath()),
+ element->isAA())) {
useSW = true;
}
}
// determines how many elements at the head of the clip can be skipped and
// whether the initial clear should be to the inside- or outside-the-clip value,
// and what op should be used to draw the first element that isn't skipped.
-const SkClipStack::Iter::Clip* process_initial_clip_elements(
+const SkClipStack::Element* process_initial_clip_elements(
SkClipStack::Iter* iter,
const GrIRect& devBounds,
bool* clearToInside,
bool done = false;
*clearToInside = true;
- const SkClipStack::Iter::Clip* clip = NULL;
+ const SkClipStack::Element* element = NULL;
- for (clip = iter->skipToTopmost(SkRegion::kReplace_Op);
- NULL != clip && !done;
- clip = iter->next()) {
- switch (clip->fOp) {
+ for (element = iter->skipToTopmost(SkRegion::kReplace_Op);
+ NULL != element && !done;
+ element = iter->next()) {
+ switch (element->getOp()) {
case SkRegion::kReplace_Op:
// replace ignores everything previous
*firstOp = SkRegion::kReplace_Op;
case SkRegion::kIntersect_Op:
// if this element contains the entire bounds then we
// can skip it.
- if (NULL != clip->fRect &&
- contains(*clip->fRect, devBounds, clipData.fOrigin)) {
+ if (Element::kRect_Type == element->getType() &&
+ contains(element->getRect(), devBounds, clipData.fOrigin)) {
break;
}
// if everything is initially clearToInside then intersect is
break;
case SkRegion::kReverseDifference_Op:
// if all pixels are clearToInside then reverse difference
- // produces empty set. Otherise it is same as replace
+ // produces empty set. Otherwise it is same as replace
if (*clearToInside) {
*clearToInside = false;
} else {
break;
}
}
- return clip;
+ return element;
}
}
////////////////////////////////////////////////////////////////////////////////
bool GrClipMaskManager::drawClipShape(GrTexture* target,
- const SkClipStack::Iter::Clip* clip,
+ const SkClipStack::Element* element,
const GrIRect& resultBounds) {
GrDrawState* drawState = fGpu->drawState();
GrAssert(NULL != drawState);
drawState->setRenderTarget(target->asRenderTarget());
- if (NULL != clip->fRect) {
- if (clip->fDoAA) {
- getContext()->getAARectRenderer()->fillAARect(fGpu, fGpu,
- *clip->fRect,
- true);
- } else {
- fGpu->drawSimpleRect(*clip->fRect, NULL);
- }
- } else if (NULL != clip->fPath) {
- return draw_path(this->getContext(), fGpu,
- *clip->fPath,
- get_path_fill(*clip->fPath),
- clip->fDoAA,
- resultBounds);
+ switch (element->getType()) {
+ case Element::kRect_Type:
+ if (element->isAA()) {
+ getContext()->getAARectRenderer()->fillAARect(fGpu, fGpu, element->getRect(), true);
+ } else {
+ fGpu->drawSimpleRect(element->getRect(), NULL);
+ }
+ return true;
+ case Element::kPath_Type:
+ return draw_path(this->getContext(), fGpu,
+ element->getPath(),
+ get_path_fill(element->getPath()),
+ element->isAA(),
+ resultBounds);
+ default:
+ // something is wrong if we're trying to draw an empty element.
+ GrCrash("Unexpected element type");
+ return false;
}
return true;
}
SkClipStack::Iter iter(*clipDataIn.fClipStack,
SkClipStack::Iter::kBottom_IterStart);
- const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
- *devResultBounds,
- &clearToInside,
- &firstOp,
- clipDataIn);
+ const Element* element = process_initial_clip_elements(&iter,
+ *devResultBounds,
+ &clearToInside,
+ &firstOp,
+ clipDataIn);
// The scratch texture that we are drawing into can be substantially larger than the mask. Only
// clear the part that we care about.
fGpu->clear(&maskResultBounds,
GrAutoScratchTexture temp;
bool first = true;
// walk through each clip element and perform its set op
- for ( ; NULL != clip; clip = iter.next()) {
+ for ( ; NULL != element; element = iter.next()) {
- SkRegion::Op op = clip->fOp;
+ SkRegion::Op op = element->getOp();
if (first) {
first = false;
op = firstOp;
}
setup_boolean_blendcoeffs(drawState, op);
- this->drawClipShape(accum, clip, *devResultBounds);
+ this->drawClipShape(accum, element, *devResultBounds);
} else if (SkRegion::kReverseDifference_Op == op ||
SkRegion::kIntersect_Op == op) {
// there is no point in intersecting a screen filling rectangle.
- if (SkRegion::kIntersect_Op == op && NULL != clip->fRect &&
- contains(*clip->fRect, *devResultBounds, clipDataIn.fOrigin)) {
+ if (SkRegion::kIntersect_Op == op && Element::kRect_Type == element->getType() &&
+ contains(element->getRect(), *devResultBounds, clipDataIn.fOrigin)) {
continue;
}
// mask buffer can be substantially larger than the actually clip stack element. We
// touch the minimum number of pixels necessary and use decal mode to combine it with
// the accumulator
- GrRect elementMaskBounds = clip->getBounds();
+ GrRect elementMaskBounds = element->getBounds();
elementMaskBounds.offset(clipToMaskOffset);
GrIRect elementMaskIBounds;
elementMaskBounds.roundOut(&elementMaskIBounds);
fGpu->clear(&elementMaskIBounds, 0x00000000, temp.texture()->asRenderTarget());
setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
- this->drawClipShape(temp.texture(), clip, elementMaskIBounds);
+ this->drawClipShape(temp.texture(), element, elementMaskIBounds);
// Now draw into the accumulator using the real operation
// and the temp buffer as a texture
// all the remaining ops can just be directly draw into
// the accumulation buffer
setup_boolean_blendcoeffs(drawState, op);
- this->drawClipShape(accum, clip, *devResultBounds);
+ this->drawClipShape(accum, element, *devResultBounds);
}
accumClearedToZero = false;
}
SkClipStack::Iter iter(*oldClipData->fClipStack,
SkClipStack::Iter::kBottom_IterStart);
- const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
- devRTRect,
- &clearToInside,
- &firstOp,
- clipDataIn);
+ const Element* element = process_initial_clip_elements(&iter,
+ devRTRect,
+ &clearToInside,
+ &firstOp,
+ clipDataIn);
fGpu->clearStencilClip(devClipBounds, clearToInside);
bool first = true;
// walk through each clip element and perform its set op
// with the existing clip.
- for ( ; NULL != clip; clip = iter.next()) {
+ for ( ; NULL != element; element = iter.next()) {
GrPathFill fill;
bool fillInverted = false;
// enabled at bottom of loop
drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
// if the target is MSAA then we want MSAA enabled when the clip is soft
if (rt->isMultisampled()) {
- drawState->setState(GrDrawState::kHWAntialias_StateBit, clip->fDoAA);
+ drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA());
}
// Can the clip element be drawn directly to the stencil buffer
// resolve in/out status?
bool canRenderDirectToStencil = false;
- SkRegion::Op op = clip->fOp;
+ SkRegion::Op op = element->getOp();
if (first) {
first = false;
op = firstOp;
GrPathRenderer* pr = NULL;
const SkPath* clipPath = NULL;
- if (NULL != clip->fRect) {
+ if (Element::kRect_Type == element->getType()) {
canRenderDirectToStencil = true;
fill = kEvenOdd_GrPathFill;
fillInverted = false;
// there is no point in intersecting a screen filling
// rectangle.
if (SkRegion::kIntersect_Op == op &&
- contains(*clip->fRect, devRTRect, oldClipData->fOrigin)) {
+ contains(element->getRect(), devRTRect, oldClipData->fOrigin)) {
continue;
}
} else {
- GrAssert(NULL != clip->fPath);
- fill = get_path_fill(*clip->fPath);
+ GrAssert(Element::kPath_Type == element->getType());
+ clipPath = &element->getPath();
+ fill = get_path_fill(*clipPath);
fillInverted = GrIsFillInverted(fill);
fill = GrNonInvertedFill(fill);
- clipPath = clip->fPath;
pr = this->getContext()->getPathRenderer(*clipPath, fill, fGpu, false, true);
if (NULL == pr) {
fGpu->setClip(oldClipData);
0x0000,
0xffff);
SET_RANDOM_COLOR
- if (NULL != clip->fRect) {
+ if (Element::kRect_Type == element->getType()) {
*drawState->stencil() = gDrawToStencil;
- fGpu->drawSimpleRect(*clip->fRect, NULL);
+ fGpu->drawSimpleRect(element->getRect(), NULL);
} else {
+ GrAssert(Element::kPath_Type == element->getType());
if (canRenderDirectToStencil) {
*drawState->stencil() = gDrawToStencil;
pr->drawPath(*clipPath, fill, fGpu, false);
for (int p = 0; p < passes; ++p) {
*drawState->stencil() = stencilSettings[p];
if (canDrawDirectToClip) {
- if (NULL != clip->fRect) {
+ if (Element::kRect_Type == element->getType()) {
SET_RANDOM_COLOR
- fGpu->drawSimpleRect(*clip->fRect, NULL);
+ fGpu->drawSimpleRect(element->getRect(), NULL);
} else {
+ GrAssert(Element::kPath_Type == element->getType());
SET_RANDOM_COLOR
pr->drawPath(*clipPath, fill, fGpu, false);
}
SkClipStack::Iter iter(*clipDataIn.fClipStack,
SkClipStack::Iter::kBottom_IterStart);
- const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
- *devResultBounds,
- &clearToInside,
- &firstOp,
- clipDataIn);
+ const Element* element = process_initial_clip_elements(&iter,
+ *devResultBounds,
+ &clearToInside,
+ &firstOp,
+ clipDataIn);
helper.clear(clearToInside ? 0xFF : 0x00);
bool first = true;
- for ( ; NULL != clip; clip = iter.next()) {
+ for ( ; NULL != element; element = iter.next()) {
- SkRegion::Op op = clip->fOp;
+ SkRegion::Op op = element->getOp();
if (first) {
first = false;
op = firstOp;
helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF);
}
- if (NULL != clip->fRect) {
-
+ if (Element::kRect_Type == element->getType()) {
// convert the rect to a path so we can invert the fill
SkPath temp;
- temp.addRect(*clip->fRect);
+ temp.addRect(element->getRect());
helper.draw(temp, SkRegion::kReplace_Op,
- kInverseEvenOdd_GrPathFill, clip->fDoAA,
+ kInverseEvenOdd_GrPathFill, element->isAA(),
0x00);
- } else if (NULL != clip->fPath) {
- helper.draw(*clip->fPath,
+ } else {
+ GrAssert(Element::kPath_Type == element->getType());
+ helper.draw(element->getPath(),
SkRegion::kReplace_Op,
- invert_fill(get_path_fill(*clip->fPath)),
- clip->fDoAA,
+ invert_fill(get_path_fill(element->getPath())),
+ element->isAA(),
0x00);
}
// The other ops (union, xor, diff) only affect pixels inside
// the geometry so they can just be drawn normally
- if (NULL != clip->fRect) {
-
- helper.draw(*clip->fRect,
- op,
- clip->fDoAA, 0xFF);
-
- } else if (NULL != clip->fPath) {
- helper.draw(*clip->fPath,
+ if (Element::kRect_Type == element->getType()) {
+ helper.draw(element->getRect(), op, element->isAA(), 0xFF);
+ } else {
+ GrAssert(Element::kPath_Type == element->getType());
+ helper.draw(element->getPath(),
op,
- get_path_fill(*clip->fPath),
- clip->fDoAA, 0xFF);
+ get_path_fill(element->getPath()),
+ element->isAA(), 0xFF);
}
}
// bottom to top iteration
{
- const SkClipStack::B2TIter::Clip* clip = NULL;
+ const SkClipStack::Element* element = NULL;
SkClipStack::B2TIter iter(stack);
int i;
- for (i = 0, clip = iter.next(); clip; ++i, clip = iter.next()) {
- REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]);
+ for (i = 0, element = iter.next(); element; ++i, element = iter.next()) {
+ REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+ REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
}
SkASSERT(i == 4);
// top to bottom iteration
{
- const SkClipStack::Iter::Clip* clip = NULL;
+ const SkClipStack::Element* element = NULL;
SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
int i;
- for (i = 3, clip = iter.prev(); clip; --i, clip = iter.prev()) {
- REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]);
+ for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) {
+ REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+ REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
}
SkASSERT(i == -1);
// skipToTopmost
{
- const SkClipStack::Iter::Clip*clip = NULL;
+ const SkClipStack::Element* element = NULL;
SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
- clip = iter.skipToTopmost(SkRegion::kUnion_Op);
- REPORTER_ASSERT(reporter, *clip->fRect == gRects[3]);
+ element = iter.skipToTopmost(SkRegion::kUnion_Op);
+ REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+ REPORTER_ASSERT(reporter, element->getRect() == gRects[3]);
}
}
SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
- const SkClipStack::Iter::Clip* clip = NULL;
+ const SkClipStack::Element* element = NULL;
int count = 0;
- for (clip = iter.prev(); clip; clip = iter.prev(), ++count) {
+ for (element = iter.prev(); element; element = iter.prev(), ++count) {
;
}
stack->clipDevPath(path, op, false);
};
-static void add_elem_to_stack(const SkClipStack::Iter::Clip& clip, SkClipStack* stack) {
- if (NULL != clip.fPath) {
- stack->clipDevPath(*clip.fPath, clip.fOp, clip.fDoAA);
- } else if (NULL != clip.fRect) {
- stack->clipDevRect(*clip.fRect, clip.fOp, clip.fDoAA);
+static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack* stack) {
+ switch (element.getType()) {
+ case SkClipStack::Element::kRect_Type:
+ stack->clipDevRect(element.getRect(), element.getOp(), element.isAA());
+ break;
+ case SkClipStack::Element::kPath_Type:
+ stack->clipDevPath(element.getPath(), element.getOp(), element.isAA());
+ break;
+ case SkClipStack::Element::kEmpty_Type:
+ SkDEBUGFAIL("Why did the reducer produce an explicit empty.");
+ stack->clipEmpty();
+ break;
}
}
-static void add_elem_to_region(const SkClipStack::Iter::Clip& clip,
+static void add_elem_to_region(const SkClipStack::Element& element,
const SkIRect& bounds,
SkRegion* region) {
SkRegion elemRegion;
SkRegion boundsRgn(bounds);
- if (NULL != clip.fPath) {
- elemRegion.setPath(*clip.fPath, boundsRgn);
- } else if (NULL != clip.fRect) {
- SkPath path;
- path.addRect(*clip.fRect);
- elemRegion.setPath(path, boundsRgn);
- } else {
- // TODO: Figure out why we sometimes get here in the reduced clip stack.
- region->setEmpty();
- return;
+ switch (element.getType()) {
+ case SkClipStack::Element::kRect_Type: {
+ SkPath path;
+ path.addRect(element.getRect());
+ elemRegion.setPath(path, boundsRgn);
+ break;
+ }
+ case SkClipStack::Element::kPath_Type:
+ elemRegion.setPath(element.getPath(), boundsRgn);
+ break;
+ case SkClipStack::Element::kEmpty_Type:
+ //
+ region->setEmpty();
+ return;
}
- region->op(elemRegion, clip.fOp);
+ region->op(elemRegion, element.getOp());
}
// This can assist with debugging the clip stack reduction code when the test below fails.
-static void print_clip(const SkClipStack::Iter::Clip& clip) {
+static void print_clip(const SkClipStack::Element& element) {
static const char* kOpStrs[] = {
"DF",
"IS",
"RD",
"RP",
};
- if (NULL != clip.fRect || NULL != clip.fPath) {
- const SkRect& bounds = clip.getBounds();
+ if (SkClipStack::Element::kEmpty_Type != element.getType()) {
+ const SkRect& bounds = element.getBounds();
+ bool isRect = SkClipStack::Element::kRect_Type == element.getType();
SkDebugf("%s %s %s [%f %f] x [%f %f]\n",
- kOpStrs[clip.fOp],
- (NULL != clip.fRect ? "R" : "P"),
- ((NULL != clip.fPath && clip.fPath->isInverseFillType() ? "I" : " ")),
+ kOpStrs[element.getOp()],
+ (isRect ? "R" : "P"),
+ (element.isInverseFilled() ? "I" : " "),
bounds.fLeft, bounds.fRight, bounds.fTop, bounds.fBottom);
} else {
SkDebugf("EM\n");
}
}
+ typedef GrReducedClip::ElementList ElementList;
// Get the reduced version of the stack.
- SkTDArray<SkClipStack::Iter::Clip> reducedClips;
+ ElementList reducedClips;
SkRect resultBounds;
bool bounded;
GrReducedClip::InitialState initial;
// whether the result is bounded or not, the whole plane should start outside the clip.
reducedStack.clipEmpty();
}
- for (int c = 0; c < reducedClips.count(); ++c) {
- add_elem_to_stack(reducedClips[c], &reducedStack);
+ for (ElementList::Iter iter = reducedClips.headIter(); NULL != iter.get(); iter.next()) {
+ add_elem_to_stack(*iter.get(), &reducedStack);
}
if (bounded) {
// GrReduceClipStack() assumes that there is an implicit clip to the bounds
SkRegion reducedRegion;
region.setRect(inflatedIBounds);
- const SkClipStack::Iter::Clip* clip;
+ const SkClipStack::Element* element;
SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
- while ((clip = iter.next())) {
- add_elem_to_region(*clip, inflatedIBounds, ®ion);
+ while ((element = iter.next())) {
+ add_elem_to_region(*element, inflatedIBounds, ®ion);
}
reducedRegion.setRect(inflatedIBounds);
iter.reset(reducedStack, SkClipStack::Iter::kBottom_IterStart);
- while ((clip = iter.next())) {
- add_elem_to_region(*clip, inflatedIBounds, &reducedRegion);
+ while ((element = iter.next())) {
+ add_elem_to_region(*element, inflatedIBounds, &reducedRegion);
}
REPORTER_ASSERT(reporter, region == reducedRegion);
// all of the above rects should have been intersected, leaving only 1 rect
SkClipStack::B2TIter iter(stack);
- const SkClipStack::B2TIter::Clip* clip = iter.next();
+ const SkClipStack::Element* element = iter.next();
SkRect answer;
answer.iset(25, 25, 75, 75);
- REPORTER_ASSERT(reporter, clip);
- REPORTER_ASSERT(reporter, clip->fRect);
- REPORTER_ASSERT(reporter, !clip->fPath);
- REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == clip->fOp);
- REPORTER_ASSERT(reporter, *clip->fRect == answer);
+ REPORTER_ASSERT(reporter, NULL != element);
+ REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
+ REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == element->getOp());
+ REPORTER_ASSERT(reporter, element->getRect() == answer);
// now check that we only had one in our iterator
REPORTER_ASSERT(reporter, !iter.next());