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 33 class Deserializer; 34 class Serializer; 35 enum SkAxisAlignment : uint32_t; 36 class SkDescriptor; 37 class SkAutoDescriptor; 38 struct SkPackedGlyphID; 39 enum SkScalerContextFlags : uint32_t; 40 class SkStrikeCache; 41 class SkTypefaceProxy; 42 struct WireTypeface; 43 44 class SkStrikeServer; 45 46 // A SkTextBlobCacheDiffCanvas is used to populate the SkStrikeServer with ops 47 // which will be serialized and rendered using the SkStrikeClient. 48 class SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas { 49 public: 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 61 protected: 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 67 private: 68 class TrackLayerDevice; 69 }; 70 71 using SkDiscardableHandleId = uint32_t; 72 73 // This class is not thread-safe. 74 class SkStrikeServer final : public SkStrikeForGPUCacheInterface { 75 public: 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. isHandleDeleted(SkDiscardableHandleId)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 setMaxEntriesInDescriptorMapForTesting(size_t count)128 void setMaxEntriesInDescriptorMapForTesting(size_t count) { 129 fMaxEntriesInDescriptorMap = count; 130 } remoteStrikeMapSizeForTesting()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 138 private: 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 167 class SkStrikeClient { 168 public: 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 notifyCacheMiss(CacheMissType)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 }; notifyReadFailure(const ReadFailureData & data)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 222 private: 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. 235 bool SkFuzzDeserializeSkDescriptor(sk_sp<SkData> bytes, SkAutoDescriptor* ad); 236 237 #endif // SkRemoteGlyphCache_DEFINED 238