msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 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" |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 10 | #include "SkPictureRecorder.h" |
| 11 | #include "SkReadBuffer.h" |
| 12 | #include "SkRect.h" |
| 13 | #include "SkStream.h" |
| 14 | #include "SkWriteBuffer.h" |
| 15 | #include "Test.h" |
| 16 | |
| 17 | class IntDrawable : public SkDrawable { |
| 18 | public: |
| 19 | IntDrawable(uint32_t a, uint32_t b, uint32_t c, uint32_t d) |
| 20 | : fA(a) |
| 21 | , fB(b) |
| 22 | , fC(c) |
| 23 | , fD(d) |
| 24 | {} |
| 25 | |
| 26 | void flatten(SkWriteBuffer& buffer) const override { |
| 27 | buffer.writeUInt(fA); |
| 28 | buffer.writeUInt(fB); |
| 29 | buffer.writeUInt(fC); |
| 30 | buffer.writeUInt(fD); |
| 31 | } |
| 32 | |
| 33 | static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { |
| 34 | uint32_t a = buffer.readUInt(); |
| 35 | uint32_t b = buffer.readUInt(); |
| 36 | uint32_t c = buffer.readUInt(); |
| 37 | uint32_t d = buffer.readUInt(); |
| 38 | return sk_sp<IntDrawable>(new IntDrawable(a, b, c, d)); |
| 39 | } |
| 40 | |
| 41 | Factory getFactory() const override { return CreateProc; } |
| 42 | |
| 43 | uint32_t a() const { return fA; } |
| 44 | uint32_t b() const { return fB; } |
| 45 | uint32_t c() const { return fC; } |
| 46 | uint32_t d() const { return fD; } |
| 47 | |
| 48 | const char* getTypeName() const override { return "IntDrawable"; } |
| 49 | |
| 50 | protected: |
| 51 | SkRect onGetBounds() override { return SkRect::MakeEmpty(); } |
| 52 | void onDraw(SkCanvas*) override {} |
| 53 | |
| 54 | private: |
| 55 | uint32_t fA; |
| 56 | uint32_t fB; |
| 57 | uint32_t fC; |
| 58 | uint32_t fD; |
| 59 | }; |
| 60 | |
| 61 | class PaintDrawable : public SkDrawable { |
| 62 | public: |
| 63 | PaintDrawable(const SkPaint& paint) |
| 64 | : fPaint(paint) |
| 65 | {} |
| 66 | |
| 67 | void flatten(SkWriteBuffer& buffer) const override { |
| 68 | buffer.writePaint(fPaint); |
| 69 | } |
| 70 | |
| 71 | static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { |
| 72 | SkPaint paint; |
| 73 | buffer.readPaint(&paint); |
| 74 | return sk_sp<PaintDrawable>(new PaintDrawable(paint)); |
| 75 | } |
| 76 | |
| 77 | Factory getFactory() const override { return CreateProc; } |
| 78 | |
| 79 | const SkPaint& paint() const { return fPaint; } |
| 80 | |
msarett | 002c92b | 2016-04-26 08:20:14 -0700 | [diff] [blame] | 81 | const char* getTypeName() const override { return "PaintDrawable"; } |
| 82 | |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 83 | protected: |
| 84 | SkRect onGetBounds() override { return SkRect::MakeEmpty(); } |
| 85 | void onDraw(SkCanvas*) override {} |
| 86 | |
| 87 | private: |
| 88 | SkPaint fPaint; |
| 89 | }; |
| 90 | |
| 91 | class CompoundDrawable : public SkDrawable { |
| 92 | public: |
| 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 { |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 104 | buffer.writeFlattenable(fIntDrawable.get()); |
| 105 | buffer.writeFlattenable(fPaintDrawable.get()); |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 109 | sk_sp<SkFlattenable> intDrawable( |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 110 | buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); |
| 111 | SkASSERT(intDrawable); |
| 112 | SkASSERT(!strcmp("IntDrawable", intDrawable->getTypeName())); |
| 113 | |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 114 | sk_sp<SkFlattenable> paintDrawable( |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 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 | |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 125 | IntDrawable* intDrawable() const { return fIntDrawable.get(); } |
| 126 | PaintDrawable* paintDrawable() const { return fPaintDrawable.get(); } |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 127 | |
msarett | 002c92b | 2016-04-26 08:20:14 -0700 | [diff] [blame] | 128 | const char* getTypeName() const override { return "CompoundDrawable"; } |
| 129 | |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 130 | protected: |
| 131 | SkRect onGetBounds() override { return SkRect::MakeEmpty(); } |
| 132 | void onDraw(SkCanvas*) override {} |
| 133 | |
| 134 | private: |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 135 | sk_sp<IntDrawable> fIntDrawable; |
| 136 | sk_sp<PaintDrawable> fPaintDrawable; |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 137 | }; |
| 138 | |
| 139 | class RootDrawable : public SkDrawable { |
| 140 | public: |
| 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 { |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 156 | buffer.writeFlattenable(fCompoundDrawable.get()); |
| 157 | buffer.writeFlattenable(fIntDrawable.get()); |
| 158 | buffer.writeFlattenable(fDrawable.get()); |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 162 | sk_sp<SkFlattenable> compoundDrawable( |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 163 | buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); |
| 164 | SkASSERT(compoundDrawable); |
| 165 | SkASSERT(!strcmp("CompoundDrawable", compoundDrawable->getTypeName())); |
| 166 | |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 167 | sk_sp<SkFlattenable> intDrawable( |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 168 | buffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); |
| 169 | SkASSERT(intDrawable); |
| 170 | SkASSERT(!strcmp("IntDrawable", intDrawable->getTypeName())); |
| 171 | |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 172 | sk_sp<SkFlattenable> drawable( |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 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 | |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 183 | CompoundDrawable* compoundDrawable() const { return fCompoundDrawable.get(); } |
| 184 | IntDrawable* intDrawable() const { return fIntDrawable.get(); } |
| 185 | SkDrawable* drawable() const { return fDrawable.get(); } |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 186 | |
msarett | 002c92b | 2016-04-26 08:20:14 -0700 | [diff] [blame] | 187 | const char* getTypeName() const override { return "RootDrawable"; } |
| 188 | |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 189 | protected: |
| 190 | SkRect onGetBounds() override { return SkRect::MakeEmpty(); } |
| 191 | void onDraw(SkCanvas*) override {} |
| 192 | |
| 193 | private: |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 194 | sk_sp<CompoundDrawable> fCompoundDrawable; |
| 195 | sk_sp<IntDrawable> fIntDrawable; |
| 196 | sk_sp<SkDrawable> fDrawable; |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 197 | }; |
| 198 | |
Mike Klein | 4c683fc | 2018-10-19 17:35:02 -0400 | [diff] [blame] | 199 | // Register these drawables for deserialization some time before main(). |
| 200 | static struct Initializer { |
| 201 | Initializer() { |
Brian Salomon | 2335644 | 2018-11-30 15:33:19 -0500 | [diff] [blame] | 202 | SK_REGISTER_FLATTENABLE(IntDrawable); |
| 203 | SK_REGISTER_FLATTENABLE(PaintDrawable); |
| 204 | SK_REGISTER_FLATTENABLE(CompoundDrawable); |
| 205 | SK_REGISTER_FLATTENABLE(RootDrawable); |
Mike Klein | 4c683fc | 2018-10-19 17:35:02 -0400 | [diff] [blame] | 206 | } |
| 207 | } initializer; |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 208 | |
| 209 | DEF_TEST(FlattenDrawable, r) { |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 210 | // Create and serialize the test drawable |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 211 | sk_sp<SkDrawable> drawable(new IntDrawable(1, 2, 3, 4)); |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 212 | SkPaint paint; |
| 213 | paint.setColor(SK_ColorBLUE); |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 214 | sk_sp<RootDrawable> root(new RootDrawable(5, 6, 7, 8, paint, 9, 10, 11, 12, drawable.get())); |
brianosman | fad9856 | 2016-05-04 11:06:28 -0700 | [diff] [blame] | 215 | SkBinaryWriteBuffer writeBuffer; |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 216 | writeBuffer.writeFlattenable(root.get()); |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 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 |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 224 | sk_sp<SkDrawable> out((SkDrawable*)readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); |
msarett | edf7fcd | 2016-04-25 06:40:26 -0700 | [diff] [blame] | 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 | } |
msarett | 95416f4 | 2016-04-27 13:51:20 -0700 | [diff] [blame] | 249 | |
| 250 | DEF_TEST(FlattenRecordedDrawable, r) { |
| 251 | // Record a set of canvas draw commands |
| 252 | SkPictureRecorder recorder; |
| 253 | SkCanvas* canvas = recorder.beginRecording(1000.0f, 1000.0f); |
msarett | 95416f4 | 2016-04-27 13:51:20 -0700 | [diff] [blame] | 254 | SkPaint paint; |
Mike Reed | 3661bc9 | 2017-02-22 13:21:42 -0500 | [diff] [blame] | 255 | paint.setColor(SK_ColorGREEN); |
| 256 | canvas->drawPoint(42.0f, 17.0f, paint); |
msarett | 95416f4 | 2016-04-27 13:51:20 -0700 | [diff] [blame] | 257 | paint.setColor(SK_ColorRED); |
| 258 | canvas->drawPaint(paint); |
| 259 | SkPaint textPaint; |
| 260 | textPaint.setColor(SK_ColorBLUE); |
Cary Clark | 2a475ea | 2017-04-28 15:35:12 -0400 | [diff] [blame] | 261 | canvas->drawString("TEXT", 467.0f, 100.0f, textPaint); |
msarett | 95416f4 | 2016-04-27 13:51:20 -0700 | [diff] [blame] | 262 | |
| 263 | // Draw some drawables as well |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 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); |
msarett | 95416f4 | 2016-04-27 13:51:20 -0700 | [diff] [blame] | 271 | |
| 272 | // Serialize the recorded drawable |
| 273 | sk_sp<SkDrawable> recordedDrawable = recorder.finishRecordingAsDrawable(); |
brianosman | fad9856 | 2016-05-04 11:06:28 -0700 | [diff] [blame] | 274 | SkBinaryWriteBuffer writeBuffer; |
msarett | 95416f4 | 2016-04-27 13:51:20 -0700 | [diff] [blame] | 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()); |
msarett | 95416f4 | 2016-04-27 13:51:20 -0700 | [diff] [blame] | 281 | |
| 282 | // Deserialize and verify the drawable |
Hal Canary | 342b7ac | 2016-11-04 11:49:42 -0400 | [diff] [blame] | 283 | sk_sp<SkDrawable> out((SkDrawable*)readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type)); |
msarett | 95416f4 | 2016-04-27 13:51:20 -0700 | [diff] [blame] | 284 | REPORTER_ASSERT(r, out); |
| 285 | REPORTER_ASSERT(r, !strcmp("SkRecordedDrawable", out->getTypeName())); |
| 286 | } |
Mike Reed | 80747ef | 2018-01-23 15:29:32 -0500 | [diff] [blame] | 287 | |
| 288 | // be sure these constructs compile, don't assert, and return null |
| 289 | DEF_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(SkPathEffect); |
| 294 | test(SkMaskFilter); |
| 295 | test(SkShaderBase); // todo: make this just be shader! |
| 296 | test(SkColorFilter); |
| 297 | test(SkImageFilter); |
| 298 | test(SkDrawLooper); |
| 299 | #undef test |
| 300 | } |
| 301 | |