Index: src/core/SkRecordDraw.h |
diff --git a/src/core/SkRecordDraw.h b/src/core/SkRecordDraw.h |
index f3f00881ea69b2cb1be5892c6935a2b5d16df577..9e6c814d31d45cfbf6ac9e820b5341d2936edcf9 100644 |
--- a/src/core/SkRecordDraw.h |
+++ b/src/core/SkRecordDraw.h |
@@ -74,6 +74,93 @@ private: |
typedef Draw INHERITED; |
}; |
+// This is an SkRecord visitor that fills an SkBBoxHierarchy. |
+// |
+// The interesting part here is how to calculate bounds for ops which don't |
+// have intrinsic bounds. What is the bounds of a Save or a Translate? |
+// |
+// We answer this by thinking about a particular definition of bounds: if I |
+// don't execute this op, pixels in this rectangle might draw incorrectly. So |
+// the bounds of a Save, a Translate, a Restore, etc. are the union of the |
+// bounds of Draw* ops that they might have an effect on. For any given |
+// Save/Restore block, the bounds of the Save, the Restore, and any other |
+// non-drawing ("control") ops inside are exactly the union of the bounds of |
+// the drawing ops inside that block. |
+// |
+// To implement this, we keep a stack of active Save blocks. As we consume ops |
+// inside the Save/Restore block, drawing ops are unioned with the bounds of |
+// the block, and control ops are stashed away for later. When we finish the |
+// block with a Restore, our bounds are complete, and we go back and fill them |
+// in for all the control ops we stashed away. |
+class FillBounds : SkNoncopyable { |
+public: |
+ FillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHierarchy* bbh); |
+ |
+ void setCurrentOp(unsigned currentOp) { fCurrentOp = currentOp; } |
+ void cleanUp(); |
+ |
+ template <typename T> void operator()(const T& op) { |
+ this->updateCTM(op); |
+ this->updateClipBounds(op); |
+ this->trackBounds(op); |
+ } |
+ |
+ // In FillBounds, SkRect are in local coordinates, Bounds are translated back to identity space. |
+ typedef SkRect Bounds; |
+ |
+ unsigned currentOp() const { return fCurrentOp; } |
+ const SkMatrix& ctm() const { return *fCTM; } |
+ const Bounds& currentClipBounds() const { return fCurrentClipBounds; } |
+ |
+ Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const; |
+ const Bounds& getBounds(unsigned index) const { return fBounds[index]; } |
+ |
+private: |
+ struct SaveBounds { |
+ int controlOps; // Number of control ops in this Save block, including the Save. |
+ Bounds bounds; // Bounds of everything in the block. |
+ const SkPaint* paint; // Unowned. If set, adjusts the bounds of all ops in this block. |
+ }; |
+ |
+ template <typename T> void updateCTM(const T&); |
+ template <typename T> void updateClipBounds(const T&); |
+ template <typename T> void trackBounds(const T&); |
+ template <typename T> Bounds bounds(const T&) const; |
+ |
+ void updateClipBoundsForClipOp(const SkIRect& devBounds); |
+ |
+ void pushSaveBlock(const SkPaint* paint); |
+ Bounds popSaveBlock(); |
+ void pushControl(); |
+ void popControl(const Bounds& bounds); |
+ void updateSaveBounds(const Bounds& bounds); |
+ |
+ bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const; |
+ |
+ const unsigned int fNumRecords; |
+ |
+ // The BBH being filled in |
+ SkBBoxHierarchy* fBBH; |
+ |
+ // We do not guarantee anything for operations outside of the cull rect |
+ const SkRect fCullRect; |
+ |
+ // Conservative identity-space bounds for each op in the SkRecord. |
+ SkAutoTMalloc<Bounds> fBounds; |
+ |
+ // We walk fCurrentOp through the SkRecord, as we go using updateCTM() |
+ // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative |
+ // identity-space bounds of the current clip (fCurrentClipBounds). |
+ unsigned fCurrentOp; |
+ const SkMatrix* fCTM; |
+ Bounds fCurrentClipBounds; |
+ |
+ // Used to track the bounds of Save/Restore blocks and the control ops inside them. |
+ SkTDArray<SaveBounds> fSaveStack; |
+ SkTDArray<unsigned> fControlIndices; |
+}; |
+ |
+ |
} // namespace SkRecords |
#endif//SkRecordDraw_DEFINED |