Chromium Code Reviews| Index: src/core/SkPicturePlayback.cpp |
| =================================================================== |
| --- src/core/SkPicturePlayback.cpp (revision 9110) |
| +++ src/core/SkPicturePlayback.cpp (working copy) |
| @@ -124,6 +124,12 @@ |
| } |
| } |
| +#if SK_RECORD_BOUNDS_IN_PICTURE |
| + fHasRecordedBounds = true; |
| +#else |
| + fHasRecordedBounds = false; |
| +#endif |
| + |
| #ifdef SK_DEBUG_SIZE |
| int overall = fPlayback->size(&overallBytes); |
| bitmaps = fPlayback->bitmaps(&bitmapBytes); |
| @@ -176,7 +182,7 @@ |
| fBoundingHierarchy = src.fBoundingHierarchy; |
| fStateTree = src.fStateTree; |
| - |
| + fHasRecordedBounds = src.fHasRecordedBounds; |
| SkSafeRef(fBoundingHierarchy); |
| SkSafeRef(fStateTree); |
| @@ -270,6 +276,7 @@ |
| fFactoryPlayback = NULL; |
| fBoundingHierarchy = NULL; |
| fStateTree = NULL; |
| + fHasRecordedBounds = false; |
| } |
| SkPicturePlayback::~SkPicturePlayback() { |
| @@ -592,7 +599,13 @@ |
| SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info, |
| SkPicture::InstallPixelRefProc proc) { |
| this->init(); |
| - |
| +#if SK_RECORD_BOUNDS_IN_PICTURE |
| + fHasRecordedBounds = SkToBool(info.fFlags & SkPictInfo::kHasRecordedBounds_Flag); |
| +#else |
| + // Can't handle skps with recorded bounds in a build that does support them. |
|
Tom Hudson
2013/05/14 17:00:49
Typo: does *not* support them?
|
| + SkASSERT(false == SkToBool(info.fFlags & SkPictInfo::kHasRecordedBounds_Flag)); |
| + fHasRecordedBounds = false; |
| +#endif |
| for (;;) { |
| uint32_t tag = stream->readU32(); |
| if (PICT_EOF_TAG == tag) { |
| @@ -656,6 +669,42 @@ |
| return (DrawType) op; |
| } |
| +// Sets 'bounds' to represent the clip bounds of the playback canvas, |
| +// expressed in the recording device's coordinate space. |
| +// returns true if the bounds are not empty. |
| +static inline bool get_intial_clip_bounds(const SkCanvas& canvas, SkIRect* bounds) { |
| + SkASSERT(NULL != bounds); |
| + SkRect clipBounds; |
| + if (canvas.getClipBounds(&clipBounds)) { |
| + clipBounds.roundOut(bounds); |
| + } else { |
| + bounds->setEmpty(); |
| + return false; |
| + } |
| + return !bounds->isEmpty(); |
| +} |
| + |
| +class SkDisableQuickRejectInScope { |
| +public: |
| + SkDisableQuickRejectInScope() { |
| + fCanvas = NULL; |
|
Tom Hudson
2013/05/14 17:00:49
Why not pass a canvas to the constructor, and avoi
|
| + } |
| + void set(SkCanvas* canvas) { |
| + if (canvas->fQuickRejectEnabled == true) { |
|
Tom Hudson
2013/05/14 17:00:49
// protect against nested Disables
|
| + fCanvas = canvas; |
| + fCanvas->fQuickRejectEnabled = false; |
| + } |
| + } |
| + |
| + ~SkDisableQuickRejectInScope() { |
| + if (fCanvas) { |
| + fCanvas->fQuickRejectEnabled = true; |
| + } |
| + } |
| +private: |
| + SkCanvas* fCanvas; |
| +}; |
| + |
| void SkPicturePlayback::draw(SkCanvas& canvas) { |
| #ifdef ENABLE_TIME_DRAW |
| SkAutoTime at("SkPicture::draw", 50); |
| @@ -677,21 +726,39 @@ |
| TextContainer text; |
| SkTDArray<void*> results; |
| +#if SK_RECORD_BOUNDS_IN_PICTURE |
| + bool initialClipBoundsSet = false; |
| +#endif |
| + 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); |
| - if (results.count() == 0) { |
| - return; |
| - } |
| - SkTQSort<SkPictureStateTree::Draw>( |
| - reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()), |
| - reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1)); |
| + if (!get_intial_clip_bounds(canvas, &initialClipBounds)) { |
| + return; |
|
Tom Hudson
2013/05/14 17:00:49
You now have an early return where it looks like y
|
| } |
| + fBoundingHierarchy->search(initialClipBounds, &results); |
| + if (results.count() == 0) { |
| + return; |
| + } |
| +#if SK_RECORD_BOUNDS_IN_PICTURE |
| + initialClipBoundsSet = true; |
| +#endif |
| + SkTQSort<SkPictureStateTree::Draw>( |
| + reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()), |
| + reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1)); |
| } |
| +#if SK_RECORD_BOUNDS_IN_PICTURE |
| + SkDisableQuickRejectInScope dqr; |
| + if (fHasRecordedBounds) { |
| + // Temporarily disable quickReject testing on 'canvas' |
| + // because it is redundant with early bounds check. |
|
Tom Hudson
2013/05/14 17:00:49
Nit: Second line of this comment is more useful th
|
| + dqr.set(&canvas); |
|
Tom Hudson
2013/05/14 17:00:49
Ugh, given that you need this to be conditionally
|
| + if (!initialClipBoundsSet && !get_intial_clip_bounds(canvas, &initialClipBounds)) { |
| + return; |
| + } |
| + initialClipBoundsSet = true; |
| + } |
| +#endif |
| + |
| SkPictureStateTree::Iterator it = (NULL == fStateTree) ? |
| SkPictureStateTree::Iterator() : |
| fStateTree->getIterator(results, &canvas); |
| @@ -727,9 +794,22 @@ |
| // "curOffset + size" |
| skipTo = this->preDraw(curOffset, op); |
| #endif |
| - if (0 == skipTo && NOOP == op) { |
| - // NOOPs are to be ignored - do not propagate them any further |
| - skipTo = curOffset + size; |
| + if (0 == skipTo) { |
| + if (NOOP == op) { |
| + // NOOPs are to be ignored - do not propagate them any further |
| + skipTo = curOffset + size; |
| + } |
| +#if SK_RECORD_BOUNDS_IN_PICTURE |
| + else 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. |
| + SkASSERT(initialClipBoundsSet); |
| + if (!SkIRect::Intersects(clippedBounds, initialClipBounds)) { |
| + skipTo = curOffset + size; |
| + } |
| + } |
| +#endif |
| } |
| if (0 != skipTo) { |