/* * Copyright 2018 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkRemoteGlyphCache_DEFINED #define SkRemoteGlyphCache_DEFINED #include #include #include #include #include #include "../private/SkTHash.h" #include "SkData.h" #include "SkDrawLooper.h" #include "SkMakeUnique.h" #include "SkNoDrawCanvas.h" #include "SkRefCnt.h" #include "SkSerialProcs.h" #include "SkTypeface.h" class Serializer; enum SkAxisAlignment : uint32_t; class SkDescriptor; class SkGlyphCache; struct SkPackedGlyphID; enum SkScalerContextFlags : uint32_t; class SkScalerContextRecDescriptor; class SkStrikeCache; class SkTextBlobRunIterator; class SkTypefaceProxy; struct WireTypeface; class SkStrikeServer; struct SkDescriptorMapOperators { size_t operator()(const SkDescriptor* key) const; bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const; }; template using SkDescriptorMap = std::unordered_map; using SkDescriptorSet = std::unordered_set; // A SkTextBlobCacheDiffCanvas is used to populate the SkStrikeServer with ops // which will be serialized and renderered using the SkStrikeClient. class SK_API SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas { public: struct SK_API Settings { Settings(); ~Settings(); bool fContextSupportsDistanceFieldText = true; SkScalar fMinDistanceFieldFontSize = -1.f; SkScalar fMaxDistanceFieldFontSize = -1.f; int fMaxTextureSize = 0; size_t fMaxTextureBytes = 0u; }; SkTextBlobCacheDiffCanvas(int width, int height, const SkSurfaceProps& props, SkStrikeServer* strikeserver, Settings settings = Settings()); // TODO(khushalsagar): Remove once removed from chromium. SkTextBlobCacheDiffCanvas(int width, int height, const SkMatrix& deviceMatrix, const SkSurfaceProps& props, SkStrikeServer* strikeserver, Settings settings = Settings()); ~SkTextBlobCacheDiffCanvas() override; protected: SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) override; private: class TrackLayerDevice; }; using SkDiscardableHandleId = uint32_t; // This class is not thread-safe. class SK_API SkStrikeServer { public: // An interface used by the server to create handles for pinning SkGlyphCache // entries on the remote client. class SK_API DiscardableHandleManager { public: virtual ~DiscardableHandleManager() {} // Creates a new *locked* handle and returns a unique ID that can be used to identify // it on the remote client. virtual SkDiscardableHandleId createHandle() = 0; // Returns true if the handle could be successfully locked. The server can // assume it will remain locked until the next set of serialized entries is // pulled from the SkStrikeServer. // If returns false, the cache entry mapped to the handle has been deleted // on the client. Any subsequent attempts to lock the same handle are not // allowed. virtual bool lockHandle(SkDiscardableHandleId) = 0; // TODO(khushalsagar): Add an API which checks whether a handle is still // valid without locking, so we can avoid tracking stale handles once they // have been purged on the remote side. }; SkStrikeServer(DiscardableHandleManager* discardableHandleManager); ~SkStrikeServer(); // Serializes the typeface to be remoted using this server. sk_sp serializeTypeface(SkTypeface*); // Serializes the strike data captured using a SkTextBlobCacheDiffCanvas. Any // handles locked using the DiscardableHandleManager will be assumed to be // unlocked after this call. void writeStrikeData(std::vector* memory); // Methods used internally in skia ------------------------------------------ class SkGlyphCacheState { public: SkGlyphCacheState(std::unique_ptr deviceDescriptor, std::unique_ptr keyDescriptor, SkDiscardableHandleId discardableHandleId, bool isSubpixel, SkAxisAlignment axisAlignmentForHText); ~SkGlyphCacheState(); void addGlyph(SkTypeface*, const SkScalerContextEffects&, SkPackedGlyphID, bool pathOnly); void writePendingGlyphs(Serializer* serializer); SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; } const SkDescriptor& getDeviceDescriptor() { return *fDeviceDescriptor; } bool isSubpixel() const { return fIsSubpixel; } SkAxisAlignment axisAlignmentForHText() const { return fAxisAlignmentForHText; } const SkDescriptor& getKeyDescriptor() { return *fKeyDescriptor; } const SkGlyph& findGlyph(SkTypeface*, const SkScalerContextEffects&, SkPackedGlyphID); private: bool hasPendingGlyphs() const { return !fPendingGlyphImages.empty() || !fPendingGlyphPaths.empty(); } void writeGlyphPath(const SkPackedGlyphID& glyphID, Serializer* serializer) const; // The set of glyphs cached on the remote client. SkTHashSet fCachedGlyphImages; SkTHashSet fCachedGlyphPaths; // The set of glyphs which has not yet been serialized and sent to the // remote client. std::vector fPendingGlyphImages; std::vector fPendingGlyphPaths; // The device descriptor is used to create the scaler context. The glyphs to have the // correct device rendering. The key descriptor is used for communication. The GPU side will // create descriptors with out the device filtering, thus matching the key descriptor. std::unique_ptr fDeviceDescriptor; std::unique_ptr fKeyDescriptor; const SkDiscardableHandleId fDiscardableHandleId; const bool fIsSubpixel; const SkAxisAlignment fAxisAlignmentForHText; // The context built using fDeviceDescriptor std::unique_ptr fContext; // FallbackTextHelper cases require glyph metrics when analyzing a glyph run, in which case // we cache them here. SkTHashMap fGlyphMap; }; SkGlyphCacheState* getOrCreateCache(const SkPaint&, const SkSurfaceProps*, const SkMatrix*, SkScalerContextFlags flags, SkScalerContextEffects* effects); private: SkDescriptorMap> fRemoteGlyphStateMap; DiscardableHandleManager* const fDiscardableHandleManager; SkTHashSet fCachedTypefaces; // State cached until the next serialization. SkDescriptorSet fLockedDescs; std::vector fTypefacesToSend; }; class SK_API SkStrikeClient { public: // This enum is used in histogram reporting in chromium. Please don't re-order the list of // entries, and consider it to be append-only. enum CacheMissType : uint32_t { // Hard failures where no fallback could be found. kFontMetrics = 0, kGlyphMetrics = 1, kGlyphImage = 2, kGlyphPath = 3, // The original glyph could not be found and a fallback was used. kGlyphMetricsFallback = 4, kGlyphPathFallback = 5, kLast = kGlyphPathFallback }; // An interface to delete handles that may be pinned by the remote server. class DiscardableHandleManager : public SkRefCnt { public: virtual ~DiscardableHandleManager() {} // Returns true if the handle was unlocked and can be safely deleted. Once // successful, subsequent attempts to delete the same handle are invalid. virtual bool deleteHandle(SkDiscardableHandleId) = 0; virtual void notifyCacheMiss(CacheMissType) {} }; SkStrikeClient(sk_sp, bool isLogging = true, SkStrikeCache* strikeCache = nullptr); ~SkStrikeClient(); // Deserializes the typeface previously serialized using the SkStrikeServer. Returns null if the // data is invalid. sk_sp deserializeTypeface(const void* data, size_t length); // Deserializes the strike data from a SkStrikeServer. All messages generated // from a server when serializing the ops must be deserialized before the op // is rasterized. // Returns false if the data is invalid. bool readStrikeData(const volatile void* memory, size_t memorySize); private: class DiscardableStrikePinner; sk_sp addTypeface(const WireTypeface& wire); SkTHashMap> fRemoteFontIdToTypeface; sk_sp fDiscardableHandleManager; SkStrikeCache* const fStrikeCache; const bool fIsLogging; }; #endif // SkRemoteGlyphCache_DEFINED