blob: 92e3795cf852ada051a3b121c76a664ca6d00118 [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**
reed@google.com98539c62011-03-15 15:40:16 +00005** 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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008**
reed@google.com98539c62011-03-15 15:40:16 +00009** http://www.apache.org/licenses/LICENSE-2.0
reed@android.com8a1c16f2008-12-17 15:59:43 +000010**
reed@google.com98539c62011-03-15 15:40:16 +000011** 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
reed@android.com8a1c16f2008-12-17 15:59:43 +000015** 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);
reed@google.com98539c62011-03-15 15:40:16 +000050
reed@android.com8a1c16f2008-12-17 15:59:43 +000051 /** 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.
reed@google.com98539c62011-03-15 15:40:16 +000054
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 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);
reed@google.com98539c62011-03-15 15:40:16 +000060
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 /** 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);
reed@google.com98539c62011-03-15 15:40:16 +000068
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 /** 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);
reed@google.com98539c62011-03-15 15:40:16 +000074
reed@android.com9d3a9852010-01-08 14:07:42 +000075 /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
76 a character code of zero.
77 */
78 SkUnichar glyphToUnichar(uint16_t);
79
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +000080 /** Returns the number of glyphs for this strike.
81 */
82 unsigned getGlyphCount();
83
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 /** 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 */
95 const SkPaint::FontMetrics& getFontMetricsY() const {
96 return fFontMetricsY;
97 }
reed@android.comf2b98d62010-12-20 18:26:13 +000098
99 const SkDescriptor& getDescriptor() const { return *fDesc; }
100
reed@google.com98539c62011-03-15 15:40:16 +0000101 SkMask::Format getMaskFormat() const {
102 return fScalerContext->getMaskFormat();
103 }
104
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 /* AuxProc/Data allow a client to associate data with this cache entry.
106 Multiple clients can use this, as their data is keyed with a function
107 pointer. In addition to serving as a key, the function pointer is called
108 with the data when the glyphcache object is deleted, so the client can
109 cleanup their data as well. NOTE: the auxProc must not try to access
110 this glyphcache in any way, since it may be in the process of being
111 deleted.
112 */
reed@google.com98539c62011-03-15 15:40:16 +0000113
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 //! If the proc is found, return true and set *dataPtr to its data
115 bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
116 //! Add a proc/data pair to the glyphcache. proc should be non-null
117 void setAuxProc(void (*auxProc)(void*), void* auxData);
118 //! If found, remove the proc/data pair from the glyphcache (does not
119 // call the proc)
120 void removeAuxProc(void (*auxProc)(void*));
121
122 /** Call proc on all cache entries, stopping early if proc returns true.
123 The proc should not create or delete caches, since it could produce
124 deadlock.
125 */
126 static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
reed@google.com98539c62011-03-15 15:40:16 +0000127
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 /** Find a matching cache entry, and call proc() with it. If none is found
129 create a new one. If the proc() returns true, detach the cache and
130 return it, otherwise leave it and return NULL.
131 */
132 static SkGlyphCache* VisitCache(const SkDescriptor* desc,
133 bool (*proc)(const SkGlyphCache*, void*),
134 void* context);
reed@google.com98539c62011-03-15 15:40:16 +0000135
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 /** Given a strike that was returned by either VisitCache() or DetachCache()
137 add it back into the global cache list (after which the caller should
138 not reference it anymore.
139 */
140 static void AttachCache(SkGlyphCache*);
141
142 /** Detach a strike from the global cache matching the specified descriptor.
143 Once detached, it can be queried/modified by the current thread, and
144 when finished, be reattached to the global cache with AttachCache().
145 While detached, if another request is made with the same descriptor,
146 a different strike will be generated. This is fine. It does mean we
147 can have more than 1 strike for the same descriptor, but that will
148 eventually get purged, and the win is that different thread will never
149 block each other while a strike is being used.
150 */
151 static SkGlyphCache* DetachCache(const SkDescriptor* desc) {
152 return VisitCache(desc, DetachProc, NULL);
153 }
154
155 /** Return the approximate number of bytes used by the font cache
156 */
157 static size_t GetCacheUsed();
158
159 /** This can be called to purge old font data, in an attempt to free
160 enough bytes such that the font cache is not using more than the
161 specified number of bytes. It is thread-safe, and may be called at
162 any time.
163 Return true if some amount of the cache was purged.
164 */
165 static bool SetCacheUsed(size_t bytesUsed);
166
reed@android.comf2b98d62010-12-20 18:26:13 +0000167#ifdef SK_DEBUG
168 void validate() const;
169#else
170 void validate() const {}
171#endif
172
173 class AutoValidate : SkNoncopyable {
174 public:
175 AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
176 if (fCache) {
177 fCache->validate();
178 }
179 }
180 ~AutoValidate() {
181 if (fCache) {
182 fCache->validate();
183 }
184 }
185 void forget() {
186 fCache = NULL;
187 }
188 private:
189 const SkGlyphCache* fCache;
190 };
reed@google.com98539c62011-03-15 15:40:16 +0000191
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192private:
193 SkGlyphCache(const SkDescriptor*);
194 ~SkGlyphCache();
reed@google.com98539c62011-03-15 15:40:16 +0000195
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 enum MetricsType {
197 kJustAdvance_MetricsType,
198 kFull_MetricsType
199 };
200
201 SkGlyph* lookupMetrics(uint32_t id, MetricsType);
202 static bool DetachProc(const SkGlyphCache*, void*) { return true; }
203
204 void detach(SkGlyphCache** head) {
205 if (fPrev) {
206 fPrev->fNext = fNext;
207 } else {
208 *head = fNext;
209 }
210 if (fNext) {
211 fNext->fPrev = fPrev;
212 }
213 fPrev = fNext = NULL;
214 }
reed@google.com98539c62011-03-15 15:40:16 +0000215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 void attachToHead(SkGlyphCache** head) {
217 SkASSERT(NULL == fPrev && NULL == fNext);
218 if (*head) {
219 (*head)->fPrev = this;
220 fNext = *head;
221 }
222 *head = this;
223 }
224
225 SkGlyphCache* fNext, *fPrev;
226 SkDescriptor* fDesc;
227 SkScalerContext* fScalerContext;
228 SkPaint::FontMetrics fFontMetricsY;
229
230 enum {
231 kHashBits = 8,
232 kHashCount = 1 << kHashBits,
233 kHashMask = kHashCount - 1
234 };
235 SkGlyph* fGlyphHash[kHashCount];
236 SkTDArray<SkGlyph*> fGlyphArray;
237 SkChunkAlloc fGlyphAlloc;
238 SkChunkAlloc fImageAlloc;
reed@google.com98539c62011-03-15 15:40:16 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 int fMetricsCount, fAdvanceCount;
241
242 struct CharGlyphRec {
243 uint32_t fID; // unichar + subpixel
244 SkGlyph* fGlyph;
245 };
246 // no reason to use the same kHashCount as fGlyphHash, but we do for now
247 CharGlyphRec fCharToGlyphHash[kHashCount];
reed@google.com98539c62011-03-15 15:40:16 +0000248
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 enum {
250 // shift so that the top bits fall into kHashBits region
251 kShiftForHashIndex = SkGlyph::kSubShift +
252 SkGlyph::kSubBits*2 -
253 kHashBits
254 };
255
256 static inline unsigned ID2HashIndex(uint32_t id) {
257 return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
258 }
reed@google.com98539c62011-03-15 15:40:16 +0000259
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 // used to track (approx) how much ram is tied-up in this cache
261 size_t fMemoryUsed;
262
263 struct AuxProcRec {
264 AuxProcRec* fNext;
265 void (*fProc)(void*);
266 void* fData;
267 };
268 AuxProcRec* fAuxProcList;
269 void invokeAndRemoveAuxProcs();
270
271 // This relies on the caller to have already acquired the mutex to access the global cache
272 static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
273
274 inline static SkGlyphCache* FindTail(SkGlyphCache* head);
275 static size_t ComputeMemoryUsed(const SkGlyphCache* head);
276
277 friend class SkGlyphCache_Globals;
278};
279
280class SkAutoGlyphCache {
281public:
282 SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
283 SkAutoGlyphCache(const SkDescriptor* desc)
284 {
285 fCache = SkGlyphCache::DetachCache(desc);
286 }
287 SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix)
288 {
289 fCache = paint.detachCache(matrix);
290 }
291 ~SkAutoGlyphCache()
292 {
293 if (fCache)
294 SkGlyphCache::AttachCache(fCache);
295 }
296
297 SkGlyphCache* getCache() const { return fCache; }
298
299 void release()
300 {
301 if (fCache)
302 {
303 SkGlyphCache::AttachCache(fCache);
304 fCache = NULL;
305 }
306 }
307private:
308 SkGlyphCache* fCache;
reed@google.com98539c62011-03-15 15:40:16 +0000309
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 static bool DetachProc(const SkGlyphCache*, void*);
311};
312
313#endif
314