diff options
-rw-r--r-- | gyp/core.gypi | 2 | ||||
-rw-r--r-- | include/core/SkPicture.h | 1 | ||||
-rw-r--r-- | src/core/SkPicture.cpp | 20 | ||||
-rw-r--r-- | src/core/SkRecordAnalysis.cpp | 66 | ||||
-rw-r--r-- | src/core/SkRecordAnalysis.h | 8 | ||||
-rw-r--r-- | tests/RecordTest.cpp | 43 |
6 files changed, 134 insertions, 6 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi index 49191402ea..31479caff7 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -151,6 +151,8 @@ '<(skia_src_path)/core/SkRasterClip.cpp', '<(skia_src_path)/core/SkRasterizer.cpp', '<(skia_src_path)/core/SkReadBuffer.cpp', + '<(skia_src_path)/core/SkRecordAnalysis.cpp', + '<(skia_src_path)/core/SkRecordAnalysis.h', '<(skia_src_path)/core/SkRecordDraw.cpp', '<(skia_src_path)/core/SkRecordOpts.cpp', '<(skia_src_path)/core/SkRecorder.cpp', diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index 8fcf66707c..62fc633198 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -313,6 +313,7 @@ private: SkPicture(int width, int height, SkRecord*); // Takes ownership. SkAutoTDelete<SkRecord> fRecord; + bool fRecordWillPlayBackBitmaps; // TODO: const }; #endif diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 8d196a130b..0c6f31b2ed 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -19,6 +19,7 @@ #include "SkDrawPictureCallback.h" #include "SkPaintPriv.h" #include "SkPicture.h" +#include "SkRecordAnalysis.h" #include "SkRegion.h" #include "SkStream.h" #include "SkTDArray.h" @@ -132,7 +133,8 @@ static void validateMatrix(const SkMatrix* matrix) { // fRecord OK SkPicture::SkPicture() : fWidth(0) - , fHeight(0) { + , fHeight(0) + , fRecordWillPlayBackBitmaps(false) { this->needsNewGenID(); } @@ -141,7 +143,8 @@ SkPicture::SkPicture(int width, int height, const SkPictureRecord& record, bool deepCopyOps) : fWidth(width) - , fHeight(height) { + , fHeight(height) + , fRecordWillPlayBackBitmaps(false) { this->needsNewGenID(); SkPictInfo info; @@ -170,6 +173,7 @@ SkPicture::SkPicture(const SkPicture& src) : INHERITED() { this->needsNewGenID(); fWidth = src.fWidth; fHeight = src.fHeight; + fRecordWillPlayBackBitmaps = src.fRecordWillPlayBackBitmaps; if (NULL != src.fData.get()) { fData.reset(SkNEW_ARGS(SkPictureData, (*src.fData))); @@ -204,6 +208,7 @@ void SkPicture::clone(SkPicture* pictures, int count) const { clone->fWidth = fWidth; clone->fHeight = fHeight; clone->fData.reset(NULL); + clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps; /* We want to copy the src's playback. However, if that hasn't been built yet, we need to fake a call to endRecording() without actually calling @@ -381,7 +386,8 @@ bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo SkPicture::SkPicture(SkPictureData* data, int width, int height) : fData(data) , fWidth(width) - , fHeight(height) { + , fHeight(height) + , fRecordWillPlayBackBitmaps(false) { this->needsNewGenID(); } @@ -521,8 +527,11 @@ bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **rea } #endif -// fRecord TODO +// fRecord OK bool SkPicture::willPlayBackBitmaps() const { + if (fRecord.get()) { + return fRecordWillPlayBackBitmaps; + } if (!fData.get()) { return false; } @@ -563,6 +572,7 @@ uint32_t SkPicture::uniqueID() const { SkPicture::SkPicture(int width, int height, SkRecord* record) : fWidth(width) , fHeight(height) - , fRecord(record) { + , fRecord(record) + , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) { this->needsNewGenID(); } diff --git a/src/core/SkRecordAnalysis.cpp b/src/core/SkRecordAnalysis.cpp new file mode 100644 index 0000000000..0bfbaef9a6 --- /dev/null +++ b/src/core/SkRecordAnalysis.cpp @@ -0,0 +1,66 @@ +#include "SkRecordAnalysis.h" + +#include "SkShader.h" +#include "SkTLogic.h" + +/** SkRecords visitor to determine whether an instance may require an + "external" bitmap to rasterize. May return false positives. + Does not return true for bitmap text. + + Expected use is to determine whether images need to be decoded before + rasterizing a particular SkRecord. + */ +struct BitmapTester { + // Helpers. These create HasMember_bitmap and HasMember_paint. + SK_CREATE_MEMBER_DETECTOR(bitmap); + SK_CREATE_MEMBER_DETECTOR(paint); + + // Some commands have a paint, some have an optional paint. Either way, get back a pointer. + static const SkPaint* AsPtr(const SkPaint& p) { return &p; } + static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; } + + + // Main entry for visitor: + // If the command has a bitmap directly, return true. + // If the command has a paint and the paint has a bitmap, return true. + // Otherwise, return false. + template <typename T> + bool operator()(const T& r) { return CheckBitmap(r); } + + + // If the command has a bitmap, of course we're going to play back bitmaps. + template <typename T> + static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; } + + // If not, look for one in its paint (if it has a paint). + template <typename T> + static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); } + + // If we have a paint, dig down into the effects looking for a bitmap. + template <typename T> + static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) { + const SkPaint* paint = AsPtr(r.paint); + if (paint) { + const SkShader* shader = paint->getShader(); + if (shader && + shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) { + return true; + } + } + return false; + } + + // If we don't have a paint, that non-paint has no bitmap. + template <typename T> + static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; } +}; + +bool SkRecordWillPlaybackBitmaps(const SkRecord& record) { + BitmapTester tester; + for (unsigned i = 0; i < record.count(); i++) { + if (record.visit<bool>(i, tester)) { + return true; + } + } + return false; +} diff --git a/src/core/SkRecordAnalysis.h b/src/core/SkRecordAnalysis.h new file mode 100644 index 0000000000..6bdd5bc311 --- /dev/null +++ b/src/core/SkRecordAnalysis.h @@ -0,0 +1,8 @@ +#ifndef SkRecordAnalysis_DEFINED +#define SkRecordAnalysis_DEFINED + +#include "SkRecord.h" + +bool SkRecordWillPlaybackBitmaps(const SkRecord& record); + +#endif // SkRecordAnalysis_DEFINED diff --git a/tests/RecordTest.cpp b/tests/RecordTest.cpp index 96f3ad41e1..8ec5bcba76 100644 --- a/tests/RecordTest.cpp +++ b/tests/RecordTest.cpp @@ -7,7 +7,11 @@ #include "Test.h" +#include "SkBitmap.h" +#include "SkImageInfo.h" +#include "SkShader.h" #include "SkRecord.h" +#include "SkRecordAnalysis.h" #include "SkRecords.h" // Sums the area of any DrawRect command it sees. @@ -48,6 +52,8 @@ struct Stretch { } }; +#define APPEND(record, type, ...) SkNEW_PLACEMENT_ARGS(record.append<type>(), type, (__VA_ARGS__)) + // Basic tests for the low-level SkRecord code. DEF_TEST(Record, r) { SkRecord record; @@ -55,7 +61,7 @@ DEF_TEST(Record, r) { // Add a simple DrawRect command. SkRect rect = SkRect::MakeWH(10, 10); SkPaint paint; - SkNEW_PLACEMENT_ARGS(record.append<SkRecords::DrawRect>(), SkRecords::DrawRect, (paint, rect)); + APPEND(record, SkRecords::DrawRect, paint, rect); // Its area should be 100. AreaSummer summer; @@ -70,3 +76,38 @@ DEF_TEST(Record, r) { summer.apply(record); REPORTER_ASSERT(r, summer.area() == 500); } + +DEF_TEST(RecordAnalysis, r) { + SkRecord record; + + SkRect rect = SkRect::MakeWH(10, 10); + SkPaint paint; + APPEND(record, SkRecords::DrawRect, paint, rect); + REPORTER_ASSERT(r, !SkRecordWillPlaybackBitmaps(record)); + + SkBitmap bitmap; + APPEND(record, SkRecords::DrawBitmap, &paint, bitmap, 0.0f, 0.0f); + REPORTER_ASSERT(r, SkRecordWillPlaybackBitmaps(record)); + + SkNEW_PLACEMENT_ARGS(record.replace<SkRecords::DrawRect>(1), + SkRecords::DrawRect, (paint, rect)); + REPORTER_ASSERT(r, !SkRecordWillPlaybackBitmaps(record)); + + SkPaint paint2; + // CreateBitmapShader is too smart for us; an empty (or 1x1) bitmap shader + // gets optimized into a non-bitmap form, so we create a 2x2 bitmap here. + SkBitmap bitmap2; + bitmap2.allocPixels(SkImageInfo::MakeN32Premul(2, 2)); + bitmap2.eraseColor(SK_ColorBLUE); + *(bitmap2.getAddr32(0, 0)) = SK_ColorGREEN; + SkShader* shader = SkShader::CreateBitmapShader(bitmap2, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode); + paint2.setShader(shader); + REPORTER_ASSERT(r, shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType); + + APPEND(record, SkRecords::DrawRect, paint2, rect); + REPORTER_ASSERT(r, SkRecordWillPlaybackBitmaps(record)); +} + +#undef APPEND + |