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