Index: src/core/SkRecordDraw.cpp |
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp |
index d29e0b8c48c2f21edf706156c30bbededfb6e65e..e075074f40ec1df2238d1b70bdca5a360bfbca09 100644 |
--- a/src/core/SkRecordDraw.cpp |
+++ b/src/core/SkRecordDraw.cpp |
@@ -6,14 +6,46 @@ |
*/ |
#include "SkRecordDraw.h" |
+#include "SkTSort.h" |
-void SkRecordDraw(const SkRecord& record, SkCanvas* canvas, SkDrawPictureCallback* callback) { |
+void SkRecordDraw(const SkRecord& record, |
+ SkCanvas* canvas, |
+ const SkBBoxHierarchy* bbh, |
+ SkDrawPictureCallback* callback) { |
SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); |
- for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) { |
- if (NULL != callback && callback->abortDrawing()) { |
- return; |
+ |
+ if (NULL != bbh) { |
+ SkASSERT(bbh->getCount() == SkToInt(record.count())); |
+ |
+ // Draw only ops that affect pixels in the canvas's current clip. |
+ SkIRect devBounds; |
+ canvas->getClipDeviceBounds(&devBounds); |
+ SkTDArray<void*> ops; |
+ bbh->search(devBounds, &ops); |
+ |
+ // Until we start filling in real bounds, we should get every op back. |
+ SkASSERT(ops.count() == SkToInt(record.count())); |
+ |
+ // FIXME: QuadTree doesn't send these back in the order we inserted them. :( |
+ if (ops.count() > 0) { |
+ SkTQSort(ops.begin(), ops.end() - 1, SkTCompareLT<void*>()); |
+ } |
+ |
+ SkRecords::Draw draw(canvas); |
+ for (int i = 0; i < ops.count(); i++) { |
+ if (NULL != callback && callback->abortDrawing()) { |
+ return; |
+ } |
+ record.visit<void>((uintptr_t)ops[i], draw); // See FillBounds below. |
+ } |
+ } else { |
+ // Draw all ops. |
+ for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) { |
+ if (NULL != callback && callback->abortDrawing()) { |
+ return; |
+ } |
+ record.visit<void>(draw.index(), draw); |
} |
- record.visit<void>(draw.index(), draw); |
} |
} |
@@ -65,4 +97,35 @@ DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co |
r.xmode.get(), r.indices, r.indexCount, r.paint)); |
#undef DRAW |
+ |
+// This is an SkRecord visitor that fills an SkBBoxHierarchy. |
+class FillBounds : SkNoncopyable { |
+public: |
+ explicit FillBounds(SkBBoxHierarchy* bbh) : fBBH(bbh), fIndex(0) {} |
+ ~FillBounds() { fBBH->flushDeferredInserts(); } |
+ |
+ uintptr_t index() const { return fIndex; } |
+ void next() { ++fIndex; } |
+ |
+ template <typename T> void operator()(const T& r) { |
+ // MakeLargest() is a trivially safe default for ops that haven't been bounded yet. |
+ this->insert(this->index(), SkIRect::MakeLargest()); |
+ } |
+ |
+private: |
+ void insert(uintptr_t opIndex, const SkIRect& bounds) { |
+ fBBH->insert((void*)opIndex, bounds, true/*ok to defer*/); |
+ } |
+ |
+ SkBBoxHierarchy* fBBH; // Unowned. The BBH is guaranteed to be ref'd for our lifetime. |
+ uintptr_t fIndex; |
+}; |
+ |
} // namespace SkRecords |
+ |
+void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) { |
+ SkASSERT(NULL != bbh); |
+ for(SkRecords::FillBounds fb(bbh); fb.index() < record.count(); fb.next()) { |
+ record.visit<void>(fb.index(), fb); |
+ } |
+} |