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