Index: src/core/SkCanvas.cpp |
=================================================================== |
--- src/core/SkCanvas.cpp (revision 9298) |
+++ src/core/SkCanvas.cpp (working copy) |
@@ -1279,6 +1279,74 @@ |
return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); |
} |
+bool SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, |
reed1
2013/05/29 18:54:01
/**
* This *never* calls back through a virtual o
|
+ bool inverseFilled) { |
+ // This is for updating the clip conservatively using only bounds |
+ // information. |
+ // Contract: |
+ // The current clip must contain the true clip. The true |
+ // clip is the clip that would have normally been computed |
+ // by calls to clipPath and clipRRect |
+ // Objective: |
+ // Keep the current clip as small as possible without |
+ // breaking the contract, using only clip bounding rectangles |
+ // (for performance). |
+ if (inverseFilled) { |
+ switch (op) { |
+ case SkRegion::kIntersect_Op: |
+ case SkRegion::kDifference_Op: |
+ // These ops can only shrink the current clip. So leaving |
+ // the clip unchanges conservatively respects the contract. |
+ return this->getClipDeviceBounds(NULL); |
+ case SkRegion::kUnion_Op: |
+ case SkRegion::kReplace_Op: |
+ case SkRegion::kReverseDifference_Op: |
+ case SkRegion::kXOR_Op: |
+ { |
+ // These ops can grow the current clip up to the extents of |
+ // the input clip, which is inverse filled, so we just set |
+ // the current clip to the device bounds. |
+ SkRect deviceBounds; |
+ SkIRect deviceIBounds; |
+ this->getDevice()->getGlobalBounds(&deviceIBounds); |
+ deviceBounds = SkRect::MakeFromIRect(deviceIBounds); |
+ this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); |
+ // set the clip in device space |
+ this->SkCanvas::setMatrix(SkMatrix::I()); |
+ bool result = this->SkCanvas::clipRect(deviceBounds, |
+ SkRegion::kReplace_Op, false); |
+ this->SkCanvas::restore(); //pop the matrix, but keep the clip |
+ return result; |
+ } |
+ default: |
+ SkASSERT(0); // unhandled op? |
+ } |
+ } else { |
+ // Not inverse filled |
+ switch (op) { |
+ case SkRegion::kIntersect_Op: |
+ case SkRegion::kUnion_Op: |
+ case SkRegion::kReplace_Op: |
+ return this->SkCanvas::clipRect(bounds, op, false); |
+ case SkRegion::kDifference_Op: |
+ // Difference can only shrink the current clip. |
+ // Leaving clip unchanged conservatively fullfills the contract. |
+ return this->getClipDeviceBounds(NULL); |
+ case SkRegion::kReverseDifference_Op: |
+ // To reverse, we swap in the bounds with a replace op. |
+ // As with difference, leave it unchanged. |
+ return this->SkCanvas::clipRect(bounds, SkRegion::kReplace_Op, false); |
+ case SkRegion::kXOR_Op: |
+ // Be conservative, based on (A XOR B) always included in (A union B), |
+ // which is always included in (bounds(A) union bounds(B)) |
+ return this->SkCanvas::clipRect(bounds, SkRegion::kUnion_Op, false); |
+ default: |
+ SkASSERT(0); // unhandled op? |
+ } |
+ } |
+ return true; |
+} |
+ |
bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
AutoValidateClip avc(this); |