• 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 
126     /** Call proc on all cache entries, stopping early if proc returns true.
127         The proc should not create or delete caches, since it could produce
128         deadlock.
129     */
130     static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
131 
132     /** Find a matching cache entry, and call proc() with it. If none is found
133         create a new one. If the proc() returns true, detach the cache and
134         return it, otherwise leave it and return NULL.
135     */
136     static SkGlyphCache* VisitCache(const SkDescriptor* desc,
137                                     bool (*proc)(const SkGlyphCache*, void*),
138                                     void* context);
139 
140     /** Given a strike that was returned by either VisitCache() or DetachCache()
141         add it back into the global cache list (after which the caller should
142         not reference it anymore.
143     */
144     static void AttachCache(SkGlyphCache*);
145 
146     /** Detach a strike from the global cache matching the specified descriptor.
147         Once detached, it can be queried/modified by the current thread, and
148         when finished, be reattached to the global cache with AttachCache().
149         While detached, if another request is made with the same descriptor,
150         a different strike will be generated. This is fine. It does mean we
151         can have more than 1 strike for the same descriptor, but that will
152         eventually get purged, and the win is that different thread will never
153         block each other while a strike is being used.
154     */
DetachCache(const SkDescriptor * desc)155     static SkGlyphCache* DetachCache(const SkDescriptor* desc) {
156         return VisitCache(desc, DetachProc, NULL);
157     }
158 
159     /** Return the approximate number of bytes used by the font cache
160     */
161     static size_t GetCacheUsed();
162 
163     /** This can be called to purge old font data, in an attempt to free
164         enough bytes such that the font cache is not using more than the
165         specified number of bytes. It is thread-safe, and may be called at
166         any time.
167         Return true if some amount of the cache was purged.
168     */
169     static bool SetCacheUsed(size_t bytesUsed);
170 
171 #ifdef SK_DEBUG
172     void validate() const;
173 #else
validate()174     void validate() const {}
175 #endif
176 
177     class AutoValidate : SkNoncopyable {
178     public:
AutoValidate(const SkGlyphCache * cache)179         AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
180             if (fCache) {
181                 fCache->validate();
182             }
183         }
~AutoValidate()184         ~AutoValidate() {
185             if (fCache) {
186                 fCache->validate();
187             }
188         }
forget()189         void forget() {
190             fCache = NULL;
191         }
192     private:
193         const SkGlyphCache* fCache;
194     };
195 
196 private:
197     SkGlyphCache(const SkDescriptor*);
198     ~SkGlyphCache();
199 
200     enum MetricsType {
201         kJustAdvance_MetricsType,
202         kFull_MetricsType
203     };
204 
205     SkGlyph* lookupMetrics(uint32_t id, MetricsType);
DetachProc(const SkGlyphCache *,void *)206     static bool DetachProc(const SkGlyphCache*, void*) { return true; }
207 
detach(SkGlyphCache ** head)208     void detach(SkGlyphCache** head) {
209         if (fPrev) {
210             fPrev->fNext = fNext;
211         } else {
212             *head = fNext;
213         }
214         if (fNext) {
215             fNext->fPrev = fPrev;
216         }
217         fPrev = fNext = NULL;
218     }
219 
attachToHead(SkGlyphCache ** head)220     void attachToHead(SkGlyphCache** head) {
221         SkASSERT(NULL == fPrev && NULL == fNext);
222         if (*head) {
223             (*head)->fPrev = this;
224             fNext = *head;
225         }
226         *head = this;
227     }
228 
229     SkGlyphCache*       fNext, *fPrev;
230     SkDescriptor*       fDesc;
231     SkScalerContext*    fScalerContext;
232     SkPaint::FontMetrics fFontMetricsY;
233 
234     enum {
235         kHashBits   = 12,
236         kHashCount  = 1 << kHashBits,
237         kHashMask   = kHashCount - 1
238     };
239     SkGlyph*            fGlyphHash[kHashCount];
240     SkTDArray<SkGlyph*> fGlyphArray;
241     SkChunkAlloc        fGlyphAlloc;
242     SkChunkAlloc        fImageAlloc;
243 
244     int fMetricsCount, fAdvanceCount;
245 
246     struct CharGlyphRec {
247         uint32_t    fID;    // unichar + subpixel
248         SkGlyph*    fGlyph;
249     };
250     // no reason to use the same kHashCount as fGlyphHash, but we do for now
251     CharGlyphRec    fCharToGlyphHash[kHashCount];
252 
253     enum {
254         // shift so that the top bits fall into kHashBits region
255         kShiftForHashIndex = SkGlyph::kSubShift +
256                              SkGlyph::kSubBits*2 -
257                              kHashBits
258     };
259 
ID2HashIndex(uint32_t id)260     static inline unsigned ID2HashIndex(uint32_t id) {
261         return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
262     }
263 
264     // used to track (approx) how much ram is tied-up in this cache
265     size_t  fMemoryUsed;
266 
267     struct AuxProcRec {
268         AuxProcRec* fNext;
269         void (*fProc)(void*);
270         void* fData;
271     };
272     AuxProcRec* fAuxProcList;
273     void invokeAndRemoveAuxProcs();
274 
275     // This relies on the caller to have already acquired the mutex to access the global cache
276     static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
277 
278     inline static SkGlyphCache* FindTail(SkGlyphCache* head);
279     static size_t ComputeMemoryUsed(const SkGlyphCache* head);
280 
281     friend class SkGlyphCache_Globals;
282 };
283 
284 class SkAutoGlyphCache {
285 public:
SkAutoGlyphCache(SkGlyphCache * cache)286     SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
SkAutoGlyphCache(const SkDescriptor * desc)287     SkAutoGlyphCache(const SkDescriptor* desc) {
288         fCache = SkGlyphCache::DetachCache(desc);
289     }
SkAutoGlyphCache(const SkPaint & paint,const SkMatrix * matrix)290     SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix) {
291         fCache = paint.detachCache(matrix);
292     }
~SkAutoGlyphCache()293     ~SkAutoGlyphCache() {
294         if (fCache) {
295             SkGlyphCache::AttachCache(fCache);
296         }
297     }
298 
getCache()299     SkGlyphCache* getCache() const { return fCache; }
300 
release()301     void release() {
302         if (fCache) {
303             SkGlyphCache::AttachCache(fCache);
304             fCache = NULL;
305         }
306     }
307 
308 private:
309     SkGlyphCache*   fCache;
310 
311     static bool DetachProc(const SkGlyphCache*, void*);
312 };
313 
314 #endif
315 
316