Index: src/core/SkClipStack.cpp |
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp |
index 9e3f7c6b308071c16397e1cd6ece7d2abefc9a64..2c0961ab83c8254654078782903364666e260209 100644 |
--- a/src/core/SkClipStack.cpp |
+++ b/src/core/SkClipStack.cpp |
@@ -452,6 +452,7 @@ void SkClipStack::restoreTo(int saveCount) { |
if (element->fSaveCount <= saveCount) { |
break; |
} |
+ this->purgeClip(element); |
element->~Element(); |
fDeque.pop_back(); |
} |
@@ -539,6 +540,7 @@ void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
return; |
case Element::kRect_Type: |
if (element->rectRectIntersectAllowed(rect, doAA)) { |
+ this->purgeClip(element); |
if (!element->fRect.intersect(rect)) { |
element->setEmpty(); |
return; |
@@ -552,6 +554,7 @@ void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
break; |
case Element::kPath_Type: |
if (!SkRect::Intersects(element->fPath.getBounds(), rect)) { |
+ this->purgeClip(element); |
element->setEmpty(); |
return; |
} |
@@ -564,6 +567,10 @@ void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
} |
new (fDeque.push_back()) Element(fSaveCount, rect, op, doAA); |
((Element*) fDeque.back())->updateBoundAndGenID(element); |
+ |
+ if (element && element->fSaveCount == fSaveCount) { |
+ this->purgeClip(element); |
+ } |
} |
void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
@@ -582,12 +589,14 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
return; |
case Element::kRect_Type: |
if (!SkRect::Intersects(element->fRect, pathBounds)) { |
+ this->purgeClip(element); |
element->setEmpty(); |
return; |
} |
break; |
case Element::kPath_Type: |
if (!SkRect::Intersects(element->fPath.getBounds(), pathBounds)) { |
+ this->purgeClip(element); |
element->setEmpty(); |
return; |
} |
@@ -600,6 +609,10 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
} |
new (fDeque.push_back()) Element(fSaveCount, path, op, doAA); |
((Element*) fDeque.back())->updateBoundAndGenID(element); |
+ |
+ if (element && element->fSaveCount == fSaveCount) { |
+ this->purgeClip(element); |
+ } |
} |
void SkClipStack::clipEmpty() { |
@@ -613,17 +626,27 @@ void SkClipStack::clipEmpty() { |
return; |
case Element::kRect_Type: |
case Element::kPath_Type: |
+ this->purgeClip(element); |
element->setEmpty(); |
return; |
} |
} |
new (fDeque.push_back()) Element(fSaveCount); |
+ if (element && element->fSaveCount == fSaveCount) { |
+ this->purgeClip(element); |
+ } |
((Element*)fDeque.back())->fGenID = kEmptyGenID; |
} |
bool SkClipStack::isWideOpen() const { |
- return this->getTopmostGenID() == kWideOpenGenID; |
+ if (0 == fDeque.count()) { |
+ return true; |
+ } |
+ |
+ const Element* back = (const Element*) fDeque.back(); |
+ return kWideOpenGenID == back->fGenID || |
+ (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.isEmpty()); |
} |
/////////////////////////////////////////////////////////////////////////////// |
@@ -717,20 +740,45 @@ void SkClipStack::getConservativeBounds(int offsetX, |
} |
} |
+void SkClipStack::addPurgeClipCallback(PFPurgeClipCB callback, void* data) const { |
+ ClipCallbackData temp = { callback, data }; |
+ fCallbackData.append(1, &temp); |
+} |
+ |
+void SkClipStack::removePurgeClipCallback(PFPurgeClipCB callback, void* data) const { |
+ ClipCallbackData temp = { callback, data }; |
+ int index = fCallbackData.find(temp); |
+ if (index >= 0) { |
+ fCallbackData.removeShuffle(index); |
+ } |
+} |
+ |
+// The clip state represented by 'element' will never be used again. Purge it. |
+void SkClipStack::purgeClip(Element* element) { |
+ SkASSERT(NULL != element); |
+ if (element->fGenID >= 0 && element->fGenID < kFirstUnreservedGenID) { |
+ return; |
+ } |
+ |
+ for (int i = 0; i < fCallbackData.count(); ++i) { |
+ (*fCallbackData[i].fCallback)(element->fGenID, fCallbackData[i].fData); |
+ } |
+ |
+ // Invalidate element's gen ID so handlers can detect already handled records |
+ element->fGenID = kInvalidGenID; |
+} |
+ |
int32_t SkClipStack::GetNextGenID() { |
// TODO: handle overflow. |
return sk_atomic_inc(&gGenID); |
} |
int32_t SkClipStack::getTopmostGenID() const { |
- if (fDeque.empty()) { |
- return kWideOpenGenID; |
- } |
- const Element* back = static_cast<const Element*>(fDeque.back()); |
- if (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.isEmpty()) { |
- return kWideOpenGenID; |
+ if (fDeque.empty()) { |
+ return kInvalidGenID; |
} |
- return back->getGenID(); |
+ Element* element = (Element*)fDeque.back(); |
+ return element->fGenID; |
} |