• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #ifndef SkGlyphCache_DEFINED
11 #define SkGlyphCache_DEFINED
12 
13 #include "SkBitmap.h"
14 #include "SkChunkAlloc.h"
15 #include "SkDescriptor.h"
16 #include "SkScalerContext.h"
17 #include "SkTemplates.h"
18 
19 class SkPaint;
20 
21 class SkGlyphCache_Globals;
22 
23 /** \class SkGlyphCache
24 
25     This class represents a strike: a specific combination of typeface, size,
26     matrix, etc., and holds the glyphs for that strike. Calling any of the
27     getUnichar.../getGlyphID... methods will return the requested glyph,
28     either instantly if it is already cahced, or by first generating it and then
29     adding it to the strike.
30 
31     The strikes are held in a global list, available to all threads. To interact
32     with one, call either VisitCache() or DetachCache().
33 */
34 class SkGlyphCache {
35 public:
36     /** Returns a glyph with valid fAdvance and fDevKern fields.
37         The remaining fields may be valid, but that is not guaranteed. If you
38         require those, call getUnicharMetrics or 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
44         may be null. If they are null, call findImage or findPath for those.
45         If they are not null, then they are valid.
46 
47         This call is potentially slower than the matching ...Advance call. If
48         you only need the fAdvance/fDevKern fields, call those instead.
49     */
50     const SkGlyph& getUnicharMetrics(SkUnichar);
51     const SkGlyph& getGlyphIDMetrics(uint16_t);
52 
53     /** These are variants that take the device position of the glyph. Call
54         these only if you are drawing in subpixel mode. Passing 0, 0 is
55         effectively the same as calling the variants w/o the extra params, tho
56         a tiny bit slower.
57     */
58     const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
59     const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
60 
61     /** Return the glyphID for the specified Unichar. If the char has already
62         been seen, use the existing cache entry. If not, ask the scalercontext
63         to compute it for us.
64     */
65     uint16_t unicharToGlyph(SkUnichar);
66 
67     /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
68         a character code of zero.
69     */
70     SkUnichar glyphToUnichar(uint16_t);
71 
72     /** Returns the number of glyphs for this strike.
73     */
74     unsigned getGlyphCount();
75 
76 #ifdef SK_BUILD_FOR_ANDROID
77     /** Returns the base glyph count for this strike.
78     */
getBaseGlyphCount(SkUnichar charCode)79     unsigned getBaseGlyphCount(SkUnichar charCode) const {
80         return fScalerContext->getBaseGlyphCount(charCode);
81     }
82 #endif
83 
84     /** Return the image associated with the glyph. If it has not been generated
85         this will trigger that.
86     */
87     const void* findImage(const SkGlyph&);
88     /** Return the Path associated with the glyph. If it has not been generated
89         this will trigger that.
90     */
91     const SkPath* findPath(const SkGlyph&);
92 
93     /** Return the vertical metrics for this strike.
94     */
getFontMetricsY()95     const SkPaint::FontMetrics& getFontMetricsY() const {
96         return fFontMetricsY;
97     }
98 
getDescriptor()99     const SkDescriptor& getDescriptor() const { return *fDesc; }
100 
getMaskFormat()101     SkMask::Format getMaskFormat() const {
102         return fScalerContext->getMaskFormat();
103     }
104 
isSubpixel()105     bool isSubpixel() const {
106         return fScalerContext->isSubpixel();
107     }
108 
109     /*  AuxProc/Data allow a client to associate data with this cache entry.
110         Multiple clients can use this, as their data is keyed with a function
111         pointer. In addition to serving as a key, the function pointer is called
112         with the data when the glyphcache object is deleted, so the client can
113         cleanup their data as well. NOTE: the auxProc must not try to access
114         this glyphcache in any way, since it may be in the process of being
115         deleted.
116     */
117 
118     //! If the proc is found, return true and set *dataPtr to its data
119     bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
120     //! Add a proc/data pair to the glyphcache. proc should be non-null
121     void setAuxProc(void (*auxProc)(void*), void* auxData);
122     //! If found, remove the proc/data pair from the glyphcache (does not
123     //  call the proc)
124     void removeAuxProc(void (*auxProc)(void*));
125 
getScalerContext()126     SkScalerContext* getScalerContext() const { return fScalerContext; }
127 
128     /** Call proc on all cache entries, stopping early if proc returns true.
129         The proc should not create or delete caches, since it could produce
130         deadlock.
131     */
132     static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
133 
134     /** Find a matching cache entry, and call proc() with it. If none is found
135         create a new one. If the proc() returns true, detach the cache and
136         return it, otherwise leave it and return NULL.
137     */
138     static SkGlyphCache* VisitCache(const SkDescriptor* desc,
139                                     bool (*proc)(const SkGlyphCache*, void*),
140                                     void* context);
141 
142     /** Given a strike that was returned by either VisitCache() or DetachCache()
143         add it back into the global cache list (after which the caller should
144         not reference it anymore.
145     */
146     static void AttachCache(SkGlyphCache*);
147 
148     /** Detach a strike from the global cache matching the specified descriptor.
149         Once detached, it can be queried/modified by the current thread, and
150         when finished, be reattached to the global cache with AttachCache().
151         While detached, if another request is made with the same descriptor,
152         a different strike will be generated. This is fine. It does mean we
153         can have more than 1 strike for the same descriptor, but that will
154         eventually get purged, and the win is that different thread will never
155         block each other while a strike is being used.
156     */
DetachCache(const SkDescriptor * desc)157     static SkGlyphCache* DetachCache(const SkDescriptor* desc) {
158         return VisitCache(desc, DetachProc, NULL);
159     }
160 
161     /** Return the approximate number of bytes used by the font cache
162     */
163     static size_t GetCacheUsed();
164 
165     /** This can be called to purge old font data, in an attempt to free
166         enough bytes such that the font cache is not using more than the
167         specified number of bytes. It is thread-safe, and may be called at
168         any time.
169         Return true if some amount of the cache was purged.
170     */
171     static bool SetCacheUsed(size_t bytesUsed);
172 
173 #ifdef SK_DEBUG
174     void validate() const;
175 #else
validate()176     void validate() const {}
177 #endif
178 
179     class AutoValidate : SkNoncopyable {
180     public:
AutoValidate(const SkGlyphCache * cache)181         AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
182             if (fCache) {
183                 fCache->validate();
184             }
185         }
~AutoValidate()186         ~AutoValidate() {
187             if (fCache) {
188                 fCache->validate();
189             }
190         }
forget()191         void forget() {
192             fCache = NULL;
193         }
194     private:
195         const SkGlyphCache* fCache;
196     };
197 
198 private:
199     SkGlyphCache(const SkDescriptor*);
200     ~SkGlyphCache();
201 
202     enum MetricsType {
203         kJustAdvance_MetricsType,
204         kFull_MetricsType
205     };
206 
207     SkGlyph* lookupMetrics(uint32_t id, MetricsType);
DetachProc(const SkGlyphCache *,void *)208     static bool DetachProc(const SkGlyphCache*, void*) { return true; }
209 
detach(SkGlyphCache ** head)210     void detach(SkGlyphCache** head) {
211         if (fPrev) {
212             fPrev->fNext = fNext;
213         } else {
214             *head = fNext;
215         }
216         if (fNext) {
217             fNext->fPrev = fPrev;
218         }
219         fPrev = fNext = NULL;
220     }
221 
attachToHead(SkGlyphCache ** head)222     void attachToHead(SkGlyphCache** head) {
223         SkASSERT(NULL == fPrev && NULL == fNext);
224         if (*head) {
225             (*head)->fPrev = this;
226             fNext = *head;
227         }
228         *head = this;
229     }
230 
231     SkGlyphCache*       fNext, *fPrev;
232     SkDescriptor*       fDesc;
233     SkScalerContext*    fScalerContext;
234     SkPaint::FontMetrics fFontMetricsY;
235 
236     enum {
237         kHashBits   = 12,
238         kHashCount  = 1 << kHashBits,
239         kHashMask   = kHashCount - 1
240     };
241     SkGlyph*            fGlyphHash[kHashCount];
242     SkTDArray<SkGlyph*> fGlyphArray;
243     SkChunkAlloc        fGlyphAlloc;
244     SkChunkAlloc        fImageAlloc;
245 
246     int fMetricsCount, fAdvanceCount;
247 
248     struct CharGlyphRec {
249         uint32_t    fID;    // unichar + subpixel
250         SkGlyph*    fGlyph;
251     };
252     // no reason to use the same kHashCount as fGlyphHash, but we do for now
253     CharGlyphRec    fCharToGlyphHash[kHashCount];
254 
255     enum {
256         // shift so that the top bits fall into kHashBits region
257         kShiftForHashIndex = SkGlyph::kSubShift +
258                              SkGlyph::kSubBits*2 -
259                              kHashBits
260     };
261 
ID2HashIndex(uint32_t id)262     static inline unsigned ID2HashIndex(uint32_t id) {
263         return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
264     }
265 
266     // used to track (approx) how much ram is tied-up in this cache
267     size_t  fMemoryUsed;
268 
269     struct AuxProcRec {
270         AuxProcRec* fNext;
271         void (*fProc)(void*);
272         void* fData;
273     };
274     AuxProcRec* fAuxProcList;
275     void invokeAndRemoveAuxProcs();
276 
277     // This relies on the caller to have already acquired the mutex to access the global cache
278     static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
279 
280     inline static SkGlyphCache* FindTail(SkGlyphCache* head);
281     static size_t ComputeMemoryUsed(const SkGlyphCache* head);
282 
283     friend class SkGlyphCache_Globals;
284 };
285 
286 class SkAutoGlyphCache {
287 public:
SkAutoGlyphCache(SkGlyphCache * cache)288     SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
SkAutoGlyphCache(const SkDescriptor * desc)289     SkAutoGlyphCache(const SkDescriptor* desc) {
290         fCache = SkGlyphCache::DetachCache(desc);
291     }
SkAutoGlyphCache(const SkPaint & paint,const SkMatrix * matrix)292     SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix) {
293         fCache = paint.detachCache(matrix);
294     }
~SkAutoGlyphCache()295     ~SkAutoGlyphCache() {
296         if (fCache) {
297             SkGlyphCache::AttachCache(fCache);
298         }
299     }
300 
getCache()301     SkGlyphCache* getCache() const { return fCache; }
302 
release()303     void release() {
304         if (fCache) {
305             SkGlyphCache::AttachCache(fCache);
306             fCache = NULL;
307         }
308     }
309 
310 private:
311     SkGlyphCache*   fCache;
312 
313     static bool DetachProc(const SkGlyphCache*, void*);
314 };
315 
316 #endif
317 
318