From 00f30bdc9e34b013da54b4406f36556c5be8d041 Mon Sep 17 00:00:00 2001 From: mtklein Date: Tue, 2 Sep 2014 12:03:31 -0700 Subject: SkRecordPartialDraw with less code duplication BUG=skia: R=robertphillips@google.com, mtklein@google.com Author: mtklein@chromium.org Review URL: https://codereview.chromium.org/527423002 --- src/core/SkRecordDraw.cpp | 18 ++++++++++++++-- src/core/SkRecordDraw.h | 31 +++++++++++++++++++++++----- tests/RecordDrawTest.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++ tools/DumpRecord.cpp | 14 ++++++------- 4 files changed, 100 insertions(+), 15 deletions(-) diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp index 0117adeefa..f7f02997df 100644 --- a/src/core/SkRecordDraw.cpp +++ b/src/core/SkRecordDraw.cpp @@ -35,15 +35,29 @@ void SkRecordDraw(const SkRecord& record, } } else { // Draw all ops. - for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) { + SkRecords::Draw draw(canvas); + for (unsigned i = 0; i < record.count(); i++) { if (NULL != callback && callback->abortDrawing()) { return; } - record.visit(draw.index(), draw); + record.visit(i, draw); } } } +void SkRecordPartialDraw(const SkRecord& record, + SkCanvas* canvas, + const SkRect& clearRect, + unsigned start, unsigned stop) { + SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); + + stop = SkTMin(stop, record.count()); + SkRecords::PartialDraw draw(canvas, clearRect); + for (unsigned i = start; i < stop; i++) { + record.visit(i, draw); + } +} + namespace SkRecords { // FIXME: SkBitmaps are stateful, so we need to copy them to play back in multiple threads. diff --git a/src/core/SkRecordDraw.h b/src/core/SkRecordDraw.h index 8da7fb5e4a..033b76d34a 100644 --- a/src/core/SkRecordDraw.h +++ b/src/core/SkRecordDraw.h @@ -19,16 +19,16 @@ void SkRecordFillBounds(const SkRecord&, SkBBoxHierarchy*); // Draw an SkRecord into an SkCanvas. A convenience wrapper around SkRecords::Draw. void SkRecordDraw(const SkRecord&, SkCanvas*, const SkBBoxHierarchy*, SkDrawPictureCallback*); +// Draw a portion of an SkRecord into an SkCanvas while replacing clears with drawRects. +void SkRecordPartialDraw(const SkRecord&, SkCanvas*, const SkRect&, unsigned start, unsigned stop); + namespace SkRecords { // This is an SkRecord visitor that will draw that SkRecord to an SkCanvas. class Draw : SkNoncopyable { public: explicit Draw(SkCanvas* canvas) - : fInitialCTM(canvas->getTotalMatrix()), fCanvas(canvas), fIndex(0) {} - - unsigned index() const { return fIndex; } - void next() { ++fIndex; } + : fInitialCTM(canvas->getTotalMatrix()), fCanvas(canvas) {} template void operator()(const T& r) { this->draw(r); @@ -40,7 +40,28 @@ private: const SkMatrix fInitialCTM; SkCanvas* fCanvas; - unsigned fIndex; +}; + +// Used by SkRecordPartialDraw. +class PartialDraw : public Draw { +public: + PartialDraw(SkCanvas* canvas, const SkRect& clearRect) + : INHERITED(canvas), fClearRect(clearRect) {} + + // Same as Draw for all ops except Clear. + template void operator()(const T& r) { + this->INHERITED::operator()(r); + } + void operator()(const Clear& c) { + SkPaint p; + p.setColor(c.color); + DrawRect drawRect(p, fClearRect); + this->INHERITED::operator()(drawRect); + } + +private: + const SkRect fClearRect; + typedef Draw INHERITED; }; } // namespace SkRecords diff --git a/tests/RecordDrawTest.cpp b/tests/RecordDrawTest.cpp index 80f645defd..11b835b0ca 100644 --- a/tests/RecordDrawTest.cpp +++ b/tests/RecordDrawTest.cpp @@ -143,3 +143,55 @@ DEF_TEST(RecordDraw_BBH, r) { REPORTER_ASSERT(r, !SkRect::MakeLTRB(+1, +1, 399, 479).contains(bbh.entries[i].bounds)); } } + +// Base test to ensure start/stop range is respected +DEF_TEST(RecordDraw_PartialStartStop, r) { + static const int kWidth = 10, kHeight = 10; + + SkRect r1 = { 0, 0, kWidth, kHeight }; + SkRect r2 = { 0, 0, kWidth, kHeight/2 }; + SkRect r3 = { 0, 0, kWidth/2, kHeight }; + SkPaint p; + + SkRecord record; + SkRecorder recorder(&record, kWidth, kHeight); + recorder.drawRect(r1, p); + recorder.drawRect(r2, p); + recorder.drawRect(r3, p); + + SkRecord rerecord; + SkRecorder canvas(&rerecord, kWidth, kHeight); + SkRecordPartialDraw(record, &canvas, r1, 1, 2); // replay just drawRect of r2 + + REPORTER_ASSERT(r, 3 == rerecord.count()); + assert_type (r, rerecord, 0); + assert_type (r, rerecord, 1); + assert_type (r, rerecord, 2); + + const SkRecords::DrawRect* drawRect = assert_type(r, rerecord, 1); + REPORTER_ASSERT(r, drawRect->rect == r2); +} + +// Check that clears are converted to drawRects +DEF_TEST(RecordDraw_PartialClear, r) { + static const int kWidth = 10, kHeight = 10; + + SkRect rect = { 0, 0, kWidth, kHeight }; + + SkRecord record; + SkRecorder recorder(&record, kWidth, kHeight); + recorder.clear(SK_ColorRED); + + SkRecord rerecord; + SkRecorder canvas(&rerecord, kWidth, kHeight); + SkRecordPartialDraw(record, &canvas, rect, 0, 1); // replay just the clear + + REPORTER_ASSERT(r, 3 == rerecord.count()); + assert_type (r, rerecord, 0); + assert_type(r, rerecord, 1); + assert_type (r, rerecord, 2); + + const SkRecords::DrawRect* drawRect = assert_type(r, rerecord, 1); + REPORTER_ASSERT(r, drawRect->rect == rect); + REPORTER_ASSERT(r, drawRect->paint.getColor() == SK_ColorRED); +} diff --git a/tools/DumpRecord.cpp b/tools/DumpRecord.cpp index 6e679a5430..c505123acd 100644 --- a/tools/DumpRecord.cpp +++ b/tools/DumpRecord.cpp @@ -20,6 +20,7 @@ public: explicit Dumper(SkCanvas* canvas, int count, bool timeWithCommand) : fDigits(0) , fIndent(0) + , fIndex(0) , fDraw(canvas) , fTimeWithCommand(timeWithCommand) { while (count > 0) { @@ -28,9 +29,6 @@ public: } } - unsigned index() const { return fDraw.index(); } - void next() { fDraw.next(); } - template void operator()(const T& command) { Timer timer; @@ -71,7 +69,7 @@ private: if (!fTimeWithCommand) { printf("%6.1f ", time * 1000); } - printf("%*d ", fDigits, fDraw.index()); + printf("%*d ", fDigits, fIndex++); for (int i = 0; i < fIndent; i++) { putchar('\t'); } @@ -96,6 +94,7 @@ private: int fDigits; int fIndent; + int fIndex; SkRecords::Draw fDraw; const bool fTimeWithCommand; }; @@ -105,9 +104,8 @@ private: void DumpRecord(const SkRecord& record, SkCanvas* canvas, bool timeWithCommand) { - for (Dumper dumper(canvas, record.count(), timeWithCommand); - dumper.index() < record.count(); - dumper.next()) { - record.visit(dumper.index(), dumper); + Dumper dumper(canvas, record.count(), timeWithCommand); + for (unsigned i = 0; i < record.count(); i++) { + record.visit(i, dumper); } } -- cgit v1.2.3