• 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 "SkGlyph.h"
17 #include "SkScalerContext.h"
18 #include "SkTemplates.h"
19 #include "SkTDArray.h"
20 
21 struct SkDeviceProperties;
22 class SkPaint;
23 
24 class SkGlyphCache_Globals;
25 
26 /** \class SkGlyphCache
27 
28     This class represents a strike: a specific combination of typeface, size,
29     matrix, etc., and holds the glyphs for that strike. Calling any of the
30     getUnichar.../getGlyphID... methods will return the requested glyph,
31     either instantly if it is already cahced, or by first generating it and then
32     adding it to the strike.
33 
34     The strikes are held in a global list, available to all threads. To interact
35     with one, call either VisitCache() or DetachCache().
36 */
37 class SkGlyphCache {
38 public:
39     /** Returns a glyph with valid fAdvance and fDevKern fields.
40         The remaining fields may be valid, but that is not guaranteed. If you
41         require those, call getUnicharMetrics or getGlyphIDMetrics instead.
42     */
43     const SkGlyph& getUnicharAdvance(SkUnichar);
44     const SkGlyph& getGlyphIDAdvance(uint16_t);
45 
46     /** Returns a glyph with all fields valid except fImage and fPath, which
47         may be null. If they are null, call findImage or findPath for those.
48         If they are not null, then they are valid.
49 
50         This call is potentially slower than the matching ...Advance call. If
51         you only need the fAdvance/fDevKern fields, call those instead.
52     */
53     const SkGlyph& getUnicharMetrics(SkUnichar);
54     const SkGlyph& getGlyphIDMetrics(uint16_t);
55 
56     /** These are variants that take the device position of the glyph. Call
57         these only if you are drawing in subpixel mode. Passing 0, 0 is
58         effectively the same as calling the variants w/o the extra params, tho
59         a tiny bit slower.
60     */
61     const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
62     const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
63 
64     /** Return the glyphID for the specified Unichar. If the char has already
65         been seen, use the existing cache entry. If not, ask the scalercontext
66         to compute it for us.
67     */
68     uint16_t unicharToGlyph(SkUnichar);
69 
70     /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
71         a character code of zero.
72     */
73     SkUnichar glyphToUnichar(uint16_t);
74 
75     /** Returns the number of glyphs for this strike.
76     */
77     unsigned getGlyphCount();
78 
79 #ifdef SK_BUILD_FOR_ANDROID
80     /** Returns the base glyph count for this strike.
81     */
getBaseGlyphCount(SkUnichar charCode)82     unsigned getBaseGlyphCount(SkUnichar charCode) const {
83         return fScalerContext->getBaseGlyphCount(charCode);
84     }
85 #endif
86 
87     /** Return the image associated with the glyph. If it has not been generated
88         this will trigger that.
89     */
90     const void* findImage(const SkGlyph&);
91     /** Return the Path associated with the glyph. If it has not been generated
92         this will trigger that.
93     */
94     const SkPath* findPath(const SkGlyph&);
95 
96     /** Return the vertical metrics for this strike.
97     */
getFontMetricsY()98     const SkPaint::FontMetrics& getFontMetricsY() const {
99         return fFontMetricsY;
100     }
101 
getDescriptor()102     const SkDescriptor& getDescriptor() const { return *fDesc; }
103 
getMaskFormat()104     SkMask::Format getMaskFormat() const {
105         return fScalerContext->getMaskFormat();
106     }
107 
isSubpixel()108     bool isSubpixel() const {
109         return fScalerContext->isSubpixel();
110     }
111 
112     /*  AuxProc/Data allow a client to associate data with this cache entry.
113         Multiple clients can use this, as their data is keyed with a function
114         pointer. In addition to serving as a key, the function pointer is called
115         with the data when the glyphcache object is deleted, so the client can
116         cleanup their data as well. NOTE: the auxProc must not try to access
117         this glyphcache in any way, since it may be in the process of being
118         deleted.
119     */
120 
121     //! If the proc is found, return true and set *dataPtr to its data
122     bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
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     /** 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 #ifdef SK_DEBUG
162     void validate() const;
163 #else
validate()164     void validate() const {}
165 #endif
166 
167     class AutoValidate : SkNoncopyable {
168     public:
AutoValidate(const SkGlyphCache * cache)169         AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
170             if (fCache) {
171                 fCache->validate();
172             }
173         }
~AutoValidate()174         ~AutoValidate() {
175             if (fCache) {
176                 fCache->validate();
177             }
178         }
forget()179         void forget() {
180             fCache = NULL;
181         }
182     private:
183         const SkGlyphCache* fCache;
184     };
185 
186 private:
187     SkGlyphCache(const SkDescriptor*);
188     ~SkGlyphCache();
189 
190     enum MetricsType {
191         kJustAdvance_MetricsType,
192         kFull_MetricsType
193     };
194 
195     SkGlyph* lookupMetrics(uint32_t id, MetricsType);
DetachProc(const SkGlyphCache *,void *)196     static bool DetachProc(const SkGlyphCache*, void*) { return true; }
197 
detach(SkGlyphCache ** head)198     void detach(SkGlyphCache** head) {
199         if (fPrev) {
200             fPrev->fNext = fNext;
201         } else {
202             *head = fNext;
203         }
204         if (fNext) {
205             fNext->fPrev = fPrev;
206         }
207         fPrev = fNext = NULL;
208     }
209 
attachToHead(SkGlyphCache ** head)210     void attachToHead(SkGlyphCache** head) {
211         SkASSERT(NULL == fPrev && NULL == fNext);
212         if (*head) {
213             (*head)->fPrev = this;
214             fNext = *head;
215         }
216         *head = this;
217     }
218 
219     SkGlyphCache*       fNext, *fPrev;
220     SkDescriptor*       fDesc;
221     SkScalerContext*    fScalerContext;
222     SkPaint::FontMetrics fFontMetricsY;
223 
224     enum {
225         kHashBits   = 12,
226         kHashCount  = 1 << kHashBits,
227         kHashMask   = kHashCount - 1
228     };
229     SkGlyph*            fGlyphHash[kHashCount];
230     SkTDArray<SkGlyph*> fGlyphArray;
231     SkChunkAlloc        fGlyphAlloc;
232     SkChunkAlloc        fImageAlloc;
233 
234     int fMetricsCount, fAdvanceCount;
235 
236     struct CharGlyphRec {
237         uint32_t    fID;    // unichar + subpixel
238         SkGlyph*    fGlyph;
239     };
240     // no reason to use the same kHashCount as fGlyphHash, but we do for now
241     CharGlyphRec    fCharToGlyphHash[kHashCount];
242 
243     enum {
244         // shift so that the top bits fall into kHashBits region
245         kShiftForHashIndex = SkGlyph::kSubShift +
246                              SkGlyph::kSubBits*2 -
247                              kHashBits
248     };
249 
ID2HashIndex(uint32_t id)250     static inline unsigned ID2HashIndex(uint32_t id) {
251         return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
252     }
253 
254     // used to track (approx) how much ram is tied-up in this cache
255     size_t  fMemoryUsed;
256 
257     struct AuxProcRec {
258         AuxProcRec* fNext;
259         void (*fProc)(void*);
260         void* fData;
261     };
262     AuxProcRec* fAuxProcList;
263     void invokeAndRemoveAuxProcs();
264 
265     // This relies on the caller to have already acquired the mutex to access the global cache
266     static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
267 
268     inline static SkGlyphCache* FindTail(SkGlyphCache* head);
269 
270     friend class SkGlyphCache_Globals;
271 };
272 
273 class SkAutoGlyphCache {
274 public:
SkAutoGlyphCache(SkGlyphCache * cache)275     SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
SkAutoGlyphCache(const SkDescriptor * desc)276     SkAutoGlyphCache(const SkDescriptor* desc) {
277         fCache = SkGlyphCache::DetachCache(desc);
278     }
SkAutoGlyphCache(const SkPaint & paint,const SkDeviceProperties * deviceProperties,const SkMatrix * matrix)279     SkAutoGlyphCache(const SkPaint& paint,
280                      const SkDeviceProperties* deviceProperties,
281                      const SkMatrix* matrix) {
282         fCache = paint.detachCache(deviceProperties, matrix);
283     }
~SkAutoGlyphCache()284     ~SkAutoGlyphCache() {
285         if (fCache) {
286             SkGlyphCache::AttachCache(fCache);
287         }
288     }
289 
getCache()290     SkGlyphCache* getCache() const { return fCache; }
291 
release()292     void release() {
293         if (fCache) {
294             SkGlyphCache::AttachCache(fCache);
295             fCache = NULL;
296         }
297     }
298 
299 private:
300     SkGlyphCache*   fCache;
301 
302     static bool DetachProc(const SkGlyphCache*, void*);
303 };
304 
305 #endif
306