1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkCanvas.h" 9 #include "SkDrawable.h" 10 #include "SkOnce.h" 11 #include "SkPictureRecorder.h" 12 #include "SkReadBuffer.h" 13 #include "SkRect.h" 14 #include "SkStream.h" 15 #include "SkWriteBuffer.h" 16 #include "Test.h" 17 18 class IntDrawable : public SkDrawable { 19 public: 20 IntDrawable(uint32_t a, uint32_t b, uint32_t c, uint32_t d) 21 : fA(a) 22 , fB(b) 23 , fC(c) 24 , fD(d) 25 {} 26 27 void flatten(SkWriteBuffer& buffer) const override { 28 buffer.writeUInt(fA); 29 buffer.writeUInt(fB); 30 buffer.writeUInt(fC); 31 buffer.writeUInt(fD); 32 } 33 34 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { 35 uint32_t a = buffer.readUInt(); 36 uint32_t b = buffer.readUInt(); 37 uint32_t c = buffer.readUInt(); 38 uint32_t d = buffer.readUInt(); 39 return sk_sp<IntDrawable>(new IntDrawable(a, b, c, d)); 40 } 41 42 Factory getFactory() const override { return CreateProc; } 43 44 uint32_t a() const { return fA; } 45 uint32_t b() const { return fB; } 46 uint32_t c() const { return fC; } 47 uint32_t d() const { return fD; } 48 49 const char* getTypeName() const override { return "IntDrawable"; } 50 51 protected: 52 SkRect onGetBounds() override { return SkRect::MakeEmpty(); } 53 void onDraw(SkCanvas*) override {} 54 55 private: 56 uint32_t fA; 57 uint32_t fB; 58 uint32_t fC; 59 uint32_t fD; 60 }; 61 62 class PaintDrawable : public SkDrawable { 63 public: 64 PaintDrawable(const SkPaint& paint) 65 : fPaint(paint) 66 {} 67 68 void flatten(SkWriteBuffer& buffer) const override { 69 buffer.writePaint(fPaint); 70 } 71 72 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { 73 SkPaint paint; 74 buffer.readPaint(&paint); 75 return sk_sp<PaintDrawable>(new PaintDrawable(paint)); 76 } 77 78 Factory getFactory() const override { return CreateProc; } 79 80 const SkPaint& paint() const { return fPaint; } 81 82 const char* getTypeName() const override { return "PaintDrawable"; } 83 84 protected: 85 SkRect onGetBounds() override { return SkRect::MakeEmpty(); } 86 void onDraw(SkCanvas*) override {} 87 88 private: 89 SkPaint fPaint; 90 }; 91 92 class CompoundDrawable : public SkDrawable { 93 public: 94 CompoundDrawable(uint32_t a, uint32_t b, uint32_t c, uint32_t d, const SkPaint& paint) 95 : fIntDrawable(new IntDrawable(a, b, c, d)) 96 , fPaintDrawable(new PaintDrawable(paint)) 97 {} 98 99 CompoundDrawable(IntDrawable* intDrawable, PaintDrawable* paintDrawable) 100 : fIntDrawable(SkRef(intDrawable)) 101 , fPaintDrawable(SkRef(paintDrawable)) 102 {} 103 104 void flatten(SkWriteBuffer& buffer) const override { 105 buffer.writeFlattenable(fIntDrawable.get()); 106 buffer.writeFlattenable(fPaintDrawable.get()); 107 } 108 109 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { 110 sk_sp<SkFlattenable> intDrawable( 111 buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); 112 SkASSERT(intDrawable); 113 SkASSERT(!strcmp("IntDrawable", intDrawable->getTypeName())); 114 115 sk_sp<SkFlattenable> paintDrawable( 116 buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); 117 SkASSERT(paintDrawable); 118 SkASSERT(!strcmp("PaintDrawable", paintDrawable->getTypeName())); 119 120 return sk_sp<CompoundDrawable>(new CompoundDrawable((IntDrawable*) intDrawable.get(), 121 (PaintDrawable*) paintDrawable.get())); 122 } 123 124 Factory getFactory() const override { return CreateProc; } 125 126 IntDrawable* intDrawable() const { return fIntDrawable.get(); } 127 PaintDrawable* paintDrawable() const { return fPaintDrawable.get(); } 128 129 const char* getTypeName() const override { return "CompoundDrawable"; } 130 131 protected: 132 SkRect onGetBounds() override { return SkRect::MakeEmpty(); } 133 void onDraw(SkCanvas*) override {} 134 135 private: 136 sk_sp<IntDrawable> fIntDrawable; 137 sk_sp<PaintDrawable> fPaintDrawable; 138 }; 139 140 class RootDrawable : public SkDrawable { 141 public: 142 RootDrawable(uint32_t a, uint32_t b, uint32_t c, uint32_t d, const SkPaint& paint, 143 uint32_t e, uint32_t f, uint32_t g, uint32_t h, SkDrawable* drawable) 144 : fCompoundDrawable(new CompoundDrawable(a, b, c, d, paint)) 145 , fIntDrawable(new IntDrawable(e, f, g, h)) 146 , fDrawable(SkRef(drawable)) 147 {} 148 149 RootDrawable(CompoundDrawable* compoundDrawable, IntDrawable* intDrawable, 150 SkDrawable* drawable) 151 : fCompoundDrawable(SkRef(compoundDrawable)) 152 , fIntDrawable(SkRef(intDrawable)) 153 , fDrawable(SkRef(drawable)) 154 {} 155 156 void flatten(SkWriteBuffer& buffer) const override { 157 buffer.writeFlattenable(fCompoundDrawable.get()); 158 buffer.writeFlattenable(fIntDrawable.get()); 159 buffer.writeFlattenable(fDrawable.get()); 160 } 161 162 static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { 163 sk_sp<SkFlattenable> compoundDrawable( 164 buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); 165 SkASSERT(compoundDrawable); 166 SkASSERT(!strcmp("CompoundDrawable", compoundDrawable->getTypeName())); 167 168 sk_sp<SkFlattenable> intDrawable( 169 buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); 170 SkASSERT(intDrawable); 171 SkASSERT(!strcmp("IntDrawable", intDrawable->getTypeName())); 172 173 sk_sp<SkFlattenable> drawable( 174 buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); 175 SkASSERT(drawable); 176 177 return sk_sp<RootDrawable>(new RootDrawable((CompoundDrawable*) compoundDrawable.get(), 178 (IntDrawable*) intDrawable.get(), 179 (SkDrawable*) drawable.get())); 180 } 181 182 Factory getFactory() const override { return CreateProc; } 183 184 CompoundDrawable* compoundDrawable() const { return fCompoundDrawable.get(); } 185 IntDrawable* intDrawable() const { return fIntDrawable.get(); } 186 SkDrawable* drawable() const { return fDrawable.get(); } 187 188 const char* getTypeName() const override { return "RootDrawable"; } 189 190 protected: 191 SkRect onGetBounds() override { return SkRect::MakeEmpty(); } 192 void onDraw(SkCanvas*) override {} 193 194 private: 195 sk_sp<CompoundDrawable> fCompoundDrawable; 196 sk_sp<IntDrawable> fIntDrawable; 197 sk_sp<SkDrawable> fDrawable; 198 }; 199 200 static void register_test_drawables(SkReadBuffer& buffer) { 201 buffer.setCustomFactory(SkString("IntDrawable"), IntDrawable::CreateProc); 202 buffer.setCustomFactory(SkString("PaintDrawable"), PaintDrawable::CreateProc); 203 buffer.setCustomFactory(SkString("CompoundDrawable"), CompoundDrawable::CreateProc); 204 buffer.setCustomFactory(SkString("RootDrawable"), RootDrawable::CreateProc); 205 } 206 207 DEF_TEST(FlattenDrawable, r) { 208 // Create and serialize the test drawable 209 sk_sp<SkDrawable> drawable(new IntDrawable(1, 2, 3, 4)); 210 SkPaint paint; 211 paint.setColor(SK_ColorBLUE); 212 sk_sp<RootDrawable> root(new RootDrawable(5, 6, 7, 8, paint, 9, 10, 11, 12, drawable.get())); 213 SkBinaryWriteBuffer writeBuffer; 214 writeBuffer.writeFlattenable(root.get()); 215 216 // Copy the contents of the write buffer into a read buffer 217 sk_sp<SkData> data = SkData::MakeUninitialized(writeBuffer.bytesWritten()); 218 writeBuffer.writeToMemory(data->writable_data()); 219 SkReadBuffer readBuffer(data->data(), data->size()); 220 register_test_drawables(readBuffer); 221 222 // Deserialize and verify the drawable 223 sk_sp<SkDrawable> out((SkDrawable*)readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); 224 REPORTER_ASSERT(r, out); 225 REPORTER_ASSERT(r, !strcmp("RootDrawable", out->getTypeName())); 226 227 RootDrawable* rootOut = (RootDrawable*) out.get(); 228 REPORTER_ASSERT(r, 5 == rootOut->compoundDrawable()->intDrawable()->a()); 229 REPORTER_ASSERT(r, 6 == rootOut->compoundDrawable()->intDrawable()->b()); 230 REPORTER_ASSERT(r, 7 == rootOut->compoundDrawable()->intDrawable()->c()); 231 REPORTER_ASSERT(r, 8 == rootOut->compoundDrawable()->intDrawable()->d()); 232 REPORTER_ASSERT(r, SK_ColorBLUE == 233 rootOut->compoundDrawable()->paintDrawable()->paint().getColor()); 234 REPORTER_ASSERT(r, 9 == rootOut->intDrawable()->a()); 235 REPORTER_ASSERT(r, 10 == rootOut->intDrawable()->b()); 236 REPORTER_ASSERT(r, 11 == rootOut->intDrawable()->c()); 237 REPORTER_ASSERT(r, 12 == rootOut->intDrawable()->d()); 238 239 // Note that we can still recognize the generic drawable as an IntDrawable 240 SkDrawable* generic = rootOut->drawable(); 241 REPORTER_ASSERT(r, !strcmp("IntDrawable", generic->getTypeName())); 242 IntDrawable* integer = (IntDrawable*) generic; 243 REPORTER_ASSERT(r, 1 == integer->a()); 244 REPORTER_ASSERT(r, 2 == integer->b()); 245 REPORTER_ASSERT(r, 3 == integer->c()); 246 REPORTER_ASSERT(r, 4 == integer->d()); 247 } 248 249 DEF_TEST(FlattenRecordedDrawable, r) { 250 // Record a set of canvas draw commands 251 SkPictureRecorder recorder; 252 SkCanvas* canvas = recorder.beginRecording(1000.0f, 1000.0f); 253 SkPaint paint; 254 paint.setColor(SK_ColorGREEN); 255 canvas->drawPoint(42.0f, 17.0f, paint); 256 paint.setColor(SK_ColorRED); 257 canvas->drawPaint(paint); 258 SkPaint textPaint; 259 textPaint.setColor(SK_ColorBLUE); 260 canvas->drawString("TEXT", 467.0f, 100.0f, textPaint); 261 262 // Draw some drawables as well 263 sk_sp<SkDrawable> drawable(new IntDrawable(1, 2, 3, 4)); 264 sk_sp<RootDrawable> root(new RootDrawable(5, 6, 7, 8, paint, 9, 10, 11, 12, drawable.get())); 265 canvas->drawDrawable(root.get(), 747.0f, 242.0f); 266 sk_sp<PaintDrawable> paintDrawable(new PaintDrawable(paint)); 267 canvas->drawDrawable(paintDrawable.get(), 500.0, 500.0f); 268 sk_sp<CompoundDrawable> comDrawable(new CompoundDrawable(13, 14, 15, 16, textPaint)); 269 canvas->drawDrawable(comDrawable.get(), 10.0f, 10.0f); 270 271 // Serialize the recorded drawable 272 sk_sp<SkDrawable> recordedDrawable = recorder.finishRecordingAsDrawable(); 273 SkBinaryWriteBuffer writeBuffer; 274 writeBuffer.writeFlattenable(recordedDrawable.get()); 275 276 // Copy the contents of the write buffer into a read buffer 277 sk_sp<SkData> data = SkData::MakeUninitialized(writeBuffer.bytesWritten()); 278 writeBuffer.writeToMemory(data->writable_data()); 279 SkReadBuffer readBuffer(data->data(), data->size()); 280 register_test_drawables(readBuffer); 281 282 // Deserialize and verify the drawable 283 sk_sp<SkDrawable> out((SkDrawable*)readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); 284 REPORTER_ASSERT(r, out); 285 REPORTER_ASSERT(r, !strcmp("SkRecordedDrawable", out->getTypeName())); 286 } 287