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