aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-04-27 13:51:20 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-04-27 13:51:20 -0700
commit95416f477d2ca264f2fb065455e95778a2289a1d (patch)
tree41aa18dccbe6e45d771abb4256b850c1ffb09bdd
parent80f5ea02cf69096e00b8fe01fe54375a9387c9d9 (diff)
Enable flattening of SkRecordedDrawable
-rw-r--r--gyp/core.gypi1
-rw-r--r--src/core/SkGlobalInitialization_core.cpp6
-rw-r--r--src/core/SkPictureData.cpp37
-rw-r--r--src/core/SkPictureData.h10
-rw-r--r--src/core/SkPictureFlat.h4
-rw-r--r--src/core/SkPicturePlayback.cpp9
-rw-r--r--src/core/SkPictureRecord.cpp29
-rw-r--r--src/core/SkPictureRecord.h7
-rw-r--r--src/core/SkPictureRecorder.cpp61
-rw-r--r--src/core/SkRecordedDrawable.cpp102
-rw-r--r--src/core/SkRecordedDrawable.h43
-rw-r--r--tests/FlattenDrawableTest.cpp39
12 files changed, 286 insertions, 62 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi
index c2dd432535..181417cca6 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -239,6 +239,7 @@
'<(skia_src_path)/core/SkRecordOpts.cpp',
'<(skia_src_path)/core/SkRecordOpts.h',
'<(skia_src_path)/core/SkRecordPattern.h',
+ '<(skia_src_path)/core/SkRecordedDrawable.cpp',
'<(skia_src_path)/core/SkRecorder.cpp',
'<(skia_src_path)/core/SkRect.cpp',
'<(skia_src_path)/core/SkRefDict.cpp',
diff --git a/src/core/SkGlobalInitialization_core.cpp b/src/core/SkGlobalInitialization_core.cpp
index d7b4a80003..e377437a99 100644
--- a/src/core/SkGlobalInitialization_core.cpp
+++ b/src/core/SkGlobalInitialization_core.cpp
@@ -14,10 +14,11 @@
#include "SkFlattenable.h"
#include "SkImageShader.h"
#include "SkLocalMatrixShader.h"
+#include "SkMatrixImageFilter.h"
#include "SkOnce.h"
#include "SkPathEffect.h"
#include "SkPictureShader.h"
-#include "SkMatrixImageFilter.h"
+#include "SkRecordedDrawable.h"
#include "SkXfermode.h"
/*
@@ -49,6 +50,9 @@ void SkFlattenable::PrivateInitializer::InitCore() {
// Xfermode
SkXfermode::InitializeFlattenables();
+ // Drawable
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRecordedDrawable)
+
// Now initialize any optional/additional effects (implemented in src/ports)
InitEffects();
};
diff --git a/src/core/SkPictureData.cpp b/src/core/SkPictureData.cpp
index 92aa2410ad..4de1cc3cec 100644
--- a/src/core/SkPictureData.cpp
+++ b/src/core/SkPictureData.cpp
@@ -66,6 +66,16 @@ SkPictureData::SkPictureData(const SkPictureRecord& record,
}
}
+ const SkTDArray<SkDrawable* >& drawables = record.getDrawableRefs();
+ fDrawableCount = drawables.count();
+ if (fDrawableCount > 0) {
+ fDrawableRefs = new SkDrawable* [fDrawableCount];
+ for (int i = 0; i < fDrawableCount; i++) {
+ fDrawableRefs[i] = drawables[i];
+ fDrawableRefs[i]->ref();
+ }
+ }
+
// templatize to consolidate with similar picture logic?
const SkTDArray<const SkTextBlob*>& blobs = record.getTextBlobRefs();
fTextBlobCount = blobs.count();
@@ -89,6 +99,8 @@ SkPictureData::SkPictureData(const SkPictureRecord& record,
void SkPictureData::init() {
fPictureRefs = nullptr;
fPictureCount = 0;
+ fDrawableRefs = nullptr;
+ fDrawableCount = 0;
fTextBlobRefs = nullptr;
fTextBlobCount = 0;
fImageRefs = nullptr;
@@ -102,6 +114,14 @@ SkPictureData::~SkPictureData() {
}
delete[] fPictureRefs;
+ for (int i = 0; i < fDrawableCount; i++) {
+ fDrawableRefs[i]->unref();
+ }
+ if (fDrawableCount > 0) {
+ SkASSERT(fDrawableRefs);
+ delete[] fDrawableRefs;
+ }
+
for (int i = 0; i < fTextBlobCount; i++) {
fTextBlobRefs[i]->unref();
}
@@ -306,6 +326,13 @@ void SkPictureData::flatten(SkWriteBuffer& buffer) const {
}
}
+ if (fDrawableCount > 0) {
+ write_tag_size(buffer, SK_PICT_DRAWABLE_TAG, fDrawableCount);
+ for (int i = 0; i < fDrawableCount; i++) {
+ buffer.writeFlattenable(fDrawableRefs[i]);
+ }
+ }
+
// Write this picture playback's data into a writebuffer
this->flattenToBuffer(buffer);
buffer.write32(SK_PICT_EOF_TAG);
@@ -450,6 +477,10 @@ static const SkPicture* create_picture_from_buffer(SkReadBuffer& buffer) {
return SkPicture::MakeFromBuffer(buffer).release();
}
+static const SkDrawable* create_drawable_from_buffer(SkReadBuffer& buffer) {
+ return (SkDrawable*) buffer.readFlattenable(SkFlattenable::kSkDrawable_Type);
+}
+
template <typename T>
bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
const T*** array, int* outCount, const T* (*factory)(SkReadBuffer&)) {
@@ -540,6 +571,12 @@ bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t
return false;
}
break;
+ case SK_PICT_DRAWABLE_TAG:
+ if (!new_array_from_buffer(buffer, size, (const SkDrawable***)&fDrawableRefs,
+ &fDrawableCount, create_drawable_from_buffer)) {
+ return false;
+ }
+ break;
default:
// The tag was invalid.
return false;
diff --git a/src/core/SkPictureData.h b/src/core/SkPictureData.h
index dbb117ef14..4870305de4 100644
--- a/src/core/SkPictureData.h
+++ b/src/core/SkPictureData.h
@@ -9,6 +9,7 @@
#define SkPictureData_DEFINED
#include "SkBitmap.h"
+#include "SkDrawable.h"
#include "SkPicture.h"
#include "SkPictureContentInfo.h"
#include "SkPictureFlat.h"
@@ -43,6 +44,7 @@ struct SkPictInfo {
#define SK_PICT_FACTORY_TAG SkSetFourByteTag('f', 'a', 'c', 't')
#define SK_PICT_TYPEFACE_TAG SkSetFourByteTag('t', 'p', 'f', 'c')
#define SK_PICT_PICTURE_TAG SkSetFourByteTag('p', 'c', 't', 'r')
+#define SK_PICT_DRAWABLE_TAG SkSetFourByteTag('d', 'r', 'a', 'w')
// This tag specifies the size of the ReadBuffer, needed for the following tags
#define SK_PICT_BUFFER_SIZE_TAG SkSetFourByteTag('a', 'r', 'a', 'y')
@@ -107,6 +109,12 @@ public:
return reader->validateIndex(index, fPictureCount) ? fPictureRefs[index] : nullptr;
}
+ SkDrawable* getDrawable(SkReadBuffer* reader) const {
+ int index = reader->readInt();
+ SkASSERT(index > 0 && index <= fDrawableCount);
+ return fDrawableRefs[index - 1];
+ }
+
const SkPaint* getPaint(SkReadBuffer* reader) const {
const int index = reader->readInt() - 1;
return reader->validateIndex(index, fPaints.count()) ? &fPaints[index] : nullptr;
@@ -160,6 +168,8 @@ private:
const SkPicture** fPictureRefs;
int fPictureCount;
+ SkDrawable** fDrawableRefs;
+ int fDrawableCount;
const SkTextBlob** fTextBlobRefs;
int fTextBlobCount;
const SkImage** fImageRefs;
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index cd750bffab..edfe24a451 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -78,8 +78,10 @@ enum DrawType {
SAVE_LAYER_SAVELAYERREC,
DRAW_ANNOTATION,
+ DRAW_DRAWABLE,
+ DRAW_DRAWABLE_MATRIX,
- LAST_DRAWTYPE_ENUM = DRAW_ANNOTATION,
+ LAST_DRAWTYPE_ENUM = DRAW_DRAWABLE_MATRIX,
};
// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 3316fe958e..beb745ff1a 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -257,6 +257,15 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
(void)reader->skip(length);
// skip handles padding the read out to a multiple of 4
} break;
+ case DRAW_DRAWABLE:
+ canvas->drawDrawable(fPictureData->getDrawable(reader));
+ break;
+ case DRAW_DRAWABLE_MATRIX: {
+ SkMatrix matrix;
+ reader->readMatrix(&matrix);
+ SkDrawable* drawable = fPictureData->getDrawable(reader);
+ canvas->drawDrawable(drawable, &matrix);
+ } break;
case DRAW_DRRECT: {
const SkPaint& paint = *fPictureData->getPaint(reader);
SkRRect outer, inner;
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index afde01bbfb..4a6ece17f2 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -33,6 +33,7 @@ SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
SkPictureRecord::~SkPictureRecord() {
fImageRefs.unrefAll();
fPictureRefs.unrefAll();
+ fDrawableRefs.unrefAll();
fTextBlobRefs.unrefAll();
}
@@ -637,6 +638,23 @@ void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* ma
this->validate(initialOffset, size);
}
+void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
+ // op + drawable index
+ size_t size = 2 * kUInt32Size;
+ size_t initialOffset;
+
+ if (nullptr == matrix) {
+ initialOffset = this->addDraw(DRAW_DRAWABLE, &size);
+ this->addDrawable(drawable);
+ } else {
+ size += matrix->writeToMemory(nullptr); // matrix
+ initialOffset = this->addDraw(DRAW_DRAWABLE_MATRIX, &size);
+ this->addMatrix(*matrix);
+ this->addDrawable(drawable);
+ }
+ this->validate(initialOffset, size);
+}
+
void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xfer,
@@ -918,6 +936,17 @@ void SkPictureRecord::addPicture(const SkPicture* picture) {
this->addInt(index + 1);
}
+void SkPictureRecord::addDrawable(SkDrawable* drawable) {
+ int index = fDrawableRefs.find(drawable);
+ if (index < 0) { // not found
+ index = fDrawableRefs.count();
+ *fDrawableRefs.append() = drawable;
+ drawable->ref();
+ }
+ // follow the convention of recording a 1-based index
+ this->addInt(index + 1);
+}
+
void SkPictureRecord::addPoint(const SkPoint& point) {
fWriter.writePoint(point);
}
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 129f94f9b3..59bd92dc77 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -35,6 +35,10 @@ public:
return fPictureRefs;
}
+ const SkTDArray<SkDrawable* >& getDrawableRefs() const {
+ return fDrawableRefs;
+ }
+
const SkTDArray<const SkTextBlob* >& getTextBlobRefs() const {
return fTextBlobRefs;
}
@@ -131,6 +135,7 @@ private:
void addPatch(const SkPoint cubics[12]);
void addPath(const SkPath& path);
void addPicture(const SkPicture* picture);
+ void addDrawable(SkDrawable* picture);
void addPoint(const SkPoint& point);
void addPoints(const SkPoint pts[], int count);
void addRect(const SkRect& rect);
@@ -204,6 +209,7 @@ protected:
void onClipRegion(const SkRegion&, SkRegion::Op) override;
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+ void onDrawDrawable(SkDrawable*, const SkMatrix*) override;
void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
int addPathToHeap(const SkPath& path); // does not write to ops stream
@@ -238,6 +244,7 @@ private:
// we ref each item in these arrays
SkTDArray<const SkImage*> fImageRefs;
SkTDArray<const SkPicture*> fPictureRefs;
+ SkTDArray<SkDrawable*> fDrawableRefs;
SkTDArray<const SkTextBlob*> fTextBlobRefs;
uint32_t fRecordFlags;
diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp
index b6bb34d5b4..a157d0dfe0 100644
--- a/src/core/SkPictureRecorder.cpp
+++ b/src/core/SkPictureRecorder.cpp
@@ -14,6 +14,7 @@
#include "SkRecord.h"
#include "SkRecordDraw.h"
#include "SkRecordOpts.h"
+#include "SkRecordedDrawable.h"
#include "SkRecorder.h"
#include "SkTypes.h"
@@ -117,66 +118,6 @@ void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
}
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class SkRecordedDrawable : public SkDrawable {
- SkAutoTUnref<SkRecord> fRecord;
- SkAutoTUnref<SkBBoxHierarchy> fBBH;
- SkAutoTDelete<SkDrawableList> fDrawableList;
- const SkRect fBounds;
- const bool fDoSaveLayerInfo;
-
-public:
- SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkDrawableList* drawableList,
- const SkRect& bounds, bool doSaveLayerInfo)
- : fRecord(SkRef(record))
- , fBBH(SkSafeRef(bbh))
- , fDrawableList(drawableList) // we take ownership
- , fBounds(bounds)
- , fDoSaveLayerInfo(doSaveLayerInfo)
- {}
-
-protected:
- SkRect onGetBounds() override { return fBounds; }
-
- void onDraw(SkCanvas* canvas) override {
- SkDrawable* const* drawables = nullptr;
- int drawableCount = 0;
- if (fDrawableList) {
- drawables = fDrawableList->begin();
- drawableCount = fDrawableList->count();
- }
- SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, fBBH, nullptr/*callback*/);
- }
-
- SkPicture* onNewPictureSnapshot() override {
- SkBigPicture::SnapshotArray* pictList = nullptr;
- if (fDrawableList) {
- // TODO: should we plumb-down the BBHFactory and recordFlags from our host
- // PictureRecorder?
- pictList = fDrawableList->newDrawableSnapshot();
- }
-
- SkAutoTUnref<SkLayerInfo> saveLayerData;
- if (fBBH && fDoSaveLayerInfo) {
- // TODO: can we avoid work by not allocating / filling these bounds?
- SkAutoTMalloc<SkRect> scratchBounds(fRecord->count());
- saveLayerData.reset(new SkLayerInfo);
-
- SkRecordComputeLayers(fBounds, *fRecord, scratchBounds, pictList, saveLayerData);
- }
-
- size_t subPictureBytes = 0;
- for (int i = 0; pictList && i < pictList->count(); i++) {
- subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
- }
- // SkBigPicture will take ownership of a ref on both fRecord and fBBH.
- // We're not willing to give up our ownership, so we must ref them for SkPicture.
- return new SkBigPicture(fBounds, SkRef(fRecord.get()), pictList, SkSafeRef(fBBH.get()),
- saveLayerData.release(), subPictureBytes);
- }
-};
-
sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable() {
fActivelyRecording = false;
fRecorder->flushMiniRecorder();
diff --git a/src/core/SkRecordedDrawable.cpp b/src/core/SkRecordedDrawable.cpp
new file mode 100644
index 0000000000..9b5874f927
--- /dev/null
+++ b/src/core/SkRecordedDrawable.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkLayerInfo.h"
+#include "SkMatrix.h"
+#include "SkPictureData.h"
+#include "SkPicturePlayback.h"
+#include "SkPictureRecord.h"
+#include "SkPictureRecorder.h"
+#include "SkPictureUtils.h"
+#include "SkRecordedDrawable.h"
+#include "SkRecordDraw.h"
+
+void SkRecordedDrawable::onDraw(SkCanvas* canvas) {
+ SkDrawable* const* drawables = nullptr;
+ int drawableCount = 0;
+ if (fDrawableList) {
+ drawables = fDrawableList->begin();
+ drawableCount = fDrawableList->count();
+ }
+ SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, fBBH, nullptr/*callback*/);
+}
+
+SkPicture* SkRecordedDrawable::onNewPictureSnapshot() {
+ SkBigPicture::SnapshotArray* pictList = nullptr;
+ if (fDrawableList) {
+ // TODO: should we plumb-down the BBHFactory and recordFlags from our host
+ // PictureRecorder?
+ pictList = fDrawableList->newDrawableSnapshot();
+ }
+
+ SkAutoTUnref<SkLayerInfo> saveLayerData;
+ if (fBBH && fDoSaveLayerInfo) {
+ // TODO: can we avoid work by not allocating / filling these bounds?
+ SkAutoTMalloc<SkRect> scratchBounds(fRecord->count());
+ saveLayerData.reset(new SkLayerInfo);
+
+ SkRecordComputeLayers(fBounds, *fRecord, scratchBounds, pictList, saveLayerData);
+ }
+
+ size_t subPictureBytes = 0;
+ for (int i = 0; pictList && i < pictList->count(); i++) {
+ subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
+ }
+ // SkBigPicture will take ownership of a ref on both fRecord and fBBH.
+ // We're not willing to give up our ownership, so we must ref them for SkPicture.
+ return new SkBigPicture(fBounds, SkRef(fRecord.get()), pictList, SkSafeRef(fBBH.get()),
+ saveLayerData.release(), subPictureBytes);
+}
+
+void SkRecordedDrawable::flatten(SkWriteBuffer& buffer) const {
+ // Write the bounds.
+ buffer.writeRect(fBounds);
+
+ // Create an SkPictureRecord to record the draw commands.
+ SkPictInfo info;
+ SkPictureRecord pictureRecord(SkISize::Make(fBounds.width(), fBounds.height()), 0);
+
+ // If the query contains the whole picture, don't bother with the bounding box hierarchy.
+ SkRect clipBounds;
+ pictureRecord.getClipBounds(&clipBounds);
+ SkBBoxHierarchy* bbh;
+ if (clipBounds.contains(fBounds)) {
+ bbh = nullptr;
+ } else {
+ bbh = fBBH.get();
+ }
+
+ // Record the draw commands.
+ pictureRecord.beginRecording();
+ SkRecordDraw(*fRecord, &pictureRecord, nullptr, fDrawableList->begin(), fDrawableList->count(),
+ bbh, nullptr);
+ pictureRecord.endRecording();
+
+ // Flatten the recorded commands and drawables.
+ SkPictureData pictureData(pictureRecord, info, false);
+ pictureData.flatten(buffer);
+}
+
+sk_sp<SkFlattenable> SkRecordedDrawable::CreateProc(SkReadBuffer& buffer) {
+ // Read the bounds.
+ SkRect bounds;
+ buffer.readRect(&bounds);
+
+ // Unflatten into a SkPictureData.
+ SkPictInfo info;
+ info.fCullRect = bounds;
+ SkAutoTDelete<SkPictureData> pictureData(SkPictureData::CreateFromBuffer(buffer, info));
+ if (!pictureData) {
+ return nullptr;
+ }
+
+ // Create a drawable.
+ SkPicturePlayback playback(pictureData);
+ SkPictureRecorder recorder;
+ playback.draw(recorder.beginRecording(bounds), nullptr, &buffer);
+ return recorder.finishRecordingAsDrawable();
+}
diff --git a/src/core/SkRecordedDrawable.h b/src/core/SkRecordedDrawable.h
new file mode 100644
index 0000000000..e9973b4b81
--- /dev/null
+++ b/src/core/SkRecordedDrawable.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBBoxHierarchy.h"
+#include "SkDrawable.h"
+#include "SkRecord.h"
+#include "SkRecorder.h"
+
+class SkRecordedDrawable : public SkDrawable {
+public:
+ SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkDrawableList* drawableList,
+ const SkRect& bounds, bool doSaveLayerInfo)
+ : fRecord(SkRef(record))
+ , fBBH(SkSafeRef(bbh))
+ , fDrawableList(drawableList) // we take ownership
+ , fBounds(bounds)
+ , fDoSaveLayerInfo(doSaveLayerInfo)
+ {}
+
+ void flatten(SkWriteBuffer& buffer) const override;
+
+ static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer);
+
+ Factory getFactory() const override { return CreateProc; }
+
+protected:
+ SkRect onGetBounds() override { return fBounds; }
+
+ void onDraw(SkCanvas* canvas) override;
+
+ SkPicture* onNewPictureSnapshot() override;
+
+private:
+ SkAutoTUnref<SkRecord> fRecord;
+ SkAutoTUnref<SkBBoxHierarchy> fBBH;
+ SkAutoTDelete<SkDrawableList> fDrawableList;
+ const SkRect fBounds;
+ const bool fDoSaveLayerInfo;
+};
diff --git a/tests/FlattenDrawableTest.cpp b/tests/FlattenDrawableTest.cpp
index c7fff12326..2132729330 100644
--- a/tests/FlattenDrawableTest.cpp
+++ b/tests/FlattenDrawableTest.cpp
@@ -246,3 +246,42 @@ DEF_TEST(FlattenDrawable, r) {
REPORTER_ASSERT(r, 3 == integer->c());
REPORTER_ASSERT(r, 4 == integer->d());
}
+
+DEF_TEST(FlattenRecordedDrawable, r) {
+ // Record a set of canvas draw commands
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(1000.0f, 1000.0f);
+ canvas->drawPoint(42.0f, 17.0f, SK_ColorGREEN);
+ SkPaint paint;
+ paint.setColor(SK_ColorRED);
+ canvas->drawPaint(paint);
+ SkPaint textPaint;
+ textPaint.setColor(SK_ColorBLUE);
+ canvas->drawText("TEXT", 4, 467.0f, 100.0f, textPaint);
+
+ // Draw some drawables as well
+ SkAutoTUnref<SkDrawable> drawable(new IntDrawable(1, 2, 3, 4));
+ SkAutoTUnref<RootDrawable> root(new RootDrawable(5, 6, 7, 8, paint, 9, 10, 11, 12, drawable));
+ canvas->drawDrawable(root, 747.0f, 242.0f);
+ SkAutoTUnref<PaintDrawable> paintDrawable(new PaintDrawable(paint));
+ canvas->drawDrawable(paintDrawable, 500.0, 500.0f);
+ SkAutoTUnref<CompoundDrawable> comDrawable(new CompoundDrawable(13, 14, 15, 16, textPaint));
+ canvas->drawDrawable(comDrawable, 10.0f, 10.0f);
+
+ // Serialize the recorded drawable
+ sk_sp<SkDrawable> recordedDrawable = recorder.finishRecordingAsDrawable();
+ SkWriteBuffer writeBuffer;
+ writeBuffer.writeFlattenable(recordedDrawable.get());
+
+ // Copy the contents of the write buffer into a read buffer
+ sk_sp<SkData> data = SkData::MakeUninitialized(writeBuffer.bytesWritten());
+ writeBuffer.writeToMemory(data->writable_data());
+ SkReadBuffer readBuffer(data->data(), data->size());
+ register_test_drawables(readBuffer);
+
+ // Deserialize and verify the drawable
+ SkAutoTUnref<SkDrawable> out((SkDrawable*)
+ readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
+ REPORTER_ASSERT(r, out);
+ REPORTER_ASSERT(r, !strcmp("SkRecordedDrawable", out->getTypeName()));
+}