3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #ifndef SkGlyphCache_DEFINED
11 #define SkGlyphCache_DEFINED
14 #include "SkChunkAlloc.h"
15 #include "SkDescriptor.h"
17 #include "SkScalerContext.h"
18 #include "SkTemplates.h"
19 #include "SkTDArray.h"
21 struct SkDeviceProperties;
24 class SkGlyphCache_Globals;
26 /** \class SkGlyphCache
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 cached, or by first generating it and then
32 adding it to the strike.
34 The strikes are held in a global list, available to all threads. To interact
35 with one, call either VisitCache() or DetachCache().
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.
43 const SkGlyph& getUnicharAdvance(SkUnichar);
44 const SkGlyph& getGlyphIDAdvance(uint16_t);
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.
50 This call is potentially slower than the matching ...Advance call. If
51 you only need the fAdvance/fDevKern fields, call those instead.
53 const SkGlyph& getUnicharMetrics(SkUnichar);
54 const SkGlyph& getGlyphIDMetrics(uint16_t);
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
61 const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
62 const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
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
68 uint16_t unicharToGlyph(SkUnichar);
70 /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
71 a character code of zero.
73 SkUnichar glyphToUnichar(uint16_t);
75 /** Returns the number of glyphs for this strike.
77 unsigned getGlyphCount();
79 /** Return the image associated with the glyph. If it has not been generated
80 this will trigger that.
82 const void* findImage(const SkGlyph&);
83 /** Return the Path associated with the glyph. If it has not been generated
84 this will trigger that.
86 const SkPath* findPath(const SkGlyph&);
87 /** Return the distance field associated with the glyph. If it has not been generated
88 this will trigger that.
90 const void* findDistanceField(const SkGlyph&);
92 /** Return the vertical metrics for this strike.
94 const SkPaint::FontMetrics& getFontMetrics() const {
98 const SkDescriptor& getDescriptor() const { return *fDesc; }
100 SkMask::Format getMaskFormat() const {
101 return fScalerContext->getMaskFormat();
104 bool isSubpixel() const {
105 return fScalerContext->isSubpixel();
108 /* AuxProc/Data allow a client to associate data with this cache entry.
109 Multiple clients can use this, as their data is keyed with a function
110 pointer. In addition to serving as a key, the function pointer is called
111 with the data when the glyphcache object is deleted, so the client can
112 cleanup their data as well. NOTE: the auxProc must not try to access
113 this glyphcache in any way, since it may be in the process of being
117 //! If the proc is found, return true and set *dataPtr to its data
118 bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
119 //! Add a proc/data pair to the glyphcache. proc should be non-null
120 void setAuxProc(void (*auxProc)(void*), void* auxData);
122 SkScalerContext* getScalerContext() const { return fScalerContext; }
124 /** Find a matching cache entry, and call proc() with it. If none is found
125 create a new one. If the proc() returns true, detach the cache and
126 return it, otherwise leave it and return NULL.
128 static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc,
129 bool (*proc)(const SkGlyphCache*, void*),
132 /** Given a strike that was returned by either VisitCache() or DetachCache()
133 add it back into the global cache list (after which the caller should
134 not reference it anymore.
136 static void AttachCache(SkGlyphCache*);
138 /** Detach a strike from the global cache matching the specified descriptor.
139 Once detached, it can be queried/modified by the current thread, and
140 when finished, be reattached to the global cache with AttachCache().
141 While detached, if another request is made with the same descriptor,
142 a different strike will be generated. This is fine. It does mean we
143 can have more than 1 strike for the same descriptor, but that will
144 eventually get purged, and the win is that different thread will never
145 block each other while a strike is being used.
147 static SkGlyphCache* DetachCache(SkTypeface* typeface,
148 const SkDescriptor* desc) {
149 return VisitCache(typeface, desc, DetachProc, NULL);
153 void validate() const;
155 void validate() const {}
158 class AutoValidate : SkNoncopyable {
160 AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
174 const SkGlyphCache* fCache;
178 // we take ownership of the scalercontext
179 SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*);
183 kJustAdvance_MetricsType,
187 SkGlyph* lookupMetrics(uint32_t id, MetricsType);
188 static bool DetachProc(const SkGlyphCache*, void*) { return true; }
190 SkGlyphCache* fNext, *fPrev;
192 SkScalerContext* fScalerContext;
193 SkPaint::FontMetrics fFontMetrics;
197 kHashCount = 1 << kHashBits,
198 kHashMask = kHashCount - 1
200 SkGlyph* fGlyphHash[kHashCount];
201 SkTDArray<SkGlyph*> fGlyphArray;
202 SkChunkAlloc fGlyphAlloc;
204 struct CharGlyphRec {
205 uint32_t fID; // unichar + subpixel
208 // no reason to use the same kHashCount as fGlyphHash, but we do for now
209 CharGlyphRec fCharToGlyphHash[kHashCount];
211 static inline unsigned ID2HashIndex(uint32_t id) {
214 return id & kHashMask;
217 // used to track (approx) how much ram is tied-up in this cache
222 void (*fProc)(void*);
225 AuxProcRec* fAuxProcList;
226 void invokeAndRemoveAuxProcs();
228 inline static SkGlyphCache* FindTail(SkGlyphCache* head);
230 friend class SkGlyphCache_Globals;
233 class SkAutoGlyphCacheBase {
235 SkGlyphCache* getCache() const { return fCache; }
239 SkGlyphCache::AttachCache(fCache);
245 // Hide the constructors so we can't create one of these directly.
246 // Create SkAutoGlyphCache or SkAutoGlyphCacheNoCache instead.
247 SkAutoGlyphCacheBase(SkGlyphCache* cache) : fCache(cache) {}
248 SkAutoGlyphCacheBase(SkTypeface* typeface, const SkDescriptor* desc) {
249 fCache = SkGlyphCache::DetachCache(typeface, desc);
251 SkAutoGlyphCacheBase(const SkPaint& paint,
252 const SkDeviceProperties* deviceProperties,
253 const SkMatrix* matrix) {
256 SkAutoGlyphCacheBase() {
259 ~SkAutoGlyphCacheBase() {
261 SkGlyphCache::AttachCache(fCache);
265 SkGlyphCache* fCache;
268 static bool DetachProc(const SkGlyphCache*, void*);
271 class SkAutoGlyphCache : public SkAutoGlyphCacheBase {
273 SkAutoGlyphCache(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {}
274 SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) :
275 SkAutoGlyphCacheBase(typeface, desc) {}
276 SkAutoGlyphCache(const SkPaint& paint,
277 const SkDeviceProperties* deviceProperties,
278 const SkMatrix* matrix) {
279 fCache = paint.detachCache(deviceProperties, matrix, false);
283 SkAutoGlyphCache() : SkAutoGlyphCacheBase() {}
285 #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache)
287 class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCacheBase {
289 SkAutoGlyphCacheNoGamma(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {}
290 SkAutoGlyphCacheNoGamma(SkTypeface* typeface, const SkDescriptor* desc) :
291 SkAutoGlyphCacheBase(typeface, desc) {}
292 SkAutoGlyphCacheNoGamma(const SkPaint& paint,
293 const SkDeviceProperties* deviceProperties,
294 const SkMatrix* matrix) {
295 fCache = paint.detachCache(deviceProperties, matrix, true);
299 SkAutoGlyphCacheNoGamma() : SkAutoGlyphCacheBase() {}
301 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma)