1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkRemoteGlyphCache_DEFINED
9 #define SkRemoteGlyphCache_DEFINED
10 
11 #include <memory>
12 #include <tuple>
13 #include <unordered_map>
14 #include <unordered_set>
15 #include <vector>
16 
17 #include "../private/SkTHash.h"
18 #include "SkData.h"
19 #include "SkDevice.h"
20 #include "SkDrawLooper.h"
21 #include "SkMakeUnique.h"
22 #include "SkNoDrawCanvas.h"
23 #include "SkRefCnt.h"
24 #include "SkSerialProcs.h"
25 #include "SkTypeface.h"
26 
27 class Serializer;
28 enum SkAxisAlignment : uint32_t;
29 class SkDescriptor;
30 class SkStrike;
31 struct SkPackedGlyphID;
32 enum SkScalerContextFlags : uint32_t;
33 class SkStrikeCache;
34 class SkTypefaceProxy;
35 struct WireTypeface;
36 
37 class SkStrikeServer;
38 
39 struct SkDescriptorMapOperators {
40     size_t operator()(const SkDescriptor* key) const;
41     bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const;
42 };
43 
44 template <typename T>
45 using SkDescriptorMap = std::unordered_map<const SkDescriptor*, T, SkDescriptorMapOperators,
46                                            SkDescriptorMapOperators>;
47 
48 using SkDescriptorSet =
49         std::unordered_set<const SkDescriptor*, SkDescriptorMapOperators, SkDescriptorMapOperators>;
50 
51 // A SkTextBlobCacheDiffCanvas is used to populate the SkStrikeServer with ops
52 // which will be serialized and renderered using the SkStrikeClient.
53 class SK_API SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas {
54 public:
55     struct SK_API Settings {
56         Settings();
57 
58         bool fContextSupportsDistanceFieldText = true;
59         SkScalar fMinDistanceFieldFontSize = -1.f;
60         SkScalar fMaxDistanceFieldFontSize = -1.f;
61         int fMaxTextureSize = 0;
62         size_t fMaxTextureBytes = 0u;
63     };
64     SkTextBlobCacheDiffCanvas(int width, int height, const SkSurfaceProps& props,
65                               SkStrikeServer* strikeServer, Settings settings = Settings());
66 
67     // TODO(khushalsagar): Remove once removed from chromium.
68     SkTextBlobCacheDiffCanvas(int width, int height, const SkMatrix& deviceMatrix,
69                               const SkSurfaceProps& props, SkStrikeServer* strikeserver,
70                               Settings settings = Settings());
71     ~SkTextBlobCacheDiffCanvas() override;
72 
73 protected:
74     SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
75     bool onDoSaveBehind(const SkRect*) override;
76     void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
77                         const SkPaint& paint) override;
78 
79 private:
80     class TrackLayerDevice;
81 
82     static SkScalar SetupForPath(SkPaint* paint, SkFont* font);
83 };
84 
85 using SkDiscardableHandleId = uint32_t;
86 
87 // This class is not thread-safe.
88 class SK_API SkStrikeServer {
89 public:
90     // An interface used by the server to create handles for pinning SkStrike
91     // entries on the remote client.
92     class SK_API DiscardableHandleManager {
93     public:
94         virtual ~DiscardableHandleManager() = default;
95 
96         // Creates a new *locked* handle and returns a unique ID that can be used to identify
97         // it on the remote client.
98         virtual SkDiscardableHandleId createHandle() = 0;
99 
100         // Returns true if the handle could be successfully locked. The server can
101         // assume it will remain locked until the next set of serialized entries is
102         // pulled from the SkStrikeServer.
103         // If returns false, the cache entry mapped to the handle has been deleted
104         // on the client. Any subsequent attempts to lock the same handle are not
105         // allowed.
106         virtual bool lockHandle(SkDiscardableHandleId) = 0;
107 
108         // Returns true if a handle has been deleted on the remote client. It is
109         // invalid to use a handle id again with this manager once this returns true.
110         // TODO(khushalsagar): Make pure virtual once chrome implementation lands.
isHandleDeleted(SkDiscardableHandleId)111         virtual bool isHandleDeleted(SkDiscardableHandleId) { return false; }
112     };
113 
114     explicit SkStrikeServer(DiscardableHandleManager* discardableHandleManager);
115     ~SkStrikeServer();
116 
117     // Serializes the typeface to be remoted using this server.
118     sk_sp<SkData> serializeTypeface(SkTypeface*);
119 
120     // Serializes the strike data captured using a SkTextBlobCacheDiffCanvas. Any
121     // handles locked using the DiscardableHandleManager will be assumed to be
122     // unlocked after this call.
123     void writeStrikeData(std::vector<uint8_t>* memory);
124 
125     // Methods used internally in skia ------------------------------------------
126     class SkGlyphCacheState;
127 
128     SkGlyphCacheState* getOrCreateCache(const SkPaint&,
129                                         const SkFont& font,
130                                         const SkSurfaceProps&,
131                                         const SkMatrix&,
132                                         SkScalerContextFlags flags,
133                                         SkScalerContextEffects* effects);
134 
setMaxEntriesInDescriptorMapForTesting(size_t count)135     void setMaxEntriesInDescriptorMapForTesting(size_t count) {
136         fMaxEntriesInDescriptorMap = count;
137     }
remoteGlyphStateMapSizeForTesting()138     size_t remoteGlyphStateMapSizeForTesting() const { return fRemoteGlyphStateMap.size(); }
139 
140 private:
141     static constexpr size_t kMaxEntriesInDescriptorMap = 2000u;
142 
143     void checkForDeletedEntries();
144 
145     SkDescriptorMap<std::unique_ptr<SkGlyphCacheState>> fRemoteGlyphStateMap;
146     DiscardableHandleManager* const fDiscardableHandleManager;
147     SkTHashSet<SkFontID> fCachedTypefaces;
148     size_t fMaxEntriesInDescriptorMap = kMaxEntriesInDescriptorMap;
149 
150     // Cached serialized typefaces.
151     SkTHashMap<SkFontID, sk_sp<SkData>> fSerializedTypefaces;
152 
153     // State cached until the next serialization.
154     SkDescriptorSet fLockedDescs;
155     std::vector<WireTypeface> fTypefacesToSend;
156 };
157 
158 class SK_API SkStrikeClient {
159 public:
160     // This enum is used in histogram reporting in chromium. Please don't re-order the list of
161     // entries, and consider it to be append-only.
162     enum CacheMissType : uint32_t {
163         // Hard failures where no fallback could be found.
164         kFontMetrics = 0,
165         kGlyphMetrics = 1,
166         kGlyphImage = 2,
167         kGlyphPath = 3,
168 
169         // The original glyph could not be found and a fallback was used.
170         kGlyphMetricsFallback = 4,
171         kGlyphPathFallback = 5,
172 
173         kLast = kGlyphPathFallback
174     };
175 
176     // An interface to delete handles that may be pinned by the remote server.
177     class DiscardableHandleManager : public SkRefCnt {
178     public:
179         virtual ~DiscardableHandleManager() = default;
180 
181         // Returns true if the handle was unlocked and can be safely deleted. Once
182         // successful, subsequent attempts to delete the same handle are invalid.
183         virtual bool deleteHandle(SkDiscardableHandleId) = 0;
184 
notifyCacheMiss(CacheMissType)185         virtual void notifyCacheMiss(CacheMissType) {}
186     };
187 
188     explicit SkStrikeClient(sk_sp<DiscardableHandleManager>,
189                             bool isLogging = true,
190                             SkStrikeCache* strikeCache = nullptr);
191     ~SkStrikeClient();
192 
193     // Deserializes the typeface previously serialized using the SkStrikeServer. Returns null if the
194     // data is invalid.
195     sk_sp<SkTypeface> deserializeTypeface(const void* data, size_t length);
196 
197     // Deserializes the strike data from a SkStrikeServer. All messages generated
198     // from a server when serializing the ops must be deserialized before the op
199     // is rasterized.
200     // Returns false if the data is invalid.
201     bool readStrikeData(const volatile void* memory, size_t memorySize);
202 
203 private:
204     class DiscardableStrikePinner;
205 
206     sk_sp<SkTypeface> addTypeface(const WireTypeface& wire);
207 
208     SkTHashMap<SkFontID, sk_sp<SkTypeface>> fRemoteFontIdToTypeface;
209     sk_sp<DiscardableHandleManager> fDiscardableHandleManager;
210     SkStrikeCache* const fStrikeCache;
211     const bool fIsLogging;
212 };
213 
214 #endif  // SkRemoteGlyphCache_DEFINED
215