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
This commit is contained in:
parent
e659c2e820
commit
8182fa0cac
@ -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)
|
||||
* Return the clip element for this iterator. If next()/prev() returns NULL, then the
|
||||
* iterator is done.
|
||||
*/
|
||||
const SkRect& getBounds() const;
|
||||
const Element* next();
|
||||
const Element* prev();
|
||||
|
||||
/**
|
||||
* Conservatively checks whether the clip shape (rect/path) contains the rect param.
|
||||
* (Whether the shape is inverse filled is not considered)
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
const Clip* next();
|
||||
const Clip* 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -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 {
|
||||
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;
|
||||
const SkClipStack::Element* element;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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::Element* SkClipStack::Iter::prev() {
|
||||
return (const SkClipStack::Element*)fIter.prev();
|
||||
}
|
||||
|
||||
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::Iter::Clip* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) {
|
||||
const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) {
|
||||
|
||||
if (NULL == fStack) {
|
||||
return NULL;
|
||||
|
@ -350,7 +350,13 @@ void *operator new(size_t, SkTLList<T>* 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)
|
@ -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<SkClipStack::Iter::Clip>* 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,14 +333,11 @@ 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);
|
||||
switch (element->getType()) {
|
||||
case Element::kRect_Type:
|
||||
if (element->isAA()) {
|
||||
getContext()->getAARectRenderer()->fillAARect(fGpu, fGpu, element->getRect(), true);
|
||||
} else {
|
||||
fGpu->drawSimpleRect(*clip->fRect, NULL);
|
||||
fGpu->drawSimpleRect(element->getRect(), NULL);
|
||||
}
|
||||
} else if (NULL != clip->fPath) {
|
||||
return true;
|
||||
case Element::kPath_Type:
|
||||
return draw_path(this->getContext(), fGpu,
|
||||
*clip->fPath,
|
||||
get_path_fill(*clip->fPath),
|
||||
clip->fDoAA,
|
||||
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,7 +944,7 @@ 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,
|
||||
const Element* element = process_initial_clip_elements(&iter,
|
||||
*devResultBounds,
|
||||
&clearToInside,
|
||||
&firstOp,
|
||||
@ -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,7 +1089,7 @@ 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,
|
||||
const Element* element = process_initial_clip_elements(&iter,
|
||||
devRTRect,
|
||||
&clearToInside,
|
||||
&firstOp,
|
||||
@ -1107,14 +1100,14 @@ bool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn,
|
||||
|
||||
// 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,7 +1459,7 @@ 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,
|
||||
const Element* element = process_initial_clip_elements(&iter,
|
||||
*devResultBounds,
|
||||
&clearToInside,
|
||||
&firstOp,
|
||||
@ -1473,9 +1468,9 @@ bool GrClipMaskManager::createSoftwareClipMask(const GrClipData& 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,
|
||||
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,
|
||||
clip->fDoAA, 0xFF);
|
||||
|
||||
} else if (NULL != clip->fPath) {
|
||||
helper.draw(*clip->fPath,
|
||||
op,
|
||||
get_path_fill(*clip->fPath),
|
||||
clip->fDoAA, 0xFF);
|
||||
get_path_fill(element->getPath()),
|
||||
element->isAA(), 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<SkClipStack::Element> 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<SkClipStack::Iter::Clip>* resultClips,
|
||||
ElementList* result,
|
||||
SkRect* resultBounds,
|
||||
bool* resultsAreBounded,
|
||||
InitialState* initialState);
|
||||
|
@ -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,18 +319,23 @@ 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) {
|
||||
SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op);
|
||||
switch (clipEntry->getType()) {
|
||||
case SkClipStack::Element::kRect_Type: {
|
||||
SkRect translatedClip;
|
||||
transform.mapRect(&translatedClip, *clipEntry->fRect);
|
||||
transform.mapRect(&translatedClip, clipEntry->getRect());
|
||||
emit_clip(NULL, &translatedClip, fContentStream);
|
||||
} else if (clipEntry->fPath) {
|
||||
break;
|
||||
}
|
||||
case SkClipStack::Element::kPath_Type: {
|
||||
SkPath translatedPath;
|
||||
clipEntry->fPath->transform(transform, &translatedPath);
|
||||
clipEntry->getPath().transform(transform, &translatedPath);
|
||||
emit_clip(&translatedPath, NULL, fContentStream);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SkASSERT(false);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
switch (element.getType()) {
|
||||
case SkClipStack::Element::kRect_Type: {
|
||||
SkPath path;
|
||||
path.addRect(*clip.fRect);
|
||||
path.addRect(element.getRect());
|
||||
elemRegion.setPath(path, boundsRgn);
|
||||
} else {
|
||||
// TODO: Figure out why we sometimes get here in the reduced clip stack.
|
||||
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<SkClipStack::Iter::Clip> 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());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user