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:
mtklein 2015-10-21 12:34:01 -07:00 committed by Commit bot
parent e71000f0df
commit 479fe776a0
3 changed files with 296 additions and 339 deletions

View File

@ -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);
});
}

View File

@ -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

View File

@ -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