From 8182fa0cac76e7e6d583aebba060229230516887 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Tue, 4 Dec 2012 14:06:06 +0000 Subject: [PATCH] Make SkClipStack::Iter use SkClipStack::Element. R=robertphillips@google.com Review URL: https://codereview.appspot.com/6871051 git-svn-id: http://skia.googlecode.com/svn/trunk@6661 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkClipStack.h | 128 ++++++++++------- src/core/SkCanvas.cpp | 50 ++++--- src/core/SkClipStack.cpp | 104 +------------- src/core/SkTLList.h | 10 +- src/gpu/GrClipMaskManager.cpp | 320 ++++++++++++++++++++---------------------- src/gpu/GrClipMaskManager.h | 8 +- src/pdf/SkPDFDevice.cpp | 47 ++++--- tests/ClipStackTest.cpp | 111 ++++++++------- 8 files changed, 369 insertions(+), 409 deletions(-) diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h index d4f6a52..6af60a2 100644 --- a/include/core/SkClipStack.h +++ b/include/core/SkClipStack.h @@ -58,6 +58,30 @@ public: 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; } @@ -74,6 +98,8 @@ public: 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 @@ -81,6 +107,50 @@ public: 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; @@ -159,8 +229,6 @@ public: // 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 @@ -276,53 +344,18 @@ public: 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. @@ -331,13 +364,7 @@ public: 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); }; /** @@ -356,7 +383,6 @@ public: : INHERITED(stack, kBottom_IterStart) { } - using Iter::Clip; using Iter::next; /** diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index c38ed76..34310c8 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1194,15 +1194,23 @@ void SkCanvas::validateClip() const { SkRasterClip tmpClip(ir); SkClipStack::B2TIter iter(fClipStack); - const SkClipStack::B2TIter::Clip* clip; - while ((clip = iter.next()) != NULL) { - if (clip->fPath) { - clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA); - } else if (clip->fRect) { - clip->fRect->round(&ir); - tmpClip.op(ir, clip->fOp); - } else { - tmpClip.setEmpty(); + const SkClipStack::Element* element; + while ((element = iter.next()) != NULL) { + switch (element->getType()) { + case SkClipStack::Element::kPath_Type: + clipPathHelper(this, + &tmpClip, + element->getPath(), + element->getOp(), + element->isAA()); + break; + case SkClipStack::Element::kRect_Type: + element->getRect().round(&ir); + tmpClip.op(ir, element->getOp()); + break; + case SkClipStack::Element::kEmpty_Type: + tmpClip.setEmpty(); + break; } } @@ -1216,16 +1224,20 @@ void SkCanvas::validateClip() const { void SkCanvas::replayClips(ClipVisitor* visitor) const { SkClipStack::B2TIter iter(fClipStack); - const SkClipStack::B2TIter::Clip* clip; - - SkRect empty = { 0, 0, 0, 0 }; - while ((clip = iter.next()) != NULL) { - if (clip->fPath) { - visitor->clipPath(*clip->fPath, clip->fOp, clip->fDoAA); - } else if (clip->fRect) { - visitor->clipRect(*clip->fRect, clip->fOp, clip->fDoAA); - } else { - visitor->clipRect(empty, SkRegion::kIntersect_Op, false); + const SkClipStack::Element* element; + + static const SkRect kEmpty = { 0, 0, 0, 0 }; + while ((element = iter.next()) != NULL) { + switch (element->getType()) { + case SkClipStack::Element::kPath_Type: + visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); + break; + case SkClipStack::Element::kRect_Type: + visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); + break; + case SkClipStack::Element::kEmpty_Type: + visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); + break; } } } diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp index 33cd41f..107c20f 100644 --- a/src/core/SkClipStack.cpp +++ b/src/core/SkClipStack.cpp @@ -24,28 +24,6 @@ void SkClipStack::Element::checkEmpty() const { SkASSERT(fPath.isEmpty()); } -bool SkClipStack::Element::operator==(const Element& b) const { - if (fSaveCount != b.fSaveCount || - fOp != b.fOp || - fType != b.fType || - fDoAA != b.fDoAA) { - return false; - } - switch (fType) { - case kEmpty_Type: - return true; - case kRect_Type: - return fRect == b.fRect; - case kPath_Type: - return fPath == b.fPath; - } - return false; // Silence the compiler. -} - -bool SkClipStack::Element::operator!=(const Element& b) const { - return !(*this == b); -} - bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const { if (kEmpty_Type == fType && (SkRegion::kDifference_Op == op || SkRegion::kIntersect_Op == op)) { @@ -622,92 +600,20 @@ bool SkClipStack::isWideOpen() const { SkClipStack::Iter::Iter() : fStack(NULL) { } -bool operator==(const SkClipStack::Iter::Clip& a, - const SkClipStack::Iter::Clip& b) { - return a.fOp == b.fOp && a.fDoAA == b.fDoAA && - ((a.fRect == NULL && b.fRect == NULL) || - (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) && - ((a.fPath == NULL && b.fPath == NULL) || - (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath)); -} - -bool operator!=(const SkClipStack::Iter::Clip& a, - const SkClipStack::Iter::Clip& b) { - return !(a == b); -} - -const SkRect& SkClipStack::Iter::Clip::getBounds() const { - if (NULL != fRect) { - return *fRect; - } else if (NULL != fPath) { - return fPath->getBounds(); - } else { - static const SkRect kEmpty = {0, 0, 0, 0}; - return kEmpty; - } -} - -bool SkClipStack::Iter::Clip::contains(const SkRect& rect) const { - if (NULL != fRect) { - return fRect->contains(rect); - } else if (NULL != fPath) { - return fPath->conservativelyContainsRect(rect); - } else { - return false; - } -} - -bool SkClipStack::Iter::Clip::isInverseFilled() const { - return NULL != fPath && fPath->isInverseFillType(); -} - SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc) : fStack(&stack) { this->reset(stack, startLoc); } -const SkClipStack::Iter::Clip* SkClipStack::Iter::updateClip( - const SkClipStack::Element* element) { - switch (element->fType) { - case SkClipStack::Element::kEmpty_Type: - fClip.fRect = NULL; - fClip.fPath = NULL; - element->checkEmpty(); - break; - case SkClipStack::Element::kRect_Type: - fClip.fRect = &element->fRect; - fClip.fPath = NULL; - break; - case SkClipStack::Element::kPath_Type: - fClip.fRect = NULL; - fClip.fPath = &element->fPath; - break; - } - fClip.fOp = element->fOp; - fClip.fDoAA = element->fDoAA; - fClip.fGenID = element->fGenID; - return &fClip; +const SkClipStack::Element* SkClipStack::Iter::next() { + return (const SkClipStack::Element*)fIter.next(); } -const SkClipStack::Iter::Clip* SkClipStack::Iter::next() { - const SkClipStack::Element* element = (const SkClipStack::Element*)fIter.next(); - if (NULL == element) { - return NULL; - } - - return this->updateClip(element); -} - -const SkClipStack::Iter::Clip* SkClipStack::Iter::prev() { - const SkClipStack::Element* element = (const SkClipStack::Element*)fIter.prev(); - if (NULL == element) { - return NULL; - } - - return this->updateClip(element); +const SkClipStack::Element* SkClipStack::Iter::prev() { + return (const SkClipStack::Element*)fIter.prev(); } -const SkClipStack::Iter::Clip* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) { +const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) { if (NULL == fStack) { return NULL; diff --git a/src/core/SkTLList.h b/src/core/SkTLList.h index 87fd52d..30d440f 100644 --- a/src/core/SkTLList.h +++ b/src/core/SkTLList.h @@ -350,7 +350,13 @@ void *operator new(size_t, SkTLList* list, } #define SkNEW_INSERT_IN_LLIST_BEFORE(list, location, type_name, args) \ - (new (list, SkTLList< type_name >::kBefore_Placement, location) type_name args) + (new ((list), SkTLList< type_name >::kBefore_Placement, (location)) type_name args) #define SkNEW_INSERT_IN_LLIST_AFTER(list, location, type_name, args) \ - (new (list, SkTLList< type_name >::kAfter_Placement, location) type_name args) + (new ((list), SkTLList< type_name >::kAfter_Placement, (location)) type_name args) + +#define SkNEW_INSERT_AT_LLIST_HEAD(list, type_name, args) \ + SkNEW_INSERT_IN_LLIST_BEFORE((list), (list)->headIter(), type_name, args) + +#define SkNEW_INSERT_AT_LLIST_TAIL(list, type_name, args) \ + SkNEW_INSERT_IN_LLIST_AFTER((list), (list)->tailIter(), type_name, args) \ No newline at end of file diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index fdaa067..64ead1a 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -24,6 +24,7 @@ GR_DEFINE_RESOURCE_CACHE_DOMAIN(GrClipMaskManager, GetAlphaMaskDomain) #define GR_AA_CLIP 1 #define GR_SW_CLIP 1 +typedef SkClipStack::Element Element; //////////////////////////////////////////////////////////////////////////////// namespace GrReducedClip { @@ -38,11 +39,11 @@ based on later intersect operations, and perhaps remove intersect-rects. We coul 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* resultClips, + ElementList* result, SkRect* resultBounds, bool* resultsAreBounded, InitialState* initialState) { - resultClips->reset(); + result->reset(); if (stack.isWideOpen()) { *initialState = kAllIn_InitialState; @@ -56,15 +57,10 @@ void GrReduceClipStack(const SkClipStack& stack, 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; } @@ -85,16 +81,16 @@ void GrReduceClipStack(const SkClipStack& stack, 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; } @@ -102,23 +98,23 @@ void GrReduceClipStack(const SkClipStack& stack, 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; } } @@ -132,17 +128,17 @@ void GrReduceClipStack(const SkClipStack& stack, // 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; } @@ -157,18 +153,18 @@ void GrReduceClipStack(const SkClipStack& stack, // 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; } } @@ -183,16 +179,16 @@ void GrReduceClipStack(const SkClipStack& stack, // 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; } } @@ -207,17 +203,17 @@ void GrReduceClipStack(const SkClipStack& stack, // 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; } @@ -233,19 +229,19 @@ void GrReduceClipStack(const SkClipStack& stack, // 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; } @@ -261,32 +257,28 @@ void GrReduceClipStack(const SkClipStack& stack, 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; @@ -301,13 +293,13 @@ void GrReduceClipStack(const SkClipStack& stack, 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: @@ -317,15 +309,15 @@ void GrReduceClipStack(const SkClipStack& stack, *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; @@ -341,13 +333,10 @@ void GrReduceClipStack(const SkClipStack& stack, if (!skippable) { break; } else { - ++clipsToSkip; - if (clipsToSkip == resultClips->count()) { - break; - } + result->popHead(); + element = result->headIter().get(); } } - resultClips->remove(0, clipsToSkip); } } } // namespace GrReducedClip @@ -413,12 +402,12 @@ bool requires_AA(const SkClipStack& clipIn) { 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; } } @@ -441,19 +430,19 @@ bool GrClipMaskManager::useSWOnlyPath(const SkClipStack& clipIn) { 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; } } @@ -598,7 +587,7 @@ bool contains(const SkRect& canvContainer, // 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, @@ -615,12 +604,12 @@ const SkClipStack::Iter::Clip* process_initial_clip_elements( 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; @@ -630,8 +619,8 @@ const SkClipStack::Iter::Clip* process_initial_clip_elements( 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 @@ -674,7 +663,7 @@ const SkClipStack::Iter::Clip* process_initial_clip_elements( 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 { @@ -692,7 +681,7 @@ const SkClipStack::Iter::Clip* process_initial_clip_elements( break; } } - return clip; + return element; } } @@ -786,27 +775,31 @@ void device_to_canvas(SkRect* rect, const SkIPoint& origin) { //////////////////////////////////////////////////////////////////////////////// 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; } @@ -951,11 +944,11 @@ bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn, 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, @@ -966,9 +959,9 @@ bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn, 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; @@ -981,13 +974,13 @@ bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn, } 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; } @@ -1001,7 +994,7 @@ bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn, // 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); @@ -1010,7 +1003,7 @@ bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn, 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 @@ -1019,7 +1012,7 @@ bool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn, // 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; } @@ -1096,25 +1089,25 @@ bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn, 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 @@ -1122,7 +1115,7 @@ bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn, // resolve in/out status? bool canRenderDirectToStencil = false; - SkRegion::Op op = clip->fOp; + SkRegion::Op op = element->getOp(); if (first) { first = false; op = firstOp; @@ -1130,22 +1123,22 @@ bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn, 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); @@ -1180,10 +1173,11 @@ bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn, 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); @@ -1199,10 +1193,11 @@ bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn, 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); } @@ -1464,18 +1459,18 @@ bool GrClipMaskManager::createSoftwareClipMask(const GrClipData& clipDataIn, 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; @@ -1499,20 +1494,20 @@ bool GrClipMaskManager::createSoftwareClipMask(const GrClipData& clipDataIn, 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); } @@ -1521,17 +1516,14 @@ bool GrClipMaskManager::createSoftwareClipMask(const GrClipData& clipDataIn, // 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); } } diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index 4894a3a..c3a1b5e 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -19,6 +19,7 @@ #include "SkDeque.h" #include "SkPath.h" #include "SkRefCnt.h" +#include "SkTLList.h" #include "GrClipMaskCache.h" @@ -125,7 +126,7 @@ private: bool useSWOnlyPath(const SkClipStack& clipIn); bool drawClipShape(GrTexture* target, - const SkClipStack::Iter::Clip* clip, + const SkClipStack::Element* element, const GrIRect& resultBounds); void mergeMask(GrTexture* dstMask, @@ -157,9 +158,10 @@ private: typedef GrNoncopyable INHERITED; }; - namespace GrReducedClip { +typedef SkTLList ElementList; + enum InitialState { kAllIn_InitialState, kAllOut_InitialState, @@ -175,7 +177,7 @@ enum InitialState { * may become a member function of SkClipStack when its interface is determined to be stable. */ void GrReduceClipStack(const SkClipStack& stack, - SkTDArray* resultClips, + ElementList* result, SkRect* resultBounds, bool* resultsAreBounded, InitialState* initialState); diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 929ca10..0de011c 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -226,8 +226,8 @@ static void skip_clip_stack_prefix(const SkClipStack& prefix, SkClipStack::B2TIter prefixIter(prefix); iter->reset(stack, SkClipStack::Iter::kBottom_IterStart); - const SkClipStack::B2TIter::Clip* prefixEntry; - const SkClipStack::B2TIter::Clip* iterEntry; + const SkClipStack::Element* prefixEntry; + const SkClipStack::Element* iterEntry; for (prefixEntry = prefixIter.next(); prefixEntry; prefixEntry = prefixIter.next()) { @@ -236,12 +236,9 @@ static void skip_clip_stack_prefix(const SkClipStack& prefix, // Because of SkClipStack does internal intersection, the last clip // entry may differ. if (*prefixEntry != *iterEntry) { - SkASSERT(prefixEntry->fOp == SkRegion::kIntersect_Op); - SkASSERT(iterEntry->fOp == SkRegion::kIntersect_Op); - SkASSERT((iterEntry->fRect == NULL) == - (prefixEntry->fRect == NULL)); - SkASSERT((iterEntry->fPath == NULL) == - (prefixEntry->fPath == NULL)); + SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op); + SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op); + SkASSERT(iterEntry->getType() == prefixEntry->getType()); // back up the iterator by one iter->prev(); prefixEntry = prefixIter.next(); @@ -306,10 +303,9 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack, // If the clip stack does anything other than intersect or if it uses // an inverse fill type, we have to fall back to the clip region. bool needRegion = false; - const SkClipStack::B2TIter::Clip* clipEntry; + const SkClipStack::Element* clipEntry; for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { - if (clipEntry->fOp != SkRegion::kIntersect_Op || - (clipEntry->fPath && clipEntry->fPath->isInverseFillType())) { + if (clipEntry->getOp() != SkRegion::kIntersect_Op || clipEntry->isInverseFilled()) { needRegion = true; break; } @@ -323,19 +319,24 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack, skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); SkMatrix transform; transform.setTranslate(translation.fX, translation.fY); - const SkClipStack::B2TIter::Clip* clipEntry; + const SkClipStack::Element* clipEntry; for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { - SkASSERT(clipEntry->fOp == SkRegion::kIntersect_Op); - if (clipEntry->fRect) { - SkRect translatedClip; - transform.mapRect(&translatedClip, *clipEntry->fRect); - emit_clip(NULL, &translatedClip, fContentStream); - } else if (clipEntry->fPath) { - SkPath translatedPath; - clipEntry->fPath->transform(transform, &translatedPath); - emit_clip(&translatedPath, NULL, fContentStream); - } else { - SkASSERT(false); + SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op); + switch (clipEntry->getType()) { + case SkClipStack::Element::kRect_Type: { + SkRect translatedClip; + transform.mapRect(&translatedClip, clipEntry->getRect()); + emit_clip(NULL, &translatedClip, fContentStream); + break; + } + case SkClipStack::Element::kPath_Type: { + SkPath translatedPath; + clipEntry->getPath().transform(transform, &translatedPath); + emit_clip(&translatedPath, NULL, fContentStream); + break; + } + default: + SkASSERT(false); } } } diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp index adce741..bbd833b 100644 --- a/tests/ClipStackTest.cpp +++ b/tests/ClipStackTest.cpp @@ -152,13 +152,14 @@ static void test_iterators(skiatest::Reporter* reporter) { // 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); @@ -166,13 +167,14 @@ static void test_iterators(skiatest::Reporter* reporter) { // 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); @@ -180,12 +182,13 @@ static void test_iterators(skiatest::Reporter* reporter) { // 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]); } } @@ -362,10 +365,10 @@ static int count(const SkClipStack& stack) { 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) { ; } @@ -520,36 +523,47 @@ static void add_oval(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta 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", @@ -558,12 +572,13 @@ static void print_clip(const SkClipStack::Iter::Clip& clip) { "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"); @@ -644,8 +659,9 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) { } } + typedef GrReducedClip::ElementList ElementList; // Get the reduced version of the stack. - SkTDArray reducedClips; + ElementList reducedClips; SkRect resultBounds; bool bounded; GrReducedClip::InitialState initial; @@ -657,8 +673,8 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) { // 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 @@ -675,16 +691,16 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) { 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); @@ -712,15 +728,14 @@ static void TestClipStack(skiatest::Reporter* reporter) { // 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()); -- 2.7.4