1 /*
2  * Copyright 2010 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 SkStrikeCache_DEFINED
9 #define SkStrikeCache_DEFINED
10 
11 #include <unordered_map>
12 #include <unordered_set>
13 
14 #include "SkDescriptor.h"
15 #include "SkStrike.h"
16 #include "SkSpinlock.h"
17 #include "SkTemplates.h"
18 
19 class SkStrike;
20 class SkTraceMemoryDump;
21 
22 #ifndef SK_DEFAULT_FONT_CACHE_COUNT_LIMIT
23     #define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT   2048
24 #endif
25 
26 #ifndef SK_DEFAULT_FONT_CACHE_LIMIT
27     #define SK_DEFAULT_FONT_CACHE_LIMIT     (2 * 1024 * 1024)
28 #endif
29 
30 #ifndef SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT
31     #define SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT  256
32 #endif
33 
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 class SkStrikePinner {
37 public:
38     virtual ~SkStrikePinner() = default;
39     virtual bool canDelete() = 0;
40 };
41 
42 class SkStrikeCache {
43     class Node;
44 
45 public:
46     SkStrikeCache() = default;
47     ~SkStrikeCache();
48 
49     class ExclusiveStrikePtr {
50     public:
51         explicit ExclusiveStrikePtr(Node*);
52         ExclusiveStrikePtr();
53         ExclusiveStrikePtr(const ExclusiveStrikePtr&) = delete;
54         ExclusiveStrikePtr& operator = (const ExclusiveStrikePtr&) = delete;
55         ExclusiveStrikePtr(ExclusiveStrikePtr&&);
56         ExclusiveStrikePtr& operator = (ExclusiveStrikePtr&&);
57         ~ExclusiveStrikePtr();
58 
59         SkStrike* get() const;
60         SkStrike* operator -> () const;
61         SkStrike& operator *  () const;
62         explicit operator bool () const;
63         friend bool operator == (const ExclusiveStrikePtr&, const ExclusiveStrikePtr&);
64         friend bool operator == (const ExclusiveStrikePtr&, decltype(nullptr));
65         friend bool operator == (decltype(nullptr), const ExclusiveStrikePtr&);
66 
67     private:
68         Node* fNode;
69     };
70 
71     static SkStrikeCache* GlobalStrikeCache();
72 
73     static ExclusiveStrikePtr FindStrikeExclusive(const SkDescriptor&);
74     ExclusiveStrikePtr findStrikeExclusive(const SkDescriptor&);
75     Node* findAndDetachStrike(const SkDescriptor&);
76 
77     static ExclusiveStrikePtr CreateStrikeExclusive(
78             const SkDescriptor& desc,
79             std::unique_ptr<SkScalerContext> scaler,
80             SkFontMetrics* maybeMetrics = nullptr,
81             std::unique_ptr<SkStrikePinner> = nullptr);
82 
83     ExclusiveStrikePtr createStrikeExclusive(
84             const SkDescriptor& desc,
85             std::unique_ptr<SkScalerContext> scaler,
86             SkFontMetrics* maybeMetrics = nullptr,
87             std::unique_ptr<SkStrikePinner> = nullptr);
88 
89     Node* createStrike(
90             const SkDescriptor& desc,
91             std::unique_ptr<SkScalerContext> scaler,
92             SkFontMetrics* maybeMetrics = nullptr,
93             std::unique_ptr<SkStrikePinner> = nullptr);
94 
95     static ExclusiveStrikePtr FindOrCreateStrikeExclusive(
96             const SkDescriptor& desc,
97             const SkScalerContextEffects& effects,
98             const SkTypeface& typeface);
99 
100     ExclusiveStrikePtr findOrCreateStrikeExclusive(
101             const SkDescriptor& desc,
102             const SkScalerContextEffects& effects,
103             const SkTypeface& typeface);
104 
105     Node* findOrCreateStrike(
106             const SkDescriptor& desc,
107             const SkScalerContextEffects& effects,
108             const SkTypeface& typeface);
109 
110     // Routines to find suitable data when working in a remote cache situation. These are
111     // suitable as substitutes for similar calls in SkScalerContext.
112     bool desperationSearchForImage(const SkDescriptor& desc,
113                                    SkGlyph* glyph,
114                                    SkStrike* targetCache);
115     bool desperationSearchForPath(const SkDescriptor& desc, SkGlyphID glyphID, SkPath* path);
116 
117     static ExclusiveStrikePtr FindOrCreateStrikeExclusive(
118             const SkFont& font,
119             const SkPaint& paint,
120             const SkSurfaceProps& surfaceProps,
121             SkScalerContextFlags scalerContextFlags,
122             const SkMatrix& deviceMatrix);
123 
124     Node* findOrCreateStrike(
125             const SkFont& font,
126             const SkPaint& paint,
127             const SkSurfaceProps& surfaceProps,
128             SkScalerContextFlags scalerContextFlags,
129             const SkMatrix& deviceMatrix);
130 
131     // cons up a default paint, which is only needed for patheffects/maskfilter
132     static ExclusiveStrikePtr FindOrCreateStrikeWithNoDeviceExclusive(const SkFont&);
133 
134     static ExclusiveStrikePtr FindOrCreateStrikeWithNoDeviceExclusive(const SkFont& font,
135                                                                       const SkPaint& paint);
136 
137     static std::unique_ptr<SkScalerContext> CreateScalerContext(
138             const SkDescriptor&, const SkScalerContextEffects&, const SkTypeface&);
139 
140     static void PurgeAll();
141     static void ValidateGlyphCacheDataSize();
142     static void Dump();
143 
144     // Dump memory usage statistics of all the attaches caches in the process using the
145     // SkTraceMemoryDump interface.
146     static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
147 
148     // call when a glyphcache is available for caching (i.e. not in use)
149     void attachNode(Node* node);
150 
151     void purgeAll(); // does not change budget
152 
153     int getCacheCountLimit() const;
154     int setCacheCountLimit(int limit);
155     int getCacheCountUsed() const;
156 
157     size_t getCacheSizeLimit() const;
158     size_t setCacheSizeLimit(size_t limit);
159     size_t getTotalMemoryUsed() const;
160 
161     int  getCachePointSizeLimit() const;
162     int  setCachePointSizeLimit(int limit);
163 
164 #ifdef SK_DEBUG
165     // A simple accounting of what each glyph cache reports and the strike cache total.
166     void validate() const;
167     // Make sure that each glyph cache's memory tracking and actual memory used are in sync.
168     void validateGlyphCacheDataSize() const;
169 #else
validate()170     void validate() const {}
validateGlyphCacheDataSize()171     void validateGlyphCacheDataSize() const {}
172 #endif
173 
174 private:
175 
176     // The following methods can only be called when mutex is already held.
internalGetHead()177     Node* internalGetHead() const { return fHead; }
internalGetTail()178     Node* internalGetTail() const { return fTail; }
179     void internalDetachCache(Node*);
180     void internalAttachToHead(Node*);
181 
182     // Checkout budgets, modulated by the specified min-bytes-needed-to-purge,
183     // and attempt to purge caches to match.
184     // Returns number of bytes freed.
185     size_t internalPurge(size_t minBytesNeeded = 0);
186 
187     void forEachStrike(std::function<void(const SkStrike&)> visitor) const;
188 
189     mutable SkSpinlock fLock;
190     Node*              fHead{nullptr};
191     Node*              fTail{nullptr};
192     size_t             fTotalMemoryUsed{0};
193     size_t             fCacheSizeLimit{SK_DEFAULT_FONT_CACHE_LIMIT};
194     int32_t            fCacheCountLimit{SK_DEFAULT_FONT_CACHE_COUNT_LIMIT};
195     int32_t            fCacheCount{0};
196     int32_t            fPointSizeLimit{SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT};
197 };
198 
199 using SkExclusiveStrikePtr = SkStrikeCache::ExclusiveStrikePtr;
200 
201 #endif  // SkStrikeCache_DEFINED
202