|
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 */ |
|
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 */ |
|
98 const SkPaint::FontMetrics& getFontMetrics() const { |
|
99 return fFontMetrics; |
|
100 } |
|
101 |
|
102 const SkDescriptor& getDescriptor() const { return *fDesc; } |
|
103 |
|
104 SkMask::Format getMaskFormat() const { |
|
105 return fScalerContext->getMaskFormat(); |
|
106 } |
|
107 |
|
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 |
|
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(SkTypeface*, 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 */ |
|
157 static SkGlyphCache* DetachCache(SkTypeface* typeface, |
|
158 const SkDescriptor* desc) { |
|
159 return VisitCache(typeface, desc, DetachProc, NULL); |
|
160 } |
|
161 |
|
162 #ifdef SK_DEBUG |
|
163 void validate() const; |
|
164 #else |
|
165 void validate() const {} |
|
166 #endif |
|
167 |
|
168 class AutoValidate : SkNoncopyable { |
|
169 public: |
|
170 AutoValidate(const SkGlyphCache* cache) : fCache(cache) { |
|
171 if (fCache) { |
|
172 fCache->validate(); |
|
173 } |
|
174 } |
|
175 ~AutoValidate() { |
|
176 if (fCache) { |
|
177 fCache->validate(); |
|
178 } |
|
179 } |
|
180 void forget() { |
|
181 fCache = NULL; |
|
182 } |
|
183 private: |
|
184 const SkGlyphCache* fCache; |
|
185 }; |
|
186 |
|
187 private: |
|
188 // we take ownership of the scalercontext |
|
189 SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); |
|
190 ~SkGlyphCache(); |
|
191 |
|
192 enum MetricsType { |
|
193 kJustAdvance_MetricsType, |
|
194 kFull_MetricsType |
|
195 }; |
|
196 |
|
197 SkGlyph* lookupMetrics(uint32_t id, MetricsType); |
|
198 static bool DetachProc(const SkGlyphCache*, void*) { return true; } |
|
199 |
|
200 SkGlyphCache* fNext, *fPrev; |
|
201 SkDescriptor* fDesc; |
|
202 SkScalerContext* fScalerContext; |
|
203 SkPaint::FontMetrics fFontMetrics; |
|
204 |
|
205 enum { |
|
206 kHashBits = 8, |
|
207 kHashCount = 1 << kHashBits, |
|
208 kHashMask = kHashCount - 1 |
|
209 }; |
|
210 SkGlyph* fGlyphHash[kHashCount]; |
|
211 SkTDArray<SkGlyph*> fGlyphArray; |
|
212 SkChunkAlloc fGlyphAlloc; |
|
213 |
|
214 struct CharGlyphRec { |
|
215 uint32_t fID; // unichar + subpixel |
|
216 SkGlyph* fGlyph; |
|
217 }; |
|
218 // no reason to use the same kHashCount as fGlyphHash, but we do for now |
|
219 CharGlyphRec fCharToGlyphHash[kHashCount]; |
|
220 |
|
221 static inline unsigned ID2HashIndex(uint32_t id) { |
|
222 id ^= id >> 16; |
|
223 id ^= id >> 8; |
|
224 return id & kHashMask; |
|
225 } |
|
226 |
|
227 // used to track (approx) how much ram is tied-up in this cache |
|
228 size_t fMemoryUsed; |
|
229 |
|
230 struct AuxProcRec { |
|
231 AuxProcRec* fNext; |
|
232 void (*fProc)(void*); |
|
233 void* fData; |
|
234 }; |
|
235 AuxProcRec* fAuxProcList; |
|
236 void invokeAndRemoveAuxProcs(); |
|
237 |
|
238 inline static SkGlyphCache* FindTail(SkGlyphCache* head); |
|
239 |
|
240 friend class SkGlyphCache_Globals; |
|
241 }; |
|
242 |
|
243 class SkAutoGlyphCache { |
|
244 public: |
|
245 SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} |
|
246 SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) { |
|
247 fCache = SkGlyphCache::DetachCache(typeface, desc); |
|
248 } |
|
249 SkAutoGlyphCache(const SkPaint& paint, |
|
250 const SkDeviceProperties* deviceProperties, |
|
251 const SkMatrix* matrix) { |
|
252 fCache = paint.detachCache(deviceProperties, matrix); |
|
253 } |
|
254 ~SkAutoGlyphCache() { |
|
255 if (fCache) { |
|
256 SkGlyphCache::AttachCache(fCache); |
|
257 } |
|
258 } |
|
259 |
|
260 SkGlyphCache* getCache() const { return fCache; } |
|
261 |
|
262 void release() { |
|
263 if (fCache) { |
|
264 SkGlyphCache::AttachCache(fCache); |
|
265 fCache = NULL; |
|
266 } |
|
267 } |
|
268 |
|
269 private: |
|
270 SkGlyphCache* fCache; |
|
271 |
|
272 static bool DetachProc(const SkGlyphCache*, void*); |
|
273 }; |
|
274 #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) |
|
275 |
|
276 #endif |