Index: src/core/SkPicturePlayback.cpp |
=================================================================== |
--- src/core/SkPicturePlayback.cpp (revision 8010) |
+++ src/core/SkPicturePlayback.cpp (working copy) |
@@ -124,6 +124,8 @@ |
} |
} |
+ fHasRecordedBounds = record.recordBounds(); |
+ |
#ifdef SK_DEBUG_SIZE |
int overall = fPlayback->size(&overallBytes); |
bitmaps = fPlayback->bitmaps(&bitmapBytes); |
@@ -176,7 +178,7 @@ |
fBoundingHierarchy = src.fBoundingHierarchy; |
fStateTree = src.fStateTree; |
- |
+ fHasRecordedBounds = src.fHasRecordedBounds; |
SkSafeRef(fBoundingHierarchy); |
SkSafeRef(fStateTree); |
@@ -270,6 +272,7 @@ |
fFactoryPlayback = NULL; |
fBoundingHierarchy = NULL; |
fStateTree = NULL; |
+ fHasRecordedBounds = false; |
} |
SkPicturePlayback::~SkPicturePlayback() { |
@@ -586,7 +589,7 @@ |
SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info, |
SkPicture::InstallPixelRefProc proc) { |
this->init(); |
- |
+ fHasRecordedBounds = info.fFlags & SkPictInfo::kHasRecordedBounds_Flag; |
for (;;) { |
uint32_t tag = stream->readU32(); |
if (PICT_EOF_TAG == tag) { |
@@ -671,21 +674,38 @@ |
TextContainer text; |
SkTDArray<void*> results; |
+ bool initialClipBoundsSet = false; |
+ SkIRect initialClipBounds; // only computed if needed |
if (NULL != fStateTree && NULL != fBoundingHierarchy) { |
SkRect clipBounds; |
if (canvas.getClipBounds(&clipBounds)) { |
- SkIRect query; |
- clipBounds.roundOut(&query); |
- fBoundingHierarchy->search(query, &results); |
+ clipBounds.roundOut(&initialClipBounds); |
+ initialClipBoundsSet = true; |
+ fBoundingHierarchy->search(initialClipBounds, &results); |
if (results.count() == 0) { |
return; |
} |
SkTQSort<SkPictureStateTree::Draw>( |
reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()), |
reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1)); |
+ } else { |
+ return; |
} |
} |
+ if (fHasRecordedBounds) { |
+ // TODO(junov): temporarily disable quickReject testing on 'canvas' |
+ // because it is redundant with early bounds check. |
+ if (!initialClipBoundsSet) { |
+ SkRect clipBounds; |
+ if (canvas.getClipBounds(&clipBounds)) { |
+ clipBounds.roundOut(&initialClipBounds); |
+ } else { |
+ return; |
+ } |
+ } |
+ } |
+ |
SkPictureStateTree::Iterator it = (NULL == fStateTree) ? |
SkPictureStateTree::Iterator() : |
fStateTree->getIterator(results, &canvas); |
@@ -715,23 +735,43 @@ |
size_t curOffset = reader.offset(); |
uint32_t size; |
DrawType op = read_op_and_size(&reader, &size); |
+ size_t skipTo = 0; |
if (NOOP == op) { |
// NOOPs are to be ignored - do not propagate them any further |
- reader.setOffset(curOffset+size); |
- continue; |
+ skipTo = curOffset + size; |
} |
+ if (fHasRecordedBounds && SkPictureRecord::canRecordBounds(op)) { |
+ const SkIRect& clippedBounds = reader.skipT<SkIRect>(); |
+ // recording canvas device bounds are in the same coordinate space as |
+ // local clip bounds at start of playback. |
+ if (!SkIRect::Intersects(clippedBounds, initialClipBounds)) { |
+ // This test replaces SkCanvas::quickReject when using |
+ // kRecordBounds_RecordingFlag |
+ skipTo = curOffset + size; |
+ } |
+ } |
#ifdef SK_DEVELOPER |
// TODO: once chunk sizes are in all .skps just use "curOffset + size" |
- size_t skipTo = this->preDraw(curOffset, op); |
+ skipTo = this->preDraw(curOffset, op); |
+#endif |
if (0 != skipTo) { |
+ if (it.isValid()) { |
+ // If using a bounding box hierarchy, advance the state tree |
+ // iterator until at or after skipTo |
+ uint32_t adjustedSkipTo = it.draw(); |
+ while (adjustedSkipTo < skipTo) { |
+ adjustedSkipTo = it.draw(); |
+ } |
+ skipTo = adjustedSkipTo; |
+ } |
if (kDrawComplete == skipTo) { |
break; |
} |
reader.setOffset(skipTo); |
continue; |
} |
-#endif |
+ |
switch (op) { |
case CLIP_PATH: { |
const SkPath& path = getPath(reader); |