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// Use `extra_cflags=["-DSK_CAPTURE_DRAW_TEXT_BLOB"]` to capture traces to disc.
12
13// Or uncomment this line:
14//#define SK_CAPTURE_DRAW_TEXT_BLOB
15
16#include <memory>
17#include <tuple>
18#include <unordered_map>
19#include <unordered_set>
20#include <vector>
21
22#include "include/core/SkData.h"
23#include "include/core/SkRefCnt.h"
24#include "include/core/SkSerialProcs.h"
25#include "include/core/SkTypeface.h"
26#include "include/private/SkTHash.h"
27#include "include/utils/SkNoDrawCanvas.h"
28#include "src/core/SkDevice.h"
29#include "src/core/SkStrikeForGPU.h"
30#include "src/core/SkTLazy.h"
31#include "src/core/SkTextBlobTrace.h"
32
33class Deserializer;
34class Serializer;
35enum SkAxisAlignment : uint32_t;
36class SkDescriptor;
37class SkAutoDescriptor;
38struct SkPackedGlyphID;
39enum SkScalerContextFlags : uint32_t;
40class SkStrikeCache;
41class SkTypefaceProxy;
42struct WireTypeface;
43
44class SkStrikeServer;
45
46// A SkTextBlobCacheDiffCanvas is used to populate the SkStrikeServer with ops
47// which will be serialized and rendered using the SkStrikeClient.
48class SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas {
49public:
50
51 // For testing use only
52 SkTextBlobCacheDiffCanvas(int width, int height, const SkSurfaceProps& props,
53 SkStrikeServer* strikeServer, bool DFTSupport = true);
54
55 SK_SPI SkTextBlobCacheDiffCanvas(int width, int height, const SkSurfaceProps& props,
56 SkStrikeServer* strikeServer, sk_sp<SkColorSpace> colorSpace,
57 bool DFTSupport);
58
59 SK_SPI ~SkTextBlobCacheDiffCanvas() override;
60
61protected:
62 SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
63 bool onDoSaveBehind(const SkRect*) override;
64 void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
65 const SkPaint& paint) override;
66
67private:
68 class TrackLayerDevice;
69};
70
71using SkDiscardableHandleId = uint32_t;
72
73// This class is not thread-safe.
74class SkStrikeServer final : public SkStrikeForGPUCacheInterface {
75public:
76 // An interface used by the server to create handles for pinning SkStrike
77 // entries on the remote client.
78 class DiscardableHandleManager {
79 public:
80 SK_SPI virtual ~DiscardableHandleManager() = default;
81
82 // Creates a new *locked* handle and returns a unique ID that can be used to identify
83 // it on the remote client.
84 SK_SPI virtual SkDiscardableHandleId createHandle() = 0;
85
86 // Returns true if the handle could be successfully locked. The server can
87 // assume it will remain locked until the next set of serialized entries is
88 // pulled from the SkStrikeServer.
89 // If returns false, the cache entry mapped to the handle has been deleted
90 // on the client. Any subsequent attempts to lock the same handle are not
91 // allowed.
92 SK_SPI virtual bool lockHandle(SkDiscardableHandleId) = 0;
93
94 // Returns true if a handle has been deleted on the remote client. It is
95 // invalid to use a handle id again with this manager once this returns true.
96 // TODO(khushalsagar): Make pure virtual once chrome implementation lands.
97 SK_SPI virtual bool isHandleDeleted(SkDiscardableHandleId) { return false; }
98 };
99
100 SK_SPI explicit SkStrikeServer(DiscardableHandleManager* discardableHandleManager);
101 SK_SPI ~SkStrikeServer() override;
102
103 // Serializes the typeface to be transmitted using this server.
104 SK_SPI sk_sp<SkData> serializeTypeface(SkTypeface*);
105
106 // Serializes the strike data captured using a SkTextBlobCacheDiffCanvas. Any
107 // handles locked using the DiscardableHandleManager will be assumed to be
108 // unlocked after this call.
109 SK_SPI void writeStrikeData(std::vector<uint8_t>* memory);
110
111 // Methods used internally in Skia ------------------------------------------
112 class RemoteStrike;
113
114 RemoteStrike* getOrCreateCache(const SkPaint&,
115 const SkFont& font,
116 const SkSurfaceProps&,
117 const SkMatrix&,
118 SkScalerContextFlags flags,
119 SkScalerContextEffects* effects);
120
121 SkScopedStrikeForGPU findOrCreateScopedStrike(const SkDescriptor& desc,
122 const SkScalerContextEffects& effects,
123 const SkTypeface& typeface) override;
124
125 static void AddGlyphForTesting(
126 RemoteStrike* strike, SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects);
127
128 void setMaxEntriesInDescriptorMapForTesting(size_t count) {
129 fMaxEntriesInDescriptorMap = count;
130 }
131 size_t remoteStrikeMapSizeForTesting() const { return fDescToRemoteStrike.size(); }
132
133 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
134 // DrawTextBlob trace capture.
135 std::unique_ptr<SkTextBlobTrace::Capture> fCapture;
136 #endif // SK_CAPTURE_DRAW_TEXT_BLOB
137
138private:
139 static constexpr size_t kMaxEntriesInDescriptorMap = 2000u;
140
141 void checkForDeletedEntries();
142
143 RemoteStrike* getOrCreateCache(const SkDescriptor& desc,
144 const SkTypeface& typeface,
145 SkScalerContextEffects effects);
146
147 struct MapOps {
148 size_t operator()(const SkDescriptor* key) const;
149 bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const;
150 };
151 using DescToRemoteStrike =
152 std::unordered_map<const SkDescriptor*, std::unique_ptr<RemoteStrike>, MapOps, MapOps>;
153 DescToRemoteStrike fDescToRemoteStrike;
154
155 DiscardableHandleManager* const fDiscardableHandleManager;
156 SkTHashSet<SkFontID> fCachedTypefaces;
157 size_t fMaxEntriesInDescriptorMap = kMaxEntriesInDescriptorMap;
158
159 // Cached serialized typefaces.
160 SkTHashMap<SkFontID, sk_sp<SkData>> fSerializedTypefaces;
161
162 // State cached until the next serialization.
163 SkTHashSet<RemoteStrike*> fRemoteStrikesToSend;
164 std::vector<WireTypeface> fTypefacesToSend;
165};
166
167class SkStrikeClient {
168public:
169 // This enum is used in histogram reporting in chromium. Please don't re-order the list of
170 // entries, and consider it to be append-only.
171 enum CacheMissType : uint32_t {
172 // Hard failures where no fallback could be found.
173 kFontMetrics = 0,
174 kGlyphMetrics = 1,
175 kGlyphImage = 2,
176 kGlyphPath = 3,
177
178 // (DEPRECATED) The original glyph could not be found and a fallback was used.
179 kGlyphMetricsFallback = 4,
180 kGlyphPathFallback = 5,
181
182 kLast = kGlyphPath
183 };
184
185 // An interface to delete handles that may be pinned by the remote server.
186 class DiscardableHandleManager : public SkRefCnt {
187 public:
188 ~DiscardableHandleManager() override = default;
189
190 // Returns true if the handle was unlocked and can be safely deleted. Once
191 // successful, subsequent attempts to delete the same handle are invalid.
192 virtual bool deleteHandle(SkDiscardableHandleId) = 0;
193
194 virtual void notifyCacheMiss(CacheMissType) {}
195
196 struct ReadFailureData {
197 size_t memorySize;
198 size_t bytesRead;
199 uint64_t typefaceSize;
200 uint64_t strikeCount;
201 uint64_t glyphImagesCount;
202 uint64_t glyphPathsCount;
203 };
204 virtual void notifyReadFailure(const ReadFailureData& data) {}
205 };
206
207 SK_SPI explicit SkStrikeClient(sk_sp<DiscardableHandleManager>,
208 bool isLogging = true,
209 SkStrikeCache* strikeCache = nullptr);
210 SK_SPI ~SkStrikeClient();
211
212 // Deserializes the typeface previously serialized using the SkStrikeServer. Returns null if the
213 // data is invalid.
214 SK_SPI sk_sp<SkTypeface> deserializeTypeface(const void* data, size_t length);
215
216 // Deserializes the strike data from a SkStrikeServer. All messages generated
217 // from a server when serializing the ops must be deserialized before the op
218 // is rasterized.
219 // Returns false if the data is invalid.
220 SK_SPI bool readStrikeData(const volatile void* memory, size_t memorySize);
221
222private:
223 class DiscardableStrikePinner;
224
225 static bool ReadGlyph(SkTLazy<SkGlyph>& glyph, Deserializer* deserializer);
226 sk_sp<SkTypeface> addTypeface(const WireTypeface& wire);
227
228 SkTHashMap<SkFontID, sk_sp<SkTypeface>> fRemoteFontIdToTypeface;
229 sk_sp<DiscardableHandleManager> fDiscardableHandleManager;
230 SkStrikeCache* const fStrikeCache;
231 const bool fIsLogging;
232};
233
234// For exposure to fuzzing only.
235bool SkFuzzDeserializeSkDescriptor(sk_sp<SkData> bytes, SkAutoDescriptor* ad);
236
237#endif // SkRemoteGlyphCache_DEFINED
238