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