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