Index: src/core/SkClipStack.cpp |
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp |
index c66a219b629bbe7c467eafa946e2487fe067afbe..17eb6f931d31f04d344c27ecc0228fe7a100ce0a 100644 |
--- a/src/core/SkClipStack.cpp |
+++ b/src/core/SkClipStack.cpp |
@@ -16,17 +16,89 @@ |
static const int32_t kFirstUnreservedGenID = 3; |
int32_t SkClipStack::gGenID = kFirstUnreservedGenID; |
+bool SkClipStack::Element::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 kRRect_Type: |
+ return fRRect == element.fRRect; |
+ case kRect_Type: |
+ return fRect == element.fRect; |
+ case kEmpty_Type: |
+ return true; |
+ default: |
+ SkDEBUGFAIL("Unexpected type."); |
+ return false; |
+ } |
+} |
+ |
void SkClipStack::Element::invertShapeFillType() { |
switch (fType) { |
case kRect_Type: |
fPath.reset(); |
fPath.addRect(fRect); |
- fPath.setFillType(SkPath::kInverseWinding_FillType); |
+ fPath.setFillType(SkPath::kInverseEvenOdd_FillType); |
+ fType = kPath_Type; |
+ break; |
+ case kRRect_Type: |
+ fPath.reset(); |
+ fPath.addRRect(fRRect); |
+ fPath.setFillType(SkPath::kInverseEvenOdd_FillType); |
fType = kPath_Type; |
break; |
case kPath_Type: |
fPath.toggleInverseFillType(); |
+ break; |
case kEmpty_Type: |
+ // Should this set to an empty, inverse filled path? |
+ break; |
+ } |
+} |
+ |
+void SkClipStack::Element::initPath(int saveCount, const SkPath& path, SkRegion::Op op, |
+ bool doAA) { |
+ if (!path.isInverseFillType()) { |
+ if (SkPath::kNone_PathAsRect != path.asRect()) { |
+ this->initRect(saveCount, path.getBounds(), op, doAA); |
+ return; |
+ } |
+ SkRect ovalRect; |
+ if (path.isOval(&ovalRect)) { |
+ SkRRect rrect; |
+ rrect.setOval(ovalRect); |
+ this->initRRect(saveCount, rrect, op, doAA); |
+ return; |
+ } |
+ } |
+ fPath = path; |
+ fType = kPath_Type; |
+ this->initCommon(saveCount, op, doAA); |
+} |
+ |
+void SkClipStack::Element::asPath(SkPath* path) const { |
+ switch (fType) { |
+ case kEmpty_Type: |
+ path->reset(); |
+ break; |
+ case kRect_Type: |
+ path->reset(); |
+ path->addRect(fRect); |
+ break; |
+ case kRRect_Type: |
+ path->reset(); |
+ path->addRRect(fRRect); |
+ break; |
+ case kPath_Type: |
+ *path = fPath; |
break; |
} |
} |
@@ -100,10 +172,10 @@ void SkClipStack::Element::combineBoundsDiff(FillCombo combination, const SkRect |
// is erased, so the only pixels that can remain set |
// occur w/in the intersection of the two finite bounds |
if (!fFiniteBound.intersect(prevFinite)) { |
- fFiniteBound.setEmpty(); |
- fGenID = kEmptyGenID; |
+ this->setEmpty(); |
+ } else { |
+ fFiniteBoundType = kNormal_BoundsType; |
} |
- fFiniteBoundType = kNormal_BoundsType; |
break; |
case kPrev_Cur_FillCombo: |
// The most conservative result bound is that of the |
@@ -205,8 +277,7 @@ void SkClipStack::Element::combineBoundsIntersection(int combination, const SkRe |
break; |
case kPrev_Cur_FillCombo: |
if (!fFiniteBound.intersect(prevFinite)) { |
- fFiniteBound.setEmpty(); |
- fGenID = kEmptyGenID; |
+ this->setEmpty(); |
} |
break; |
default: |
@@ -228,10 +299,10 @@ void SkClipStack::Element::combineBoundsRevDiff(int combination, const SkRect& p |
break; |
case kInvPrev_Cur_FillCombo: |
if (!fFiniteBound.intersect(prevFinite)) { |
- fFiniteBound.setEmpty(); |
- fGenID = kEmptyGenID; |
+ this->setEmpty(); |
+ } else { |
+ fFiniteBoundType = kNormal_BoundsType; |
} |
- fFiniteBoundType = kNormal_BoundsType; |
break; |
case kPrev_InvCur_FillCombo: |
fFiniteBound.join(prevFinite); |
@@ -258,27 +329,34 @@ void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { |
// First, optimistically update the current Element's bound information |
// with the current clip's bound |
fIsIntersectionOfRects = false; |
- if (kRect_Type == fType) { |
- fFiniteBound = fRect; |
- fFiniteBoundType = kNormal_BoundsType; |
- |
- if (SkRegion::kReplace_Op == fOp || |
- (SkRegion::kIntersect_Op == fOp && NULL == prior) || |
- (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects && |
- prior->rectRectIntersectAllowed(fRect, fDoAA))) { |
- fIsIntersectionOfRects = true; |
- } |
- |
- } else { |
- SkASSERT(kPath_Type == fType); |
- |
- fFiniteBound = fPath.getBounds(); |
+ switch (fType) { |
+ case kRect_Type: |
+ fFiniteBound = fRect; |
+ fFiniteBoundType = kNormal_BoundsType; |
- if (fPath.isInverseFillType()) { |
- fFiniteBoundType = kInsideOut_BoundsType; |
- } else { |
+ if (SkRegion::kReplace_Op == fOp || |
+ (SkRegion::kIntersect_Op == fOp && NULL == prior) || |
+ (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects && |
+ prior->rectRectIntersectAllowed(fRect, fDoAA))) { |
+ fIsIntersectionOfRects = true; |
+ } |
+ break; |
+ case kRRect_Type: |
+ fFiniteBound = fRRect.getBounds(); |
fFiniteBoundType = kNormal_BoundsType; |
- } |
+ break; |
+ case kPath_Type: |
+ fFiniteBound = fPath.getBounds(); |
+ |
+ if (fPath.isInverseFillType()) { |
+ fFiniteBoundType = kInsideOut_BoundsType; |
+ } else { |
+ fFiniteBoundType = kNormal_BoundsType; |
+ } |
+ break; |
+ case kEmpty_Type: |
+ SkDEBUGFAIL("We shouldn't get here with an empty element."); |
+ break; |
} |
if (!fDoAA) { |
@@ -344,7 +422,7 @@ void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { |
// so nothing to do |
break; |
default: |
- SkDebugf("SkRegion::Op error/n"); |
+ SkDebugf("SkRegion::Op error\n"); |
SkASSERT(0); |
break; |
} |
@@ -528,97 +606,69 @@ bool SkClipStack::quickContains(const SkRect& rect) const { |
return true; |
} |
-void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
- |
+void SkClipStack::pushElement(const Element& element) { |
// Use reverse iterator instead of back because Rect path may need previous |
SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart); |
- Element* element = (Element*) iter.prev(); |
+ Element* prior = (Element*) iter.prev(); |
- if (NULL != element) { |
- if (element->canBeIntersectedInPlace(fSaveCount, op)) { |
- switch (element->fType) { |
+ if (NULL != prior) { |
+ if (prior->canBeIntersectedInPlace(fSaveCount, element.getOp())) { |
+ switch (prior->fType) { |
case Element::kEmpty_Type: |
- element->checkEmpty(); |
+ SkDEBUGCODE(prior->checkEmpty();) |
return; |
case Element::kRect_Type: |
- if (element->rectRectIntersectAllowed(rect, doAA)) { |
- if (!element->fRect.intersect(rect)) { |
- element->setEmpty(); |
+ if (Element::kRect_Type == element.getType()) { |
+ if (prior->rectRectIntersectAllowed(element.getRect(), element.isAA())) { |
+ if (!prior->fRect.intersect(element.getRect())) { |
+ prior->setEmpty(); |
+ return; |
+ } |
+ |
+ prior->fDoAA = element.isAA(); |
+ Element* priorPrior = (Element*) iter.prev(); |
+ prior->updateBoundAndGenID(priorPrior); |
return; |
} |
- |
- element->fDoAA = doAA; |
- Element* prev = (Element*) iter.prev(); |
- element->updateBoundAndGenID(prev); |
- return; |
+ break; |
} |
- break; |
- case Element::kPath_Type: |
- if (!SkRect::Intersects(element->fPath.getBounds(), rect)) { |
- element->setEmpty(); |
+ // fallthrough |
+ default: |
+ if (!SkRect::Intersects(prior->getBounds(), element.getBounds())) { |
+ prior->setEmpty(); |
return; |
} |
break; |
} |
- } else if (SkRegion::kReplace_Op == op) { |
+ } else if (SkRegion::kReplace_Op == element.getOp()) { |
this->restoreTo(fSaveCount - 1); |
- element = (Element*) fDeque.back(); |
+ prior = (Element*) fDeque.back(); |
} |
} |
- new (fDeque.push_back()) Element(fSaveCount, rect, op, doAA); |
- ((Element*) fDeque.back())->updateBoundAndGenID(element); |
+ Element* newElement = SkNEW_PLACEMENT_ARGS(fDeque.push_back(), Element, (element)); |
+ newElement->updateBoundAndGenID(prior); |
} |
-void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
- SkRect alt; |
- if (path.isRect(&alt) && !path.isInverseFillType()) { |
- return this->clipDevRect(alt, op, doAA); |
- } |
+void SkClipStack::clipDevRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
+ Element element(fSaveCount, rrect, op, doAA); |
+ this->pushElement(element); |
+} |
- Element* element = (Element*)fDeque.back(); |
- if (NULL != element) { |
- if (element->canBeIntersectedInPlace(fSaveCount, op)) { |
- const SkRect& pathBounds = path.getBounds(); |
- switch (element->fType) { |
- case Element::kEmpty_Type: |
- element->checkEmpty(); |
- return; |
- case Element::kRect_Type: |
- if (!SkRect::Intersects(element->fRect, pathBounds)) { |
- element->setEmpty(); |
- return; |
- } |
- break; |
- case Element::kPath_Type: |
- if (!SkRect::Intersects(element->fPath.getBounds(), pathBounds)) { |
- element->setEmpty(); |
- return; |
- } |
- break; |
- } |
- } else if (SkRegion::kReplace_Op == op) { |
- this->restoreTo(fSaveCount - 1); |
- element = (Element*) fDeque.back(); |
- } |
- } |
- new (fDeque.push_back()) Element(fSaveCount, path, op, doAA); |
- ((Element*) fDeque.back())->updateBoundAndGenID(element); |
+void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
+ Element element(fSaveCount, rect, op, doAA); |
+ this->pushElement(element); |
} |
-void SkClipStack::clipEmpty() { |
+void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
+ Element element(fSaveCount, path, op, doAA); |
+ this->pushElement(element); |
+} |
+void SkClipStack::clipEmpty() { |
Element* element = (Element*) fDeque.back(); |
if (element && element->canBeIntersectedInPlace(fSaveCount, SkRegion::kIntersect_Op)) { |
- switch (element->fType) { |
- case Element::kEmpty_Type: |
- element->checkEmpty(); |
- return; |
- case Element::kRect_Type: |
- case Element::kPath_Type: |
- element->setEmpty(); |
- return; |
- } |
+ element->setEmpty(); |
} |
new (fDeque.push_back()) Element(fSaveCount); |