diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index fa614c9516..be7bad5aef 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -49,10 +49,28 @@ public: */ void swap(SkPicture& other); + enum RecordingFlags { + /* This flag specifies that when clipPath() is called, the path will + be faithfully recorded, but the recording canvas' current clip will + only see the path's bounds. This speeds up the recording process + without compromising the fidelity of the playback. The only side- + effect for recording is that calling getTotalClip() or related + clip-query calls will reflect the path's bounds, not the actual + path. + */ + kUsePathBoundsForClip_RecordingFlag = 0x01 + }; + /** Returns the canvas that records the drawing commands. + @param width the base width for the picture, as if the recording + canvas' bitmap had this width. + @param height the base width for the picture, as if the recording + canvas' bitmap had this height. + @param recordFlags optional flags that control recording. @return the picture canvas. */ - SkCanvas* beginRecording(int width, int height); + SkCanvas* beginRecording(int width, int height, uint32_t recordFlags = 0); + /** Returns the recording canvas if one is active, or NULL if recording is not active. This does not alter the refcnt on the canvas (if present). */ @@ -103,9 +121,10 @@ private: class SkAutoPictureRecord : SkNoncopyable { public: - SkAutoPictureRecord(SkPicture* pict, int width, int height) { + SkAutoPictureRecord(SkPicture* pict, int width, int height, + uint32_t recordingFlags = 0) { fPicture = pict; - fCanvas = pict->beginRecording(width, height); + fCanvas = pict->beginRecording(width, height, recordingFlags); } ~SkAutoPictureRecord() { fPicture->endRecording(); diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 07cb0a6795..343ca2b4b2 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -146,7 +146,8 @@ void SkPicture::swap(SkPicture& other) { /////////////////////////////////////////////////////////////////////////////// -SkCanvas* SkPicture::beginRecording(int width, int height) { +SkCanvas* SkPicture::beginRecording(int width, int height, + uint32_t recordingFlags) { if (fPlayback) { SkDELETE(fPlayback); fPlayback = NULL; @@ -157,7 +158,7 @@ SkCanvas* SkPicture::beginRecording(int width, int height) { fRecord = NULL; } - fRecord = SkNEW(SkPictureRecord); + fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags)); fWidth = width; fHeight = height; diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index da17c32304..4a3338a976 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -3,6 +3,11 @@ #include "SkTypeface.h" #include +/* Define this to spew out a debug statement whenever we skip the remainder of + a save/restore block because a clip... command returned false (empty). + */ +#define SPEW_CLIP_SKIPPINGx + SkPicturePlayback::SkPicturePlayback() { this->init(); } @@ -461,10 +466,31 @@ SkPicturePlayback::SkPicturePlayback(SkStream* stream) { /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// +#ifdef SPEW_CLIP_SKIPPING +struct SkipClipRec { + int fCount; + size_t fSize; + + SkipClipRec() { + fCount = 0; + fSize = 0; + } + + void recordSkip(size_t bytes) { + fCount += 1; + fSize += bytes; + } +}; +#endif + void SkPicturePlayback::draw(SkCanvas& canvas) { #ifdef ENABLE_TIME_DRAW SkAutoTime at("SkPicture::draw", 50); #endif + +#ifdef SPEW_CLIP_SKIPPING + SkipClipRec skipRect, skipRegion, skipPath; +#endif TextContainer text; fReader.rewind(); @@ -476,8 +502,10 @@ void SkPicturePlayback::draw(SkCanvas& canvas) { SkRegion::Op op = (SkRegion::Op) getInt(); size_t offsetToRestore = getInt(); // HACK (false) until I can handle op==kReplace - if (!canvas.clipPath(path, op) && false) { - //SkDebugf("---- skip clipPath for %d bytes\n", offsetToRestore - fReader.offset()); + if (!canvas.clipPath(path, op)) { +#ifdef SPEW_CLIP_SKIPPING + skipPath.recordSkip(offsetToRestore - fReader.offset()); +#endif fReader.setOffset(offsetToRestore); } } break; @@ -486,7 +514,9 @@ void SkPicturePlayback::draw(SkCanvas& canvas) { SkRegion::Op op = (SkRegion::Op) getInt(); size_t offsetToRestore = getInt(); if (!canvas.clipRegion(region, op)) { - //SkDebugf("---- skip clipDeviceRgn for %d bytes\n", offsetToRestore - fReader.offset()); +#ifdef SPEW_CLIP_SKIPPING + skipRegion.recordSkip(offsetToRestore - fReader.offset()); +#endif fReader.setOffset(offsetToRestore); } } break; @@ -495,7 +525,9 @@ void SkPicturePlayback::draw(SkCanvas& canvas) { SkRegion::Op op = (SkRegion::Op) getInt(); size_t offsetToRestore = getInt(); if (!canvas.clipRect(*rect, op)) { - //SkDebugf("---- skip clipRect for %d bytes\n", offsetToRestore - fReader.offset()); +#ifdef SPEW_CLIP_SKIPPING + skipRect.recordSkip(offsetToRestore - fReader.offset()); +#endif fReader.setOffset(offsetToRestore); } } break; @@ -671,6 +703,14 @@ void SkPicturePlayback::draw(SkCanvas& canvas) { } } +#ifdef SPEW_CLIP_SKIPPING + { + size_t size = skipRect.fSize + skipPath.fSize + skipRegion.fSize; + SkDebugf("--- Clip skips %d%% rect:%d path:%d rgn:%d\n", + size * 100 / fReader.offset(), skipRect.fCount, skipPath.fCount, + skipRegion.fCount); + } +#endif // this->dumpSize(); } diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index 4f236d6833..c1fadc6c5e 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -4,8 +4,8 @@ #define MIN_WRITER_SIZE 16384 #define HEAP_BLOCK_SIZE 4096 -SkPictureRecord::SkPictureRecord() : - fHeap(HEAP_BLOCK_SIZE), fWriter(MIN_WRITER_SIZE) { +SkPictureRecord::SkPictureRecord(uint32_t flags) : + fHeap(HEAP_BLOCK_SIZE), fWriter(MIN_WRITER_SIZE), fRecordFlags(flags) { fBitmapIndex = fMatrixIndex = fPaintIndex = fRegionIndex = 1; #ifdef SK_DEBUG_SIZE fPointBytes = fRectBytes = fTextBytes = 0; @@ -136,7 +136,14 @@ bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op) { fRestoreOffsetStack.top() = offset; validate(); - return this->INHERITED::clipPath(path, op); + + if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { + SkRect bounds; + path.computeBounds(&bounds, SkPath::kFast_BoundsType); + return this->INHERITED::clipRect(bounds, op); + } else { + return this->INHERITED::clipPath(path, op); + } } bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) { diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index b23c747efc..5325e1e386 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -11,7 +11,7 @@ class SkPictureRecord : public SkCanvas { public: - SkPictureRecord(); + SkPictureRecord(uint32_t recordFlags); virtual ~SkPictureRecord(); // overrides from SkCanvas @@ -171,6 +171,8 @@ private: SkRefCntRecorder fRCRecorder; SkRefCntRecorder fTFRecorder; + uint32_t fRecordFlags; + friend class SkPicturePlayback; typedef SkCanvas INHERITED;