Home | History | Annotate | Download | only in core
      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