SkRemote: more refactoring
- move Client / Server definitions to .cpp - rename Client / Server to Canvas / Decoder No diffs: https://gold.skia.org/search2?issue=1409113005&unt=true&query=source_type%3Dgm&master=false&include=true BUG=skia: Review URL: https://codereview.chromium.org/1409113005
This commit is contained in:
parent
e71000f0df
commit
479fe776a0
@ -1162,13 +1162,12 @@ Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkStrin
|
||||
}
|
||||
|
||||
Error ViaRemote::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
|
||||
return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
|
||||
SkRemote::Server server(canvas);
|
||||
SkAutoTDelete<SkRemote::Encoder> cache(fCache
|
||||
? SkRemote::Encoder::CreateCachingEncoder(&server)
|
||||
: nullptr);
|
||||
SkRemote::Client client(cache.get() ? cache.get() : &server);
|
||||
return src.draw(&client);
|
||||
return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* target) {
|
||||
SkAutoTDelete<SkRemote::Encoder> decoder(SkRemote::NewDecoder(target));
|
||||
SkAutoTDelete<SkRemote::Encoder> cache(fCache ? SkRemote::NewCachingEncoder(decoder)
|
||||
: nullptr);
|
||||
SkAutoTDelete<SkCanvas> canvas(SkRemote::NewCanvas(cache ? cache : decoder));
|
||||
return src.draw(canvas);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,12 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkRemote.h"
|
||||
#include "SkShader.h"
|
||||
#include "SkTHash.h"
|
||||
|
||||
namespace SkRemote {
|
||||
|
||||
@ -72,6 +75,278 @@ namespace SkRemote {
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
|
||||
class Canvas final : public SkCanvas {
|
||||
public:
|
||||
explicit Canvas(Encoder* encoder)
|
||||
: SkCanvas(1,1)
|
||||
, fEncoder(encoder) {}
|
||||
|
||||
private:
|
||||
// Calls Encoder::define() when created, Encoder::undefine() when destroyed.
|
||||
class AutoID : ::SkNoncopyable {
|
||||
public:
|
||||
template <typename T>
|
||||
explicit AutoID(Encoder* encoder, const T& val)
|
||||
: fEncoder(encoder)
|
||||
, fID(encoder->define(val)) {}
|
||||
~AutoID() { if (fEncoder) fEncoder->undefine(fID); }
|
||||
|
||||
AutoID(AutoID&& o) : fEncoder(o.fEncoder), fID(o.fID) {
|
||||
o.fEncoder = nullptr;
|
||||
}
|
||||
AutoID& operator=(AutoID&&) = delete;
|
||||
|
||||
operator ID () const { return fID; }
|
||||
|
||||
private:
|
||||
Encoder* fEncoder;
|
||||
const ID fID;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
AutoID id(const T& val) { return AutoID(fEncoder, val); }
|
||||
|
||||
void willSave() override { fEncoder-> save(); }
|
||||
void didRestore() override { fEncoder->restore(); }
|
||||
|
||||
void didConcat(const SkMatrix&) override { this->didSetMatrix(this->getTotalMatrix()); }
|
||||
void didSetMatrix(const SkMatrix& matrix) override {
|
||||
fEncoder->setMatrix(this->id(matrix));
|
||||
}
|
||||
|
||||
void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
|
||||
SkPath path;
|
||||
path.addOval(oval);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
|
||||
SkPath path;
|
||||
path.addRect(rect);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
|
||||
SkPath path;
|
||||
path.addRRect(rrect);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void onDrawDRRect(const SkRRect& outside, const SkRRect& inside,
|
||||
const SkPaint& paint) override {
|
||||
SkPath path;
|
||||
path.addRRect(outside);
|
||||
path.addRRect(inside, SkPath::kCCW_Direction);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void onDrawPath(const SkPath& path, const SkPaint& paint) override {
|
||||
auto p = this->id(path),
|
||||
m = this->id(Misc::CreateFrom(paint)),
|
||||
s = this->id(paint.getShader()),
|
||||
x = this->id(paint.getXfermode());
|
||||
|
||||
if (paint.getStyle() == SkPaint::kFill_Style) {
|
||||
fEncoder->fillPath(p, m, s, x);
|
||||
} else {
|
||||
// TODO: handle kStrokeAndFill_Style
|
||||
fEncoder->strokePath(p, m, s, x, this->id(Stroke::CreateFrom(paint)));
|
||||
}
|
||||
}
|
||||
|
||||
void onDrawPaint(const SkPaint& paint) override {
|
||||
SkPath path;
|
||||
path.setFillType(SkPath::kInverseWinding_FillType); // Either inverse FillType is fine.
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void onDrawText(const void* text, size_t byteLength,
|
||||
SkScalar x, SkScalar y, const SkPaint& paint) override {
|
||||
// Text-as-paths is a temporary hack.
|
||||
// TODO: send SkTextBlobs and SkTypefaces
|
||||
SkPath path;
|
||||
paint.getTextPath(text, byteLength, x, y, &path);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void onDrawPosText(const void* text, size_t byteLength,
|
||||
const SkPoint pos[], const SkPaint& paint) override {
|
||||
// Text-as-paths is a temporary hack.
|
||||
// TODO: send SkTextBlobs and SkTypefaces
|
||||
SkPath path;
|
||||
paint.getPosTextPath(text, byteLength, pos, &path);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void onDrawPosTextH(const void* text, size_t byteLength,
|
||||
const SkScalar xpos[], SkScalar constY, const SkPaint& paint) override {
|
||||
size_t length = paint.countText(text, byteLength);
|
||||
SkAutoTArray<SkPoint> pos(length);
|
||||
for(size_t i = 0; i < length; ++i) {
|
||||
pos[i].set(xpos[i], constY);
|
||||
}
|
||||
this->onDrawPosText(text, byteLength, &pos[0], paint);
|
||||
}
|
||||
|
||||
void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override {
|
||||
SkPath path;
|
||||
path.addRect(rect);
|
||||
this->onClipPath(path, op, edgeStyle);
|
||||
}
|
||||
|
||||
void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override {
|
||||
SkPath path;
|
||||
path.addRRect(rrect);
|
||||
this->onClipPath(path, op, edgeStyle);
|
||||
}
|
||||
|
||||
void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) override {
|
||||
fEncoder->clipPath(this->id(path), op, edgeStyle == kSoft_ClipEdgeStyle);
|
||||
}
|
||||
|
||||
Encoder* fEncoder;
|
||||
};
|
||||
|
||||
SkCanvas* NewCanvas(Encoder* encoder) { return new Canvas(encoder); }
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
|
||||
class Decoder final : public Encoder {
|
||||
public:
|
||||
explicit Decoder(SkCanvas* canvas) : fCanvas(canvas) {}
|
||||
|
||||
private:
|
||||
template <typename Map, typename T>
|
||||
ID define(Type type, Map* map, const T& val) {
|
||||
ID id(type, fNextID++);
|
||||
map->set(id, val);
|
||||
return id;
|
||||
}
|
||||
|
||||
ID define(const SkMatrix& v) override {return this->define(Type::kMatrix, &fMatrix, v);}
|
||||
ID define(const Misc& v) override {return this->define(Type::kMisc, &fMisc, v);}
|
||||
ID define(const SkPath& v) override {return this->define(Type::kPath, &fPath, v);}
|
||||
ID define(const Stroke& v) override {return this->define(Type::kStroke, &fStroke, v);}
|
||||
ID define(SkShader* v) override {return this->define(Type::kShader, &fShader, v);}
|
||||
ID define(SkXfermode* v) override {return this->define(Type::kXfermode, &fXfermode, v);}
|
||||
|
||||
void undefine(ID id) override {
|
||||
switch(id.type()) {
|
||||
case Type::kMatrix: return fMatrix .remove(id);
|
||||
case Type::kMisc: return fMisc .remove(id);
|
||||
case Type::kPath: return fPath .remove(id);
|
||||
case Type::kStroke: return fStroke .remove(id);
|
||||
case Type::kShader: return fShader .remove(id);
|
||||
case Type::kXfermode: return fXfermode.remove(id);
|
||||
};
|
||||
}
|
||||
|
||||
void save() override { fCanvas->save(); }
|
||||
void restore() override { fCanvas->restore(); }
|
||||
|
||||
void setMatrix(ID matrix) override { fCanvas->setMatrix(fMatrix.find(matrix)); }
|
||||
|
||||
void clipPath(ID path, SkRegion::Op op, bool aa) override {
|
||||
fCanvas->clipPath(fPath.find(path), op, aa);
|
||||
}
|
||||
void fillPath(ID path, ID misc, ID shader, ID xfermode) override {
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
fMisc.find(misc).applyTo(&paint);
|
||||
paint.setShader (fShader .find(shader));
|
||||
paint.setXfermode(fXfermode.find(xfermode));
|
||||
fCanvas->drawPath(fPath.find(path), paint);
|
||||
}
|
||||
void strokePath(ID path, ID misc, ID shader, ID xfermode, ID stroke) override {
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
fMisc .find(misc ).applyTo(&paint);
|
||||
fStroke.find(stroke).applyTo(&paint);
|
||||
paint.setShader (fShader .find(shader));
|
||||
paint.setXfermode(fXfermode.find(xfermode));
|
||||
fCanvas->drawPath(fPath.find(path), paint);
|
||||
}
|
||||
|
||||
// Maps ID -> T.
|
||||
template <typename T, Type kType>
|
||||
class IDMap {
|
||||
public:
|
||||
~IDMap() {
|
||||
// A well-behaved client always cleans up its definitions.
|
||||
SkASSERT(fMap.count() == 0);
|
||||
}
|
||||
|
||||
void set(const ID& id, const T& val) {
|
||||
SkASSERT(id.type() == kType);
|
||||
fMap.set(id, val);
|
||||
}
|
||||
|
||||
void remove(const ID& id) {
|
||||
SkASSERT(id.type() == kType);
|
||||
fMap.remove(id);
|
||||
}
|
||||
|
||||
const T& find(const ID& id) const {
|
||||
SkASSERT(id.type() == kType);
|
||||
T* val = fMap.find(id);
|
||||
SkASSERT(val != nullptr);
|
||||
return *val;
|
||||
}
|
||||
|
||||
private:
|
||||
SkTHashMap<ID, T> fMap;
|
||||
};
|
||||
|
||||
// Maps ID -> T*, and keeps the T alive by reffing it.
|
||||
template <typename T, Type kType>
|
||||
class ReffedIDMap {
|
||||
public:
|
||||
ReffedIDMap() {}
|
||||
~ReffedIDMap() {
|
||||
// A well-behaved client always cleans up its definitions.
|
||||
SkASSERT(fMap.count() == 0);
|
||||
}
|
||||
|
||||
void set(const ID& id, T* val) {
|
||||
SkASSERT(id.type() == kType);
|
||||
fMap.set(id, SkSafeRef(val));
|
||||
}
|
||||
|
||||
void remove(const ID& id) {
|
||||
SkASSERT(id.type() == kType);
|
||||
T** val = fMap.find(id);
|
||||
SkASSERT(val);
|
||||
SkSafeUnref(*val);
|
||||
fMap.remove(id);
|
||||
}
|
||||
|
||||
T* find(const ID& id) const {
|
||||
SkASSERT(id.type() == kType);
|
||||
T** val = fMap.find(id);
|
||||
SkASSERT(val);
|
||||
return *val;
|
||||
}
|
||||
|
||||
private:
|
||||
SkTHashMap<ID, T*> fMap;
|
||||
};
|
||||
|
||||
|
||||
IDMap<SkMatrix , Type::kMatrix> fMatrix;
|
||||
IDMap<Misc , Type::kMisc > fMisc;
|
||||
IDMap<SkPath , Type::kPath > fPath;
|
||||
IDMap<Stroke , Type::kStroke> fStroke;
|
||||
ReffedIDMap<SkShader , Type::kShader> fShader;
|
||||
ReffedIDMap<SkXfermode, Type::kXfermode> fXfermode;
|
||||
|
||||
SkCanvas* fCanvas;
|
||||
uint64_t fNextID = 0;
|
||||
};
|
||||
|
||||
Encoder* NewDecoder(SkCanvas* canvas) { return new Decoder(canvas); }
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
|
||||
class CachingEncoder final : public Encoder {
|
||||
public:
|
||||
explicit CachingEncoder(Encoder* wrapped) : fWrapped(wrapped) {}
|
||||
@ -166,194 +441,6 @@ namespace SkRemote {
|
||||
Encoder* fWrapped;
|
||||
};
|
||||
|
||||
Encoder* Encoder::CreateCachingEncoder(Encoder* wrapped) { return new CachingEncoder(wrapped); }
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
|
||||
// Calls Encoder::define() when created, Encoder::undefine() when destroyed.
|
||||
class Client::AutoID : ::SkNoncopyable {
|
||||
public:
|
||||
template <typename T>
|
||||
explicit AutoID(Encoder* encoder, const T& val)
|
||||
: fEncoder(encoder)
|
||||
, fID(encoder->define(val)) {}
|
||||
~AutoID() { if (fEncoder) fEncoder->undefine(fID); }
|
||||
|
||||
AutoID(AutoID&& o) : fEncoder(o.fEncoder), fID(o.fID) {
|
||||
o.fEncoder = nullptr;
|
||||
}
|
||||
AutoID& operator=(AutoID&&) = delete;
|
||||
|
||||
operator ID () const { return fID; }
|
||||
|
||||
private:
|
||||
Encoder* fEncoder;
|
||||
const ID fID;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Client::AutoID Client::id(const T& val) { return AutoID(fEncoder, val); }
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
|
||||
Client::Client(Encoder* encoder)
|
||||
: SkCanvas(1,1)
|
||||
, fEncoder(encoder)
|
||||
{}
|
||||
|
||||
void Client::willSave() { fEncoder->save(); }
|
||||
void Client::didRestore() { fEncoder->restore(); }
|
||||
|
||||
void Client::didConcat (const SkMatrix&) { this->didSetMatrix(this->getTotalMatrix()); }
|
||||
void Client::didSetMatrix(const SkMatrix& matrix) {
|
||||
fEncoder->setMatrix(this->id(matrix));
|
||||
}
|
||||
|
||||
void Client::onDrawOval(const SkRect& oval, const SkPaint& paint) {
|
||||
SkPath path;
|
||||
path.addOval(oval);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void Client::onDrawRect(const SkRect& rect, const SkPaint& paint) {
|
||||
SkPath path;
|
||||
path.addRect(rect);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void Client::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
||||
SkPath path;
|
||||
path.addRRect(rrect);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void Client::onDrawDRRect(const SkRRect& outside,
|
||||
const SkRRect& inside,
|
||||
const SkPaint& paint) {
|
||||
SkPath path;
|
||||
path.addRRect(outside);
|
||||
path.addRRect(inside, SkPath::kCCW_Direction);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void Client::onDrawPath(const SkPath& path, const SkPaint& paint) {
|
||||
auto p = this->id(path),
|
||||
m = this->id(Misc::CreateFrom(paint)),
|
||||
s = this->id(paint.getShader()),
|
||||
x = this->id(paint.getXfermode());
|
||||
|
||||
if (paint.getStyle() == SkPaint::kFill_Style) {
|
||||
fEncoder->fillPath(p, m, s, x);
|
||||
} else {
|
||||
// TODO: handle kStrokeAndFill_Style
|
||||
fEncoder->strokePath(p, m, s, x, this->id(Stroke::CreateFrom(paint)));
|
||||
}
|
||||
}
|
||||
|
||||
void Client::onDrawPaint(const SkPaint& paint) {
|
||||
SkPath path;
|
||||
path.setFillType(SkPath::kInverseWinding_FillType); // Either inverse FillType works fine.
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void Client::onDrawText(const void* text, size_t byteLength, SkScalar x,
|
||||
SkScalar y, const SkPaint& paint) {
|
||||
// Text-as-paths is a temporary hack.
|
||||
// TODO: send SkTextBlobs and SkTypefaces
|
||||
SkPath path;
|
||||
paint.getTextPath(text, byteLength, x, y, &path);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void Client::onDrawPosText(const void* text, size_t byteLength,
|
||||
const SkPoint pos[], const SkPaint& paint) {
|
||||
// Text-as-paths is a temporary hack.
|
||||
// TODO: send SkTextBlobs and SkTypefaces
|
||||
SkPath path;
|
||||
paint.getPosTextPath(text, byteLength, pos, &path);
|
||||
this->onDrawPath(path, paint);
|
||||
}
|
||||
|
||||
void Client::onDrawPosTextH(const void* text, size_t byteLength,
|
||||
const SkScalar xpos[], SkScalar constY,
|
||||
const SkPaint& paint) {
|
||||
size_t length = paint.countText(text, byteLength);
|
||||
SkAutoTArray<SkPoint> pos(length);
|
||||
for(size_t i = 0; i < length; ++i) {
|
||||
pos[i].set(xpos[i], constY);
|
||||
}
|
||||
this->onDrawPosText(text, byteLength, &pos[0], paint);
|
||||
}
|
||||
|
||||
void Client::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
|
||||
SkPath path;
|
||||
path.addRect(rect);
|
||||
this->onClipPath(path, op, edgeStyle);
|
||||
}
|
||||
|
||||
void Client::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
|
||||
SkPath path;
|
||||
path.addRRect(rrect);
|
||||
this->onClipPath(path, op, edgeStyle);
|
||||
}
|
||||
|
||||
void Client::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
|
||||
fEncoder->clipPath(this->id(path), op, edgeStyle == kSoft_ClipEdgeStyle);
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
|
||||
Server::Server(SkCanvas* canvas) : fCanvas(canvas) {}
|
||||
|
||||
template <typename Map, typename T>
|
||||
ID Server::define(Type type, Map* map, const T& val) {
|
||||
ID id(type, fNextID++);
|
||||
map->set(id, val);
|
||||
return id;
|
||||
}
|
||||
|
||||
ID Server::define(const SkMatrix& v) { return this->define(Type::kMatrix, &fMatrix, v); }
|
||||
ID Server::define(const Misc& v) { return this->define(Type::kMisc, &fMisc, v); }
|
||||
ID Server::define(const SkPath& v) { return this->define(Type::kPath, &fPath, v); }
|
||||
ID Server::define(const Stroke& v) { return this->define(Type::kStroke, &fStroke, v); }
|
||||
ID Server::define(SkShader* v) { return this->define(Type::kShader, &fShader, v); }
|
||||
ID Server::define(SkXfermode* v) { return this->define(Type::kXfermode, &fXfermode, v); }
|
||||
|
||||
void Server::undefine(ID id) {
|
||||
switch(id.type()) {
|
||||
case Type::kMatrix: return fMatrix .remove(id);
|
||||
case Type::kMisc: return fMisc .remove(id);
|
||||
case Type::kPath: return fPath .remove(id);
|
||||
case Type::kStroke: return fStroke .remove(id);
|
||||
case Type::kShader: return fShader .remove(id);
|
||||
case Type::kXfermode: return fXfermode.remove(id);
|
||||
};
|
||||
}
|
||||
|
||||
void Server:: save() { fCanvas->save(); }
|
||||
void Server::restore() { fCanvas->restore(); }
|
||||
|
||||
void Server::setMatrix(ID matrix) { fCanvas->setMatrix(fMatrix.find(matrix)); }
|
||||
|
||||
void Server::clipPath(ID path, SkRegion::Op op, bool aa) {
|
||||
fCanvas->clipPath(fPath.find(path), op, aa);
|
||||
}
|
||||
void Server::fillPath(ID path, ID misc, ID shader, ID xfermode) {
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
fMisc.find(misc).applyTo(&paint);
|
||||
paint.setShader (fShader .find(shader));
|
||||
paint.setXfermode(fXfermode.find(xfermode));
|
||||
fCanvas->drawPath(fPath.find(path), paint);
|
||||
}
|
||||
void Server::strokePath(ID path, ID misc, ID shader, ID xfermode, ID stroke) {
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
fMisc .find(misc ).applyTo(&paint);
|
||||
fStroke.find(stroke).applyTo(&paint);
|
||||
paint.setShader (fShader .find(shader));
|
||||
paint.setXfermode(fXfermode.find(xfermode));
|
||||
fCanvas->drawPath(fPath.find(path), paint);
|
||||
}
|
||||
Encoder* NewCachingEncoder(Encoder* wrapped) { return new CachingEncoder(wrapped); }
|
||||
|
||||
} // namespace SkRemote
|
||||
|
@ -8,13 +8,17 @@
|
||||
#ifndef SkRemote_DEFINED
|
||||
#define SkRemote_DEFINED
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkRemote_protocol.h"
|
||||
#include "SkShader.h"
|
||||
#include "SkTHash.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
class SkCanvas;
|
||||
class SkMatrix;
|
||||
class SkPath;
|
||||
class SkShader;
|
||||
class SkXfermode;
|
||||
|
||||
// TODO: document
|
||||
|
||||
namespace SkRemote {
|
||||
@ -61,8 +65,6 @@ namespace SkRemote {
|
||||
struct Encoder {
|
||||
virtual ~Encoder() {}
|
||||
|
||||
static Encoder* CreateCachingEncoder(Encoder*);
|
||||
|
||||
virtual ID define(const SkMatrix&) = 0;
|
||||
virtual ID define(const Misc&) = 0;
|
||||
virtual ID define(const SkPath&) = 0;
|
||||
@ -85,145 +87,14 @@ namespace SkRemote {
|
||||
virtual void strokePath(ID path, ID misc, ID shader, ID xfermode, ID stroke) = 0;
|
||||
};
|
||||
|
||||
// An SkCanvas that translates to Encoder calls.
|
||||
class Client final : public SkCanvas {
|
||||
public:
|
||||
explicit Client(Encoder*);
|
||||
// None of these factories take ownership of their arguments.
|
||||
|
||||
private:
|
||||
class AutoID;
|
||||
|
||||
template <typename T>
|
||||
AutoID id(const T&);
|
||||
|
||||
void willSave() override;
|
||||
void didRestore() override;
|
||||
|
||||
void didConcat(const SkMatrix&) override;
|
||||
void didSetMatrix(const SkMatrix&) override;
|
||||
|
||||
void onClipPath (const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
|
||||
void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
|
||||
void onClipRect (const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
|
||||
|
||||
void onDrawOval(const SkRect&, const SkPaint&) override;
|
||||
void onDrawRRect(const SkRRect&, const SkPaint&) override;
|
||||
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
|
||||
void onDrawPath(const SkPath&, const SkPaint&) override;
|
||||
void onDrawRect(const SkRect&, const SkPaint&) override;
|
||||
void onDrawPaint(const SkPaint&) override;
|
||||
|
||||
void onDrawText(const void*, size_t, SkScalar,
|
||||
SkScalar, const SkPaint&) override;
|
||||
void onDrawPosText(const void*, size_t, const SkPoint[],
|
||||
const SkPaint&) override;
|
||||
void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar,
|
||||
const SkPaint&) override;
|
||||
|
||||
Encoder* fEncoder;
|
||||
};
|
||||
|
||||
// An Encoder that translates back to SkCanvas calls.
|
||||
class Server final : public Encoder {
|
||||
public:
|
||||
explicit Server(SkCanvas*);
|
||||
|
||||
private:
|
||||
ID define(const SkMatrix&) override;
|
||||
ID define(const Misc&) override;
|
||||
ID define(const SkPath&) override;
|
||||
ID define(const Stroke&) override;
|
||||
ID define(SkShader*) override;
|
||||
ID define(SkXfermode*) override;
|
||||
|
||||
void undefine(ID) override;
|
||||
|
||||
void save() override;
|
||||
void restore() override;
|
||||
|
||||
void setMatrix(ID matrix) override;
|
||||
|
||||
void clipPath(ID path, SkRegion::Op, bool aa) override;
|
||||
void fillPath(ID path, ID misc, ID shader, ID xfermode) override;
|
||||
void strokePath(ID path, ID misc, ID shader, ID xfermode, ID stroke) override;
|
||||
|
||||
// Maps ID -> T.
|
||||
template <typename T, Type kType>
|
||||
class IDMap {
|
||||
public:
|
||||
~IDMap() {
|
||||
// A well-behaved client always cleans up its definitions.
|
||||
SkASSERT(fMap.count() == 0);
|
||||
}
|
||||
|
||||
void set(const ID& id, const T& val) {
|
||||
SkASSERT(id.type() == kType);
|
||||
fMap.set(id, val);
|
||||
}
|
||||
|
||||
void remove(const ID& id) {
|
||||
SkASSERT(id.type() == kType);
|
||||
fMap.remove(id);
|
||||
}
|
||||
|
||||
const T& find(const ID& id) const {
|
||||
SkASSERT(id.type() == kType);
|
||||
T* val = fMap.find(id);
|
||||
SkASSERT(val != nullptr);
|
||||
return *val;
|
||||
}
|
||||
|
||||
private:
|
||||
SkTHashMap<ID, T> fMap;
|
||||
};
|
||||
|
||||
// Maps ID -> T*, and keeps the T alive by reffing it.
|
||||
template <typename T, Type kType>
|
||||
class ReffedIDMap {
|
||||
public:
|
||||
ReffedIDMap() {}
|
||||
~ReffedIDMap() {
|
||||
// A well-behaved client always cleans up its definitions.
|
||||
SkASSERT(fMap.count() == 0);
|
||||
}
|
||||
|
||||
void set(const ID& id, T* val) {
|
||||
SkASSERT(id.type() == kType);
|
||||
fMap.set(id, SkSafeRef(val));
|
||||
}
|
||||
|
||||
void remove(const ID& id) {
|
||||
SkASSERT(id.type() == kType);
|
||||
T** val = fMap.find(id);
|
||||
SkASSERT(val);
|
||||
SkSafeUnref(*val);
|
||||
fMap.remove(id);
|
||||
}
|
||||
|
||||
T* find(const ID& id) const {
|
||||
SkASSERT(id.type() == kType);
|
||||
T** val = fMap.find(id);
|
||||
SkASSERT(val);
|
||||
return *val;
|
||||
}
|
||||
|
||||
private:
|
||||
SkTHashMap<ID, T*> fMap;
|
||||
};
|
||||
|
||||
template <typename Map, typename T>
|
||||
ID define(Type, Map*, const T&);
|
||||
|
||||
IDMap<SkMatrix, Type::kMatrix> fMatrix;
|
||||
IDMap<Misc , Type::kMisc > fMisc;
|
||||
IDMap<SkPath , Type::kPath > fPath;
|
||||
IDMap<Stroke , Type::kStroke> fStroke;
|
||||
ReffedIDMap<SkShader, Type::kShader> fShader;
|
||||
ReffedIDMap<SkXfermode, Type::kXfermode> fXfermode;
|
||||
|
||||
SkCanvas* fCanvas;
|
||||
uint64_t fNextID = 0;
|
||||
};
|
||||
// Returns a new SkCanvas that translates to the Encoder API.
|
||||
SkCanvas* NewCanvas(Encoder*);
|
||||
// Returns an Encoder that translates back to the SkCanvas API.
|
||||
Encoder* NewDecoder(SkCanvas*);
|
||||
// Wraps another Encoder with a cache. TODO: parameterize
|
||||
Encoder* NewCachingEncoder(Encoder*);
|
||||
|
||||
} // namespace SkRemote
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user