1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
5  */
6 
7 #ifndef SkGlyphCache_DEFINED
8 #define SkGlyphCache_DEFINED
9 
10 #include "SkArenaAlloc.h"
11 #include "SkBitmap.h"
12 #include "SkDescriptor.h"
13 #include "SkGlyph.h"
14 #include "SkPaint.h"
15 #include "SkTHash.h"
16 #include "SkScalerContext.h"
17 #include "SkTemplates.h"
18 #include "SkTDArray.h"
19 #include <memory>
20 
21 class SkTraceMemoryDump;
22 
23 class SkGlyphCache_Globals;
24 
25 /** \class SkGlyphCache
26 
27     This class represents a strike: a specific combination of typeface, size, matrix, etc., and
28     holds the glyphs for that strike. Calling any of the getUnichar.../getGlyphID... methods will
29     return the requested glyph, either instantly if it is already cached, or by first generating
30     it and then adding it to the strike.
31 
32     The strikes are held in a global list, available to all threads. To interact with one, call
33     either VisitCache() or DetachCache().
34 */
35 class SkGlyphCache {
36 public:
37     /** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be
38         valid, but that is not guaranteed. If you require those, call getUnicharMetrics or
39         getGlyphIDMetrics instead.
40     */
41     const SkGlyph& getUnicharAdvance(SkUnichar);
42     const SkGlyph& getGlyphIDAdvance(SkGlyphID);
43 
44     /** Returns a glyph with all fields valid except fImage and fPath, which may be null. If they
45         are null, call findImage or findPath for those. If they are not null, then they are valid.
46 
47         This call is potentially slower than the matching ...Advance call. If you only need the
48         fAdvance/fDevKern fields, call those instead.
49     */
50     const SkGlyph& getUnicharMetrics(SkUnichar);
51     const SkGlyph& getGlyphIDMetrics(SkGlyphID);
52 
53     /** These are variants that take the device position of the glyph. Call these only if you are
54         drawing in subpixel mode. Passing 0, 0 is effectively the same as calling the variants
55         w/o the extra params, though a tiny bit slower.
56     */
57     const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
58     const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
59 
60     /** Return the glyphID for the specified Unichar. If the char has already been seen, use the
61         existing cache entry. If not, ask the scalercontext to compute it for us.
62     */
63     SkGlyphID unicharToGlyph(SkUnichar);
64 
65     /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to a character code of zero.
66     */
67     SkUnichar glyphToUnichar(SkGlyphID);
68 
69     /** Returns the number of glyphs for this strike.
70     */
71     unsigned getGlyphCount() const;
72 
73     /** Return the number of glyphs currently cached. */
74     int countCachedGlyphs() const;
75 
76     /** Return the image associated with the glyph. If it has not been generated this will
77         trigger that.
78     */
79     const void* findImage(const SkGlyph&);
80 
81     /** If the advance axis intersects the glyph's path, append the positions scaled and offset
82         to the array (if non-null), and set the count to the updated array length.
83     */
84     void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
85                         bool yAxis, SkGlyph* , SkScalar* array, int* count);
86 
87     /** Return the Path associated with the glyph. If it has not been generated this will trigger
88         that.
89     */
90     const SkPath* findPath(const SkGlyph&);
91 
92     /** Return the vertical metrics for this strike.
93     */
getFontMetrics()94     const SkPaint::FontMetrics& getFontMetrics() const {
95         return fFontMetrics;
96     }
97 
getDescriptor()98     const SkDescriptor& getDescriptor() const { return *fDesc; }
99 
getMaskFormat()100     SkMask::Format getMaskFormat() const {
101         return fScalerContext->getMaskFormat();
102     }
103 
isSubpixel()104     bool isSubpixel() const {
105         return fScalerContext->isSubpixel();
106     }
107 
108     /** Return the approx RAM usage for this cache. */
getMemoryUsed()109     size_t getMemoryUsed() const { return fMemoryUsed; }
110 
111     void dump() const;
112 
getScalerContext()113     SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
114 
115     /** Find a matching cache entry, and call proc() with it. If none is found create a new one.
116         If the proc() returns true, detach the cache and return it, otherwise leave it and return
117         nullptr.
118     */
119     static SkGlyphCache* VisitCache(SkTypeface*, const SkScalerContextEffects&, const SkDescriptor*,
120                                     bool (*proc)(const SkGlyphCache*, void*),
121                                     void* context);
122 
123     /** Given a strike that was returned by either VisitCache() or DetachCache() add it back into
124         the global cache list (after which the caller should not reference it anymore.
125     */
126     static void AttachCache(SkGlyphCache*);
127     using AttachCacheFunctor = SkFunctionWrapper<void, SkGlyphCache, AttachCache>;
128 
129     /** Detach a strike from the global cache matching the specified descriptor. Once detached,
130         it can be queried/modified by the current thread, and when finished, be reattached to the
131         global cache with AttachCache(). While detached, if another request is made with the same
132         descriptor, a different strike will be generated. This is fine. It does mean we can have
133         more than 1 strike for the same descriptor, but that will eventually get purged, and the
134         win is that different thread will never block each other while a strike is being used.
135     */
DetachCache(SkTypeface * typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)136     static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkScalerContextEffects& effects,
137                                      const SkDescriptor* desc) {
138         return VisitCache(typeface, effects, desc, DetachProc, nullptr);
139     }
140 
141     static void Dump();
142 
143     /** Dump memory usage statistics of all the attaches caches in the process using the
144         SkTraceMemoryDump interface.
145     */
146     static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
147 
148     typedef void (*Visitor)(const SkGlyphCache&, void* context);
149     static void VisitAll(Visitor, void* context);
150 
151 #ifdef SK_DEBUG
152     void validate() const;
153 #else
validate()154     void validate() const {}
155 #endif
156 
157     class AutoValidate : SkNoncopyable {
158     public:
AutoValidate(const SkGlyphCache * cache)159         AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
160             if (fCache) {
161                 fCache->validate();
162             }
163         }
~AutoValidate()164         ~AutoValidate() {
165             if (fCache) {
166                 fCache->validate();
167             }
168         }
forget()169         void forget() {
170             fCache = nullptr;
171         }
172     private:
173         const SkGlyphCache* fCache;
174     };
175 
176 private:
177     friend class SkGlyphCache_Globals;
178 
179     enum MetricsType {
180         kJustAdvance_MetricsType,
181         kFull_MetricsType
182     };
183 
184     enum {
185         kHashBits           = 8,
186         kHashCount          = 1 << kHashBits,
187         kHashMask           = kHashCount - 1
188     };
189 
190     struct CharGlyphRec {
191         SkPackedUnicharID fPackedUnicharID;
192         SkPackedGlyphID fPackedGlyphID;
193     };
194 
195     SkGlyphCache(const SkDescriptor*, std::unique_ptr<SkScalerContext>);
196     ~SkGlyphCache();
197 
198     // Return the SkGlyph* associated with MakeID. The id parameter is the
199     // combined glyph/x/y id generated by MakeID. If it is just a glyph id
200     // then x and y are assumed to be zero.
201     SkGlyph* lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, MetricsType type);
202 
203     // Return a SkGlyph* associated with unicode id and position x and y.
204     SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed y = 0);
205 
206     // Return a new SkGlyph for the glyph ID and subpixel position id. Limit the amount
207     // of work using type.
208     SkGlyph* allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsType type);
209 
DetachProc(const SkGlyphCache *,void *)210     static bool DetachProc(const SkGlyphCache*, void*) { return true; }
211 
212     // The id arg is a combined id generated by MakeID.
213     CharGlyphRec* getCharGlyphRec(SkPackedUnicharID id);
214 
215     static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale,
216                               SkScalar xPos, SkScalar* array, int* count);
217     static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept);
218     static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2],
219                           bool yAxis, SkGlyph::Intercept* intercept);
220     static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis,
221                         SkGlyph::Intercept* intercept);
222     static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis,
223                         SkGlyph::Intercept* intercept);
224     static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis,
225                          SkGlyph::Intercept* intercept);
226     static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph,
227                                                  const SkScalar bounds[2]);
228 
229     SkGlyphCache*          fNext;
230     SkGlyphCache*          fPrev;
231     const std::unique_ptr<SkDescriptor> fDesc;
232     const std::unique_ptr<SkScalerContext> fScalerContext;
233     SkPaint::FontMetrics   fFontMetrics;
234 
235     // Map from a combined GlyphID and sub-pixel position to a SkGlyph.
236     SkTHashTable<SkGlyph, SkPackedGlyphID, SkGlyph::HashTraits> fGlyphMap;
237 
238     // so we don't grow our arrays a lot
239     static constexpr size_t kMinGlyphCount = 8;
240     static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
241     static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
242 
243     SkArenaAlloc            fAlloc {kMinAllocAmount};
244 
245     std::unique_ptr<CharGlyphRec[]> fPackedUnicharIDToPackedGlyphID;
246 
247     // used to track (approx) how much ram is tied-up in this cache
248     size_t                  fMemoryUsed;
249 };
250 
251 class SkAutoGlyphCache : public std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor> {
252 public:
253     /** deprecated: use get() */
getCache()254     SkGlyphCache* getCache() const { return this->get(); }
255     SkAutoGlyphCache() = default;
SkAutoGlyphCache(SkGlyphCache * cache)256     SkAutoGlyphCache(SkGlyphCache* cache) : INHERITED(cache) {}
SkAutoGlyphCache(SkTypeface * typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)257     SkAutoGlyphCache(SkTypeface* typeface, const SkScalerContextEffects& effects,
258                      const SkDescriptor* desc)
259         : INHERITED(SkGlyphCache::DetachCache(typeface, effects, desc))
260     {}
261     /** deprecated: always enables fake gamma */
SkAutoGlyphCache(const SkPaint & paint,const SkSurfaceProps * surfaceProps,const SkMatrix * matrix)262     SkAutoGlyphCache(const SkPaint& paint,
263                      const SkSurfaceProps* surfaceProps,
264                      const SkMatrix* matrix)
265         : INHERITED(paint.detachCache(surfaceProps,
266                                       SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags,
267                                       matrix))
268     {}
SkAutoGlyphCache(const SkPaint & paint,const SkSurfaceProps * surfaceProps,uint32_t scalerContextFlags,const SkMatrix * matrix)269     SkAutoGlyphCache(const SkPaint& paint,
270                      const SkSurfaceProps* surfaceProps,
271                      uint32_t scalerContextFlags,
272                      const SkMatrix* matrix)
273         : INHERITED(paint.detachCache(surfaceProps, scalerContextFlags, matrix))
274     {}
275 private:
276     using INHERITED = std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor>;
277 };
278 
279 class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCache {
280 public:
SkAutoGlyphCacheNoGamma(const SkPaint & paint,const SkSurfaceProps * surfaceProps,const SkMatrix * matrix)281     SkAutoGlyphCacheNoGamma(const SkPaint& paint,
282                             const SkSurfaceProps* surfaceProps,
283                             const SkMatrix* matrix)
284         : SkAutoGlyphCache(paint, surfaceProps, SkPaint::kNone_ScalerContextFlags, matrix)
285     {}
286 };
287 #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache)
288 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma)
289 
290 #endif
291