diff options
author | 2014-02-07 02:09:50 +0000 | |
---|---|---|
committer | 2014-02-07 02:09:50 +0000 | |
commit | 4f6318d2e64c96fba955ea9154829aee37e155b8 (patch) | |
tree | 844e218de608a5f157b71d82aba618b568b5616a | |
parent | 70ac79b754aa6416a2bf7995792eaf07801dd76c (diff) |
Serialization of SkPictureImageFilter
BUG=skia:
Committed: http://code.google.com/p/skia/source/detail?r=13347
R=senorblanco@google.com, reed@google.com, mtklein@google.com, sugoi@google.com, senorblanco@chromium.org, robertphillips@google.com, scroggo@google.com
Author: sugoi@chromium.org
Review URL: https://codereview.chromium.org/138063005
git-svn-id: http://skia.googlecode.com/svn/trunk@13354 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkPicture.h | 21 | ||||
-rw-r--r-- | include/effects/SkPictureImageFilter.h | 8 | ||||
-rw-r--r-- | samplecode/SampleFilterFuzz.cpp | 35 | ||||
-rw-r--r-- | src/core/SkPicture.cpp | 106 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 40 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.h | 3 | ||||
-rw-r--r-- | src/effects/SkPictureImageFilter.cpp | 18 |
7 files changed, 209 insertions, 22 deletions
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index 82d6835dbd..a717153dbe 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -68,6 +68,16 @@ public: static SkPicture* CreateFromStream(SkStream*, InstallPixelRefProc proc = &SkImageDecoder::DecodeMemory); + /** + * Recreate a picture that was serialized into a buffer. If the creation requires bitmap + * decoding, the decoder must be set on the SkReadBuffer parameter by calling + * SkReadBuffer::setBitmapDecoder() before calling SkPicture::CreateFromBuffer(). + * @param SkReadBuffer Serialized picture data. + * @return A new SkPicture representing the serialized data, or NULL if the buffer is + * invalid. + */ + static SkPicture* CreateFromBuffer(SkReadBuffer&); + virtual ~SkPicture(); /** @@ -187,6 +197,11 @@ public: void serialize(SkWStream*, EncodeBitmap encoder = NULL) const; /** + * Serialize to a buffer. + */ + void flatten(SkWriteBuffer&) const; + + /** * Returns true if any bitmaps may be produced when this SkPicture * is replayed. * Returns false if called while still recording. @@ -223,7 +238,8 @@ protected: // V17: SkPixelRef now writes SkImageInfo // V18: SkBitmap now records x,y for its pixelref origin, instead of offset. // V19: encode matrices and regions into the ops stream - static const uint32_t PICTURE_VERSION = 19; + // V20: added bool to SkPictureImageFilter's serialization (to allow SkPicture serialization) + static const uint32_t PICTURE_VERSION = 20; // fPlayback, fRecord, fWidth & fHeight are protected to allow derived classes to // install their own SkPicturePlayback-derived players,SkPictureRecord-derived @@ -245,7 +261,10 @@ protected: // will be ready to be parsed to create an SkPicturePlayback. // If false is returned, SkPictInfo is unmodified. static bool StreamIsSKP(SkStream*, SkPictInfo*); + static bool BufferIsSKP(SkReadBuffer&, SkPictInfo*); private: + void createHeader(void* header) const; + friend class SkFlatPicture; friend class SkPicturePlayback; diff --git a/include/effects/SkPictureImageFilter.h b/include/effects/SkPictureImageFilter.h index eeaf1d2e46..a10d23eebb 100644 --- a/include/effects/SkPictureImageFilter.h +++ b/include/effects/SkPictureImageFilter.h @@ -28,7 +28,13 @@ public: protected: virtual ~SkPictureImageFilter(); - explicit SkPictureImageFilter(SkReadBuffer& buffer); + /* Constructs an SkPictureImageFilter object from an SkReadBuffer. + * Note: If the SkPictureImageFilter object construction requires bitmap + * decoding, the decoder must be set on the SkReadBuffer parameter by calling + * SkReadBuffer::setBitmapDecoder() before calling this constructor. + * @param SkReadBuffer Serialized picture data. + */ + explicit SkPictureImageFilter(SkReadBuffer&); virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE; diff --git a/samplecode/SampleFilterFuzz.cpp b/samplecode/SampleFilterFuzz.cpp index f77f3b814d..4ef7d4033a 100644 --- a/samplecode/SampleFilterFuzz.cpp +++ b/samplecode/SampleFilterFuzz.cpp @@ -184,6 +184,30 @@ static const SkBitmap& make_bitmap() { return bitmap[R(2)]; } +#ifdef SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION +static void drawSomething(SkCanvas* canvas) { + SkPaint paint; + + canvas->save(); + canvas->scale(0.5f, 0.5f); + canvas->drawBitmap(make_bitmap(), 0, 0, NULL); + canvas->restore(); + + const char beforeStr[] = "before circle"; + const char afterStr[] = "after circle"; + + paint.setAntiAlias(true); + + paint.setColor(SK_ColorRED); + canvas->drawData(beforeStr, sizeof(beforeStr)); + canvas->drawCircle(SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/3), paint); + canvas->drawData(afterStr, sizeof(afterStr)); + paint.setColor(SK_ColorBLACK); + paint.setTextSize(SkIntToScalar(kBitmapSize/3)); + canvas->drawText("Picture", 7, SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/4), paint); +} +#endif + static SkImageFilter* make_image_filter(bool canBeNull = true) { SkImageFilter* filter = 0; @@ -294,7 +318,16 @@ static SkImageFilter* make_image_filter(bool canBeNull = true) { filter = new SkTileImageFilter(make_rect(), make_rect(), make_image_filter(false)); break; case PICTURE: - filter = new SkPictureImageFilter(NULL, make_rect()); + { + SkPicture* pict = NULL; +#ifdef SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION + pict = new SkPicture; + SkAutoUnref aur(pict); + drawSomething(pict->beginRecording(kBitmapSize, kBitmapSize)); + pict->endRecording(); +#endif + filter = new SkPictureImageFilter(pict, make_rect()); + } break; default: break; diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index ca1b6fa22a..0d31ab403e 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -265,6 +265,7 @@ void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) { #include "SkStream.h" static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; +static const size_t kHeaderSize = sizeof(kMagic) + sizeof(SkPictInfo); bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { if (NULL == stream) { @@ -273,8 +274,8 @@ bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { // Check magic bytes. char magic[sizeof(kMagic)]; - stream->read(magic, sizeof(kMagic)); - if (0 != memcmp(magic, kMagic, sizeof(kMagic))) { + if (!stream->read(magic, sizeof(kMagic)) || + (0 != memcmp(magic, kMagic, sizeof(kMagic)))) { return false; } @@ -293,6 +294,30 @@ bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { return true; } +bool SkPicture::BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) { + // Check magic bytes. + char magic[sizeof(kMagic)]; + + if (!buffer.readByteArray(magic, sizeof(kMagic)) || + (0 != memcmp(magic, kMagic, sizeof(kMagic)))) { + return false; + } + + SkPictInfo info; + if (!buffer.readByteArray(&info, sizeof(SkPictInfo))) { + return false; + } + + if (PICTURE_VERSION != info.fVersion) { + return false; + } + + if (pInfo != NULL) { + *pInfo = info; + } + return true; +} + SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height) : fPlayback(playback) , fRecord(NULL) @@ -320,31 +345,56 @@ SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc pro return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight)); } -void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { - SkPicturePlayback* playback = fPlayback; +SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) { + SkPictInfo info; - if (NULL == playback && fRecord) { - playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); + if (!BufferIsSKP(buffer, &info)) { + return NULL; } - SkPictInfo info; + SkPicturePlayback* playback; + // Check to see if there is a playback to recreate. + if (buffer.readBool()) { + playback = SkPicturePlayback::CreateFromBuffer(buffer); + if (NULL == playback) { + return NULL; + } + } else { + playback = NULL; + } + + return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight)); +} - info.fVersion = PICTURE_VERSION; - info.fWidth = fWidth; - info.fHeight = fHeight; - info.fFlags = SkPictInfo::kCrossProcess_Flag; +void SkPicture::createHeader(void* header) const { + // Copy magic bytes at the beginning of the header + SkASSERT(sizeof(kMagic) == 8); + memcpy(header, kMagic, sizeof(kMagic)); + + // Set piture info after magic bytes in the header + SkPictInfo* info = (SkPictInfo*)(((char*)header) + sizeof(kMagic)); + info->fVersion = PICTURE_VERSION; + info->fWidth = fWidth; + info->fHeight = fHeight; + info->fFlags = SkPictInfo::kCrossProcess_Flag; // TODO: remove this flag, since we're always float (now) - info.fFlags |= SkPictInfo::kScalarIsFloat_Flag; + info->fFlags |= SkPictInfo::kScalarIsFloat_Flag; if (8 == sizeof(void*)) { - info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag; + info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag; } +} - // Write 8 magic bytes to ID this file format. - SkASSERT(sizeof(kMagic) == 8); - stream->write(kMagic, sizeof(kMagic)); +void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { + SkPicturePlayback* playback = fPlayback; + + if (NULL == playback && fRecord) { + playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); + } - stream->write(&info, sizeof(info)); + char header[kHeaderSize]; + createHeader(&header); + stream->write(header, kHeaderSize); if (playback) { stream->writeBool(true); playback->serialize(stream, encoder); @@ -357,6 +407,28 @@ void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { } } +void SkPicture::flatten(SkWriteBuffer& buffer) const { + SkPicturePlayback* playback = fPlayback; + + if (NULL == playback && fRecord) { + playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); + } + + char header[kHeaderSize]; + createHeader(&header); + buffer.writeByteArray(header, kHeaderSize); + if (playback) { + buffer.writeBool(true); + playback->flatten(buffer); + // delete playback if it is a local version (i.e. cons'd up just now) + if (playback != fPlayback) { + SkDELETE(playback); + } + } else { + buffer.writeBool(false); + } +} + bool SkPicture::willPlayBackBitmaps() const { if (!fPlayback) return false; return fPlayback->containsBitmaps(); diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index e71a17fda5..8b8c6b0862 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -431,6 +431,22 @@ void SkPicturePlayback::serialize(SkWStream* stream, stream->write32(PICT_EOF_TAG); } +void SkPicturePlayback::flatten(SkWriteBuffer& buffer) const { + writeTagSize(buffer, PICT_READER_TAG, fOpData->size()); + buffer.writeByteArray(fOpData->bytes(), fOpData->size()); + + if (fPictureCount > 0) { + writeTagSize(buffer, PICT_PICTURE_TAG, fPictureCount); + for (int i = 0; i < fPictureCount; i++) { + fPictureRefs[i]->flatten(buffer); + } + } + + // Write this picture playback's data into a writebuffer + this->flattenToBuffer(buffer); + buffer.write32(PICT_EOF_TAG); +} + /////////////////////////////////////////////////////////////////////////////// /** @@ -593,6 +609,15 @@ SkPicturePlayback* SkPicturePlayback::CreateFromStream(SkStream* stream, return playback.detach(); } +SkPicturePlayback* SkPicturePlayback::CreateFromBuffer(SkReadBuffer& buffer) { + SkAutoTDelete<SkPicturePlayback> playback(SkNEW(SkPicturePlayback)); + + if (!playback->parseBuffer(buffer)) { + return NULL; + } + return playback.detach(); +} + bool SkPicturePlayback::parseStream(SkStream* stream, const SkPictInfo& info, SkPicture::InstallPixelRefProc proc) { for (;;) { @@ -609,6 +634,21 @@ bool SkPicturePlayback::parseStream(SkStream* stream, const SkPictInfo& info, return true; } +bool SkPicturePlayback::parseBuffer(SkReadBuffer& buffer) { + for (;;) { + uint32_t tag = buffer.readUInt(); + if (PICT_EOF_TAG == tag) { + break; + } + + uint32_t size = buffer.readUInt(); + if (!this->parseBufferTag(buffer, tag, size)) { + return false; // we're invalid + } + } + return true; +} + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkPicturePlayback.h b/src/core/SkPicturePlayback.h index efa67225b5..909488b4b7 100644 --- a/src/core/SkPicturePlayback.h +++ b/src/core/SkPicturePlayback.h @@ -64,12 +64,14 @@ public: explicit SkPicturePlayback(const SkPictureRecord& record, bool deepCopy = false); static SkPicturePlayback* CreateFromStream(SkStream*, const SkPictInfo&, SkPicture::InstallPixelRefProc); + static SkPicturePlayback* CreateFromBuffer(SkReadBuffer&); virtual ~SkPicturePlayback(); void draw(SkCanvas& canvas, SkDrawPictureCallback*); void serialize(SkWStream*, SkPicture::EncodeBitmap) const; + void flatten(SkWriteBuffer&) const; void dumpSize() const; @@ -84,6 +86,7 @@ public: protected: bool parseStream(SkStream*, const SkPictInfo&, SkPicture::InstallPixelRefProc); + bool parseBuffer(SkReadBuffer& buffer); #ifdef SK_DEVELOPER virtual bool preDraw(int opIndex, int type); virtual void postDraw(int opIndex); diff --git a/src/effects/SkPictureImageFilter.cpp b/src/effects/SkPictureImageFilter.cpp index c78b2499ec..6e76231867 100644 --- a/src/effects/SkPictureImageFilter.cpp +++ b/src/effects/SkPictureImageFilter.cpp @@ -34,13 +34,27 @@ SkPictureImageFilter::~SkPictureImageFilter() { SkPictureImageFilter::SkPictureImageFilter(SkReadBuffer& buffer) : INHERITED(0, buffer), fPicture(NULL) { - // FIXME: unflatten picture here. +#ifdef SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION + if (buffer.readBool()) { + fPicture = SkPicture::CreateFromBuffer(buffer); + } +#else + buffer.readBool(); +#endif buffer.readRect(&fRect); } void SkPictureImageFilter::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); - // FIXME: flatten picture here. +#ifdef SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION + bool hasPicture = (fPicture != NULL); + buffer.writeBool(hasPicture); + if (hasPicture) { + fPicture->flatten(buffer); + } +#else + buffer.writeBool(false); +#endif buffer.writeRect(fRect); } |