2016-04-25 13:40:26 +00:00
|
|
|
/*
|
|
|
|
* 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 "SkCanvas.h"
|
|
|
|
#include "SkDrawable.h"
|
|
|
|
#include "SkOnce.h"
|
|
|
|
#include "SkPictureRecorder.h"
|
|
|
|
#include "SkReadBuffer.h"
|
|
|
|
#include "SkRect.h"
|
|
|
|
#include "SkStream.h"
|
|
|
|
#include "SkWriteBuffer.h"
|
|
|
|
#include "Test.h"
|
|
|
|
|
|
|
|
class IntDrawable : public SkDrawable {
|
|
|
|
public:
|
|
|
|
IntDrawable(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
|
|
|
|
: fA(a)
|
|
|
|
, fB(b)
|
|
|
|
, fC(c)
|
|
|
|
, fD(d)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void flatten(SkWriteBuffer& buffer) const override {
|
|
|
|
buffer.writeUInt(fA);
|
|
|
|
buffer.writeUInt(fB);
|
|
|
|
buffer.writeUInt(fC);
|
|
|
|
buffer.writeUInt(fD);
|
|
|
|
}
|
|
|
|
|
|
|
|
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
|
|
|
|
uint32_t a = buffer.readUInt();
|
|
|
|
uint32_t b = buffer.readUInt();
|
|
|
|
uint32_t c = buffer.readUInt();
|
|
|
|
uint32_t d = buffer.readUInt();
|
|
|
|
return sk_sp<IntDrawable>(new IntDrawable(a, b, c, d));
|
|
|
|
}
|
|
|
|
|
|
|
|
Factory getFactory() const override { return CreateProc; }
|
|
|
|
|
|
|
|
uint32_t a() const { return fA; }
|
|
|
|
uint32_t b() const { return fB; }
|
|
|
|
uint32_t c() const { return fC; }
|
|
|
|
uint32_t d() const { return fD; }
|
|
|
|
|
|
|
|
const char* getTypeName() const override { return "IntDrawable"; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
SkRect onGetBounds() override { return SkRect::MakeEmpty(); }
|
|
|
|
void onDraw(SkCanvas*) override {}
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint32_t fA;
|
|
|
|
uint32_t fB;
|
|
|
|
uint32_t fC;
|
|
|
|
uint32_t fD;
|
|
|
|
};
|
|
|
|
|
|
|
|
class PaintDrawable : public SkDrawable {
|
|
|
|
public:
|
|
|
|
PaintDrawable(const SkPaint& paint)
|
|
|
|
: fPaint(paint)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void flatten(SkWriteBuffer& buffer) const override {
|
|
|
|
buffer.writePaint(fPaint);
|
|
|
|
}
|
|
|
|
|
|
|
|
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
|
|
|
|
SkPaint paint;
|
|
|
|
buffer.readPaint(&paint);
|
|
|
|
return sk_sp<PaintDrawable>(new PaintDrawable(paint));
|
|
|
|
}
|
|
|
|
|
|
|
|
Factory getFactory() const override { return CreateProc; }
|
|
|
|
|
|
|
|
const SkPaint& paint() const { return fPaint; }
|
|
|
|
|
2016-04-26 15:20:14 +00:00
|
|
|
const char* getTypeName() const override { return "PaintDrawable"; }
|
|
|
|
|
2016-04-25 13:40:26 +00:00
|
|
|
protected:
|
|
|
|
SkRect onGetBounds() override { return SkRect::MakeEmpty(); }
|
|
|
|
void onDraw(SkCanvas*) override {}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SkPaint fPaint;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CompoundDrawable : public SkDrawable {
|
|
|
|
public:
|
|
|
|
CompoundDrawable(uint32_t a, uint32_t b, uint32_t c, uint32_t d, const SkPaint& paint)
|
|
|
|
: fIntDrawable(new IntDrawable(a, b, c, d))
|
|
|
|
, fPaintDrawable(new PaintDrawable(paint))
|
|
|
|
{}
|
|
|
|
|
|
|
|
CompoundDrawable(IntDrawable* intDrawable, PaintDrawable* paintDrawable)
|
|
|
|
: fIntDrawable(SkRef(intDrawable))
|
|
|
|
, fPaintDrawable(SkRef(paintDrawable))
|
|
|
|
{}
|
|
|
|
|
|
|
|
void flatten(SkWriteBuffer& buffer) const override {
|
2016-11-04 15:49:42 +00:00
|
|
|
buffer.writeFlattenable(fIntDrawable.get());
|
|
|
|
buffer.writeFlattenable(fPaintDrawable.get());
|
2016-04-25 13:40:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkFlattenable> intDrawable(
|
2016-04-25 13:40:26 +00:00
|
|
|
buffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
|
|
|
|
SkASSERT(intDrawable);
|
|
|
|
SkASSERT(!strcmp("IntDrawable", intDrawable->getTypeName()));
|
|
|
|
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkFlattenable> paintDrawable(
|
2016-04-25 13:40:26 +00:00
|
|
|
buffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
|
|
|
|
SkASSERT(paintDrawable);
|
|
|
|
SkASSERT(!strcmp("PaintDrawable", paintDrawable->getTypeName()));
|
|
|
|
|
|
|
|
return sk_sp<CompoundDrawable>(new CompoundDrawable((IntDrawable*) intDrawable.get(),
|
|
|
|
(PaintDrawable*) paintDrawable.get()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Factory getFactory() const override { return CreateProc; }
|
|
|
|
|
2016-11-04 15:49:42 +00:00
|
|
|
IntDrawable* intDrawable() const { return fIntDrawable.get(); }
|
|
|
|
PaintDrawable* paintDrawable() const { return fPaintDrawable.get(); }
|
2016-04-25 13:40:26 +00:00
|
|
|
|
2016-04-26 15:20:14 +00:00
|
|
|
const char* getTypeName() const override { return "CompoundDrawable"; }
|
|
|
|
|
2016-04-25 13:40:26 +00:00
|
|
|
protected:
|
|
|
|
SkRect onGetBounds() override { return SkRect::MakeEmpty(); }
|
|
|
|
void onDraw(SkCanvas*) override {}
|
|
|
|
|
|
|
|
private:
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<IntDrawable> fIntDrawable;
|
|
|
|
sk_sp<PaintDrawable> fPaintDrawable;
|
2016-04-25 13:40:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class RootDrawable : public SkDrawable {
|
|
|
|
public:
|
|
|
|
RootDrawable(uint32_t a, uint32_t b, uint32_t c, uint32_t d, const SkPaint& paint,
|
|
|
|
uint32_t e, uint32_t f, uint32_t g, uint32_t h, SkDrawable* drawable)
|
|
|
|
: fCompoundDrawable(new CompoundDrawable(a, b, c, d, paint))
|
|
|
|
, fIntDrawable(new IntDrawable(e, f, g, h))
|
|
|
|
, fDrawable(SkRef(drawable))
|
|
|
|
{}
|
|
|
|
|
|
|
|
RootDrawable(CompoundDrawable* compoundDrawable, IntDrawable* intDrawable,
|
|
|
|
SkDrawable* drawable)
|
|
|
|
: fCompoundDrawable(SkRef(compoundDrawable))
|
|
|
|
, fIntDrawable(SkRef(intDrawable))
|
|
|
|
, fDrawable(SkRef(drawable))
|
|
|
|
{}
|
|
|
|
|
|
|
|
void flatten(SkWriteBuffer& buffer) const override {
|
2016-11-04 15:49:42 +00:00
|
|
|
buffer.writeFlattenable(fCompoundDrawable.get());
|
|
|
|
buffer.writeFlattenable(fIntDrawable.get());
|
|
|
|
buffer.writeFlattenable(fDrawable.get());
|
2016-04-25 13:40:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkFlattenable> compoundDrawable(
|
2016-04-25 13:40:26 +00:00
|
|
|
buffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
|
|
|
|
SkASSERT(compoundDrawable);
|
|
|
|
SkASSERT(!strcmp("CompoundDrawable", compoundDrawable->getTypeName()));
|
|
|
|
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkFlattenable> intDrawable(
|
2016-04-25 13:40:26 +00:00
|
|
|
buffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
|
|
|
|
SkASSERT(intDrawable);
|
|
|
|
SkASSERT(!strcmp("IntDrawable", intDrawable->getTypeName()));
|
|
|
|
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkFlattenable> drawable(
|
2016-04-25 13:40:26 +00:00
|
|
|
buffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
|
|
|
|
SkASSERT(drawable);
|
|
|
|
|
|
|
|
return sk_sp<RootDrawable>(new RootDrawable((CompoundDrawable*) compoundDrawable.get(),
|
|
|
|
(IntDrawable*) intDrawable.get(),
|
|
|
|
(SkDrawable*) drawable.get()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Factory getFactory() const override { return CreateProc; }
|
|
|
|
|
2016-11-04 15:49:42 +00:00
|
|
|
CompoundDrawable* compoundDrawable() const { return fCompoundDrawable.get(); }
|
|
|
|
IntDrawable* intDrawable() const { return fIntDrawable.get(); }
|
|
|
|
SkDrawable* drawable() const { return fDrawable.get(); }
|
2016-04-25 13:40:26 +00:00
|
|
|
|
2016-04-26 15:20:14 +00:00
|
|
|
const char* getTypeName() const override { return "RootDrawable"; }
|
|
|
|
|
2016-04-25 13:40:26 +00:00
|
|
|
protected:
|
|
|
|
SkRect onGetBounds() override { return SkRect::MakeEmpty(); }
|
|
|
|
void onDraw(SkCanvas*) override {}
|
|
|
|
|
|
|
|
private:
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<CompoundDrawable> fCompoundDrawable;
|
|
|
|
sk_sp<IntDrawable> fIntDrawable;
|
|
|
|
sk_sp<SkDrawable> fDrawable;
|
2016-04-25 13:40:26 +00:00
|
|
|
};
|
|
|
|
|
2016-04-26 15:20:14 +00:00
|
|
|
static void register_test_drawables(SkReadBuffer& buffer) {
|
|
|
|
buffer.setCustomFactory(SkString("IntDrawable"), IntDrawable::CreateProc);
|
|
|
|
buffer.setCustomFactory(SkString("PaintDrawable"), PaintDrawable::CreateProc);
|
|
|
|
buffer.setCustomFactory(SkString("CompoundDrawable"), CompoundDrawable::CreateProc);
|
|
|
|
buffer.setCustomFactory(SkString("RootDrawable"), RootDrawable::CreateProc);
|
2016-04-25 13:40:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(FlattenDrawable, r) {
|
|
|
|
// Create and serialize the test drawable
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkDrawable> drawable(new IntDrawable(1, 2, 3, 4));
|
2016-04-25 13:40:26 +00:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<RootDrawable> root(new RootDrawable(5, 6, 7, 8, paint, 9, 10, 11, 12, drawable.get()));
|
2016-05-04 18:06:28 +00:00
|
|
|
SkBinaryWriteBuffer writeBuffer;
|
2016-11-04 15:49:42 +00:00
|
|
|
writeBuffer.writeFlattenable(root.get());
|
2016-04-25 13:40:26 +00:00
|
|
|
|
|
|
|
// 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());
|
2016-04-26 15:20:14 +00:00
|
|
|
register_test_drawables(readBuffer);
|
2016-04-25 13:40:26 +00:00
|
|
|
|
|
|
|
// Deserialize and verify the drawable
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkDrawable> out((SkDrawable*)readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
|
2016-04-25 13:40:26 +00:00
|
|
|
REPORTER_ASSERT(r, out);
|
|
|
|
REPORTER_ASSERT(r, !strcmp("RootDrawable", out->getTypeName()));
|
|
|
|
|
|
|
|
RootDrawable* rootOut = (RootDrawable*) out.get();
|
|
|
|
REPORTER_ASSERT(r, 5 == rootOut->compoundDrawable()->intDrawable()->a());
|
|
|
|
REPORTER_ASSERT(r, 6 == rootOut->compoundDrawable()->intDrawable()->b());
|
|
|
|
REPORTER_ASSERT(r, 7 == rootOut->compoundDrawable()->intDrawable()->c());
|
|
|
|
REPORTER_ASSERT(r, 8 == rootOut->compoundDrawable()->intDrawable()->d());
|
|
|
|
REPORTER_ASSERT(r, SK_ColorBLUE ==
|
|
|
|
rootOut->compoundDrawable()->paintDrawable()->paint().getColor());
|
|
|
|
REPORTER_ASSERT(r, 9 == rootOut->intDrawable()->a());
|
|
|
|
REPORTER_ASSERT(r, 10 == rootOut->intDrawable()->b());
|
|
|
|
REPORTER_ASSERT(r, 11 == rootOut->intDrawable()->c());
|
|
|
|
REPORTER_ASSERT(r, 12 == rootOut->intDrawable()->d());
|
|
|
|
|
|
|
|
// Note that we can still recognize the generic drawable as an IntDrawable
|
|
|
|
SkDrawable* generic = rootOut->drawable();
|
|
|
|
REPORTER_ASSERT(r, !strcmp("IntDrawable", generic->getTypeName()));
|
|
|
|
IntDrawable* integer = (IntDrawable*) generic;
|
|
|
|
REPORTER_ASSERT(r, 1 == integer->a());
|
|
|
|
REPORTER_ASSERT(r, 2 == integer->b());
|
|
|
|
REPORTER_ASSERT(r, 3 == integer->c());
|
|
|
|
REPORTER_ASSERT(r, 4 == integer->d());
|
|
|
|
}
|
2016-04-27 20:51:20 +00:00
|
|
|
|
|
|
|
DEF_TEST(FlattenRecordedDrawable, r) {
|
|
|
|
// Record a set of canvas draw commands
|
|
|
|
SkPictureRecorder recorder;
|
|
|
|
SkCanvas* canvas = recorder.beginRecording(1000.0f, 1000.0f);
|
|
|
|
SkPaint paint;
|
2017-02-22 18:21:42 +00:00
|
|
|
paint.setColor(SK_ColorGREEN);
|
|
|
|
canvas->drawPoint(42.0f, 17.0f, paint);
|
2016-04-27 20:51:20 +00:00
|
|
|
paint.setColor(SK_ColorRED);
|
|
|
|
canvas->drawPaint(paint);
|
|
|
|
SkPaint textPaint;
|
|
|
|
textPaint.setColor(SK_ColorBLUE);
|
2017-04-28 19:35:12 +00:00
|
|
|
canvas->drawString("TEXT", 467.0f, 100.0f, textPaint);
|
2016-04-27 20:51:20 +00:00
|
|
|
|
|
|
|
// Draw some drawables as well
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkDrawable> drawable(new IntDrawable(1, 2, 3, 4));
|
|
|
|
sk_sp<RootDrawable> root(new RootDrawable(5, 6, 7, 8, paint, 9, 10, 11, 12, drawable.get()));
|
|
|
|
canvas->drawDrawable(root.get(), 747.0f, 242.0f);
|
|
|
|
sk_sp<PaintDrawable> paintDrawable(new PaintDrawable(paint));
|
|
|
|
canvas->drawDrawable(paintDrawable.get(), 500.0, 500.0f);
|
|
|
|
sk_sp<CompoundDrawable> comDrawable(new CompoundDrawable(13, 14, 15, 16, textPaint));
|
|
|
|
canvas->drawDrawable(comDrawable.get(), 10.0f, 10.0f);
|
2016-04-27 20:51:20 +00:00
|
|
|
|
|
|
|
// Serialize the recorded drawable
|
|
|
|
sk_sp<SkDrawable> recordedDrawable = recorder.finishRecordingAsDrawable();
|
2016-05-04 18:06:28 +00:00
|
|
|
SkBinaryWriteBuffer writeBuffer;
|
2016-04-27 20:51:20 +00:00
|
|
|
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
|
2016-11-04 15:49:42 +00:00
|
|
|
sk_sp<SkDrawable> out((SkDrawable*)readBuffer.readFlattenable(SkFlattenable::kSkDrawable_Type));
|
2016-04-27 20:51:20 +00:00
|
|
|
REPORTER_ASSERT(r, out);
|
|
|
|
REPORTER_ASSERT(r, !strcmp("SkRecordedDrawable", out->getTypeName()));
|
|
|
|
}
|
2018-01-23 20:29:32 +00:00
|
|
|
|
|
|
|
// be sure these constructs compile, don't assert, and return null
|
|
|
|
DEF_TEST(Flattenable_EmptyDeserialze, reporter) {
|
|
|
|
auto data = SkData::MakeEmpty();
|
|
|
|
|
|
|
|
#define test(name) REPORTER_ASSERT(reporter, !name::Deserialize(data->data(), data->size()))
|
|
|
|
test(SkPathEffect);
|
|
|
|
test(SkMaskFilter);
|
|
|
|
test(SkShaderBase); // todo: make this just be shader!
|
|
|
|
test(SkColorFilter);
|
|
|
|
test(SkImageFilter);
|
|
|
|
test(SkDrawLooper);
|
|
|
|
#undef test
|
|
|
|
}
|
|
|
|
|