Index: src/core/SkPictureRecord.cpp |
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp |
index be86951ae803f768035906d3fd76ca0bf93a6d9d..978e2b37c2f65dc23f36f2f29c990be713f03ca4 100644 |
--- a/src/core/SkPictureRecord.cpp |
+++ b/src/core/SkPictureRecord.cpp |
@@ -112,6 +112,8 @@ static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) { |
0, // COMMENT - no paint |
0, // END_GROUP - no paint |
1, // DRAWDRRECT - right after op code |
+ 0, // PUSH_CULL - no paint |
+ 0, // POP_CULL - no paint |
}; |
SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, |
@@ -220,6 +222,15 @@ bool SkPictureRecord::isDrawingToLayer() const { |
} |
/* |
+ * Read the op code from 'offset' in 'writer'. |
+ */ |
+#ifdef SK_DEBUG |
+static DrawType peek_op(SkWriter32* writer, int32_t offset) { |
+ return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24); |
+} |
+#endif |
+ |
+/* |
* Read the op code from 'offset' in 'writer' and extract the size too. |
*/ |
static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) { |
@@ -1548,6 +1559,61 @@ void SkPictureRecord::endCommentGroup() { |
this->validate(initialOffset, size); |
} |
+// [op/size] [rect] [skip offset] |
+static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect); |
+void SkPictureRecord::onPushCull(const SkRect& cullRect) { |
+ // Skip identical cull rects. |
+ if (!fCullOffsetStack.isEmpty()) { |
+ const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect)); |
+ if (prevCull == cullRect) { |
+ // Skipped culls are tracked on the stack, but they point to the previous offset. |
+ fCullOffsetStack.push(fCullOffsetStack.top()); |
+ return; |
+ } |
+ |
+ SkASSERT(prevCull.contains(cullRect)); |
+ } |
+ |
+ uint32_t size = kPushCullOpSize; |
+ size_t initialOffset = this->addDraw(PUSH_CULL, &size); |
+ // PUSH_CULL's size should stay constant (used to rewind). |
+ SkASSERT(size == kPushCullOpSize); |
+ |
+ this->addRect(cullRect); |
+ fCullOffsetStack.push(fWriter.bytesWritten()); |
+ this->addInt(0); |
+ this->validate(initialOffset, size); |
+} |
+ |
+void SkPictureRecord::onPopCull() { |
+ SkASSERT(!fCullOffsetStack.isEmpty()); |
+ |
+ uint32_t cullSkipOffset = fCullOffsetStack.top(); |
+ fCullOffsetStack.pop(); |
+ |
+ // Skipped push, do the same for pop. |
+ if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) { |
+ return; |
+ } |
+ |
+ // Collapse empty push/pop pairs. |
+ if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) { |
+ SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize); |
+ SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize)); |
+ fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize); |
+ return; |
+ } |
+ |
+ // op only |
+ uint32_t size = kUInt32Size; |
+ size_t initialOffset = this->addDraw(POP_CULL, &size); |
+ |
+ // update the cull skip offset to point past this op. |
+ fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten()); |
+ |
+ this->validate(initialOffset, size); |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) { |