diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkRemote.cpp | 153 | ||||
-rw-r--r-- | src/core/SkRemote.h | 93 | ||||
-rw-r--r-- | src/core/SkRemote_protocol.h | 8 |
3 files changed, 187 insertions, 67 deletions
diff --git a/src/core/SkRemote.cpp b/src/core/SkRemote.cpp index 3966aaccc0..8efeb8b845 100644 --- a/src/core/SkRemote.cpp +++ b/src/core/SkRemote.cpp @@ -97,15 +97,16 @@ namespace SkRemote { Cache* Cache::CreateNeverCache() { struct NeverCache final : public Cache { NeverCache() - : fNextMatrix(Type::kMatrix) - , fNextMisc (Type::kMisc) - , fNextPath (Type::kPath) - , fNextStroke(Type::kStroke) + : fNextMatrix (Type::kMatrix) + , fNextMisc (Type::kMisc) + , fNextPath (Type::kPath) + , fNextStroke (Type::kStroke) + , fNextXfermode(Type::kXfermode) {} void cleanup(Encoder*) override {} static bool Helper(ID* next, ID* id, LookupScope* ls) { - *id = (*next)++; + *id = ++(*next); ls->undefineWhenDone(*id); return false; } @@ -122,65 +123,120 @@ namespace SkRemote { bool lookup(const Stroke&, ID* id, LookupScope* ls) override { return Helper(&fNextStroke, id, ls); } + bool lookup(const SkXfermode* xfermode, ID* id, LookupScope* ls) override { + if (!xfermode) { + *id = ID(Type::kXfermode); + return true; // Null IDs are always defined. + } + return Helper(&fNextXfermode, id, ls); + } ID fNextMatrix, fNextMisc, fNextPath, - fNextStroke; + fNextStroke, + fNextXfermode; }; return new NeverCache; } - // Can't be declared locally inside AlwaysCache because of the templating. :( - template <typename T, typename Map> - static bool always_cache_helper(const T& val, Map* map, ID* next, ID* id) { - if (ID* found = map->find(val)) { - *id = *found; - return true; + // These can't be declared locally inside AlwaysCache because of the templating. :( + namespace { + template <typename T, typename Map> + static bool always_cache_lookup(const T& val, Map* map, ID* next, ID* id) { + if (const ID* found = map->find(val)) { + *id = *found; + return true; + } + *id = ++(*next); + map->set(val, *id); + return false; } - *id = (*next)++; - map->set(val, *id); - return false; - } + + struct Undefiner { + Encoder* fEncoder; + + template <typename T> + void operator()(const T&, ID* id) const { fEncoder->undefine(*id); } + }; + + // Maps const T* -> ID, and refs the key. nullptr always maps to ID(kType). + template <typename T, Type kType> + class RefKeyMap { + public: + RefKeyMap() {} + ~RefKeyMap() { fMap.foreach([](const T* key, ID*) { key->unref(); }); } + + void set(const T* key, const ID& id) { + SkASSERT(key && id.type() == kType); + fMap.set(SkRef(key), id); + } + + void remove(const T* key) { + SkASSERT(key); + fMap.remove(key); + key->unref(); + } + + const ID* find(const T* key) const { + static const ID nullID(kType); + return key ? fMap.find(key) : &nullID; + } + + template <typename Fn> + void foreach(const Fn& fn) { fMap.foreach(fn); } + private: + SkTHashMap<const T*, ID> fMap; + }; + } // namespace Cache* Cache::CreateAlwaysCache() { struct AlwaysCache final : public Cache { AlwaysCache() - : fNextMatrix(Type::kMatrix) - , fNextMisc (Type::kMisc) - , fNextPath (Type::kPath) - , fNextStroke(Type::kStroke) + : fNextMatrix (Type::kMatrix) + , fNextMisc (Type::kMisc) + , fNextPath (Type::kPath) + , fNextStroke (Type::kStroke) + , fNextXfermode(Type::kXfermode) {} void cleanup(Encoder* encoder) override { - fMatrix.foreach([=](const SkMatrix&, ID* id) { encoder->undefine(*id); }); - fMisc .foreach([=](const Misc&, ID* id) { encoder->undefine(*id); }); - fPath .foreach([=](const SkPath&, ID* id) { encoder->undefine(*id); }); - fStroke.foreach([=](const Stroke&, ID* id) { encoder->undefine(*id); }); + Undefiner undef{encoder}; + fMatrix .foreach(undef); + fMisc .foreach(undef); + fPath .foreach(undef); + fStroke .foreach(undef); + fXfermode.foreach(undef); } bool lookup(const SkMatrix& matrix, ID* id, LookupScope*) override { - return always_cache_helper(matrix, &fMatrix, &fNextMatrix, id); + return always_cache_lookup(matrix, &fMatrix, &fNextMatrix, id); } bool lookup(const Misc& misc, ID* id, LookupScope*) override { - return always_cache_helper(misc, &fMisc, &fNextMisc, id); + return always_cache_lookup(misc, &fMisc, &fNextMisc, id); } bool lookup(const SkPath& path, ID* id, LookupScope*) override { - return always_cache_helper(path, &fPath, &fNextPath, id); + return always_cache_lookup(path, &fPath, &fNextPath, id); } bool lookup(const Stroke& stroke, ID* id, LookupScope*) override { - return always_cache_helper(stroke, &fStroke, &fNextStroke, id); + return always_cache_lookup(stroke, &fStroke, &fNextStroke, id); } + bool lookup(const SkXfermode* xfermode, ID* id, LookupScope*) override { + return always_cache_lookup(xfermode, &fXfermode, &fNextXfermode, id); + } + + SkTHashMap<SkMatrix, ID> fMatrix; + SkTHashMap<Misc, ID, MiscHash> fMisc; + SkTHashMap<SkPath, ID> fPath; + SkTHashMap<Stroke, ID> fStroke; + RefKeyMap<SkXfermode, Type::kXfermode> fXfermode; - SkTHashMap<SkMatrix, ID> fMatrix; - SkTHashMap<Misc, ID, MiscHash> fMisc; - SkTHashMap<SkPath, ID> fPath; - SkTHashMap<Stroke, ID> fStroke; ID fNextMatrix, fNextMisc, fNextPath, - fNextStroke; + fNextStroke, + fNextXfermode; }; return new AlwaysCache; } @@ -236,13 +292,14 @@ namespace SkRemote { void Client::onDrawPath(const SkPath& path, const SkPaint& paint) { LookupScope ls(fCache, fEncoder); ID p = ls.lookup(path), - m = ls.lookup(Misc::CreateFrom(paint)); + m = ls.lookup(Misc::CreateFrom(paint)), + x = ls.lookup(paint.getXfermode()); if (paint.getStyle() == SkPaint::kFill_Style) { - fEncoder->fillPath(p, m); + fEncoder->fillPath(p, m, x); } else { // TODO: handle kStrokeAndFill_Style - fEncoder->strokePath(p, m, ls.lookup(Stroke::CreateFrom(paint))); + fEncoder->strokePath(p, m, x, ls.lookup(Stroke::CreateFrom(paint))); } } @@ -302,17 +359,19 @@ namespace SkRemote { Server::Server(SkCanvas* canvas) : fCanvas(canvas) {} - void Server::define(ID id, const SkMatrix& v) { fMatrix.set(id, v); } - void Server::define(ID id, const Misc& v) { fMisc .set(id, v); } - void Server::define(ID id, const SkPath& v) { fPath .set(id, v); } - void Server::define(ID id, const Stroke& v) { fStroke.set(id, v); } + void Server::define(ID id, const SkMatrix& v) { fMatrix .set(id, v); } + void Server::define(ID id, const Misc& v) { fMisc .set(id, v); } + void Server::define(ID id, const SkPath& v) { fPath .set(id, v); } + void Server::define(ID id, const Stroke& v) { fStroke .set(id, v); } + void Server::define(ID id, SkXfermode* v) { fXfermode.set(id, 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::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::kXfermode: return fXfermode.remove(id); case Type::kNone: SkASSERT(false); }; @@ -326,17 +385,19 @@ namespace SkRemote { void Server::clipPath(ID path, SkRegion::Op op, bool aa) { fCanvas->clipPath(fPath.find(path), op, aa); } - void Server::fillPath(ID path, ID misc) { + void Server::fillPath(ID path, ID misc, ID xfermode) { SkPaint paint; paint.setStyle(SkPaint::kFill_Style); fMisc.find(misc).applyTo(&paint); + paint.setXfermode(fXfermode.find(xfermode)); fCanvas->drawPath(fPath.find(path), paint); } - void Server::strokePath(ID path, ID misc, ID stroke) { + void Server::strokePath(ID path, ID misc, ID xfermode, ID stroke) { SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); fMisc .find(misc ).applyTo(&paint); fStroke.find(stroke).applyTo(&paint); + paint.setXfermode(fXfermode.find(xfermode)); fCanvas->drawPath(fPath.find(path), paint); } diff --git a/src/core/SkRemote.h b/src/core/SkRemote.h index 72914d4382..ed99c0f866 100644 --- a/src/core/SkRemote.h +++ b/src/core/SkRemote.h @@ -45,6 +45,7 @@ namespace SkRemote { virtual void define(ID, const Misc&) = 0; virtual void define(ID, const SkPath&) = 0; virtual void define(ID, const Stroke&) = 0; + virtual void define(ID, SkXfermode*) = 0; virtual void undefine(ID) = 0; @@ -53,24 +54,37 @@ namespace SkRemote { virtual void setMatrix(ID matrix) = 0; - virtual void clipPath(ID path, SkRegion::Op, bool aa) = 0; - virtual void fillPath(ID path, ID misc) = 0; - virtual void strokePath(ID path, ID misc, ID stroke) = 0; + // TODO: struct CommonIDs { ID misc; ID xfermode; ... } + // for IDs that affect both fill + stroke? + + virtual void clipPath(ID path, SkRegion::Op, bool aa) = 0; + virtual void fillPath(ID path, ID misc, ID xfermode) = 0; + virtual void strokePath(ID path, ID misc, ID xfermode, ID stroke) = 0; }; class LookupScope; - // TODO: document + // The Cache interface encapsulates the caching logic of the Client. + // + // Each lookup() method must always fill ID* with a valid value, + // but ID may be cached. If so, the lookup() method returns true; + // if not the lookup() method returns false and the Client must + // then define() this ID -> Thing mapping before using the ID. + // + // The Caches may also add IDs to the LookupScope's list of IDs to + // undefine() on destruction. This lets the Cache purge IDs. struct Cache { virtual ~Cache() {} - static Cache* CreateNeverCache(); - static Cache* CreateAlwaysCache(); + static Cache* CreateNeverCache(); // Never caches anything. + static Cache* CreateAlwaysCache(); // Caches by value (not deep pointer equality). + // TODO: static Cache* CreateDeepCache(); // Caches by deep value. - virtual bool lookup(const SkMatrix&, ID*, LookupScope*) = 0; - virtual bool lookup(const Misc&, ID*, LookupScope*) = 0; - virtual bool lookup(const SkPath&, ID*, LookupScope*) = 0; - virtual bool lookup(const Stroke&, ID*, LookupScope*) = 0; + virtual bool lookup(const SkMatrix&, ID*, LookupScope*) = 0; + virtual bool lookup(const Misc&, ID*, LookupScope*) = 0; + virtual bool lookup(const SkPath&, ID*, LookupScope*) = 0; + virtual bool lookup(const Stroke&, ID*, LookupScope*) = 0; + virtual bool lookup(const SkXfermode*, ID*, LookupScope*) = 0; virtual void cleanup(Encoder*) = 0; }; @@ -120,6 +134,7 @@ namespace SkRemote { void define(ID, const Misc&) override; void define(ID, const SkPath&) override; void define(ID, const Stroke&) override; + void define(ID, SkXfermode*) override; void undefine(ID) override; @@ -128,13 +143,19 @@ namespace SkRemote { void setMatrix(ID matrix) override; - void clipPath(ID path, SkRegion::Op, bool aa) override; - void fillPath(ID path, ID misc) override; - void strokePath(ID path, ID misc, ID stroke) override; + void clipPath(ID path, SkRegion::Op, bool aa) override; + void fillPath(ID path, ID misc, ID xfermode) override; + void strokePath(ID path, ID misc, 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); @@ -156,10 +177,48 @@ namespace SkRemote { SkTHashMap<ID, T> fMap; }; - IDMap<SkMatrix, Type::kMatrix> fMatrix; - IDMap<Misc , Type::kMisc > fMisc; - IDMap<SkPath , Type::kPath > fPath; - IDMap<Stroke , Type::kStroke> fStroke; + // Maps ID -> T*, and keeps the T alive by reffing it. + template <typename T, Type kType> + class ReffedIDMap { + public: + ReffedIDMap() { + // A null ID always maps to nullptr. + fMap.set(ID(kType), nullptr); + } + ~ReffedIDMap() { + // A well-behaved client always cleans up its definitions. + SkASSERT(fMap.count() == 1); + } + + void set(const ID& id, T* val) { + SkASSERT(id.type() == kType && val); + fMap.set(id, SkRef(val)); + } + + void remove(const ID& id) { + SkASSERT(id.type() == kType); + T** val = fMap.find(id); + SkASSERT(val && *val); + (*val)->unref(); + 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<SkXfermode, Type::kXfermode> fXfermode; SkCanvas* fCanvas; }; diff --git a/src/core/SkRemote_protocol.h b/src/core/SkRemote_protocol.h index 997521356e..23fa60cfc9 100644 --- a/src/core/SkRemote_protocol.h +++ b/src/core/SkRemote_protocol.h @@ -21,6 +21,7 @@ namespace SkRemote { kMisc, kPath, kStroke, + kXfermode, }; class ID { @@ -35,11 +36,10 @@ namespace SkRemote { uint64_t val() const { return fVal & ~((uint64_t)0xFF << 56); } bool operator==(ID o) const { return fVal == o.fVal; } - ID operator++(int) { - ID prev = *this; - fVal++; + ID operator++() { + ++fVal; SkASSERT(this->val() != 0); // Overflow is particularly bad as it'd change our Type. - return prev; + return *this; } private: |