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