OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be found
in the LICENSE file. |
5 * found in the LICENSE file. | |
6 */ | 5 */ |
7 | 6 |
8 #ifndef SkGlyphCache_DEFINED | 7 #ifndef SkGlyphCache_DEFINED |
9 #define SkGlyphCache_DEFINED | 8 #define SkGlyphCache_DEFINED |
10 | 9 |
11 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
12 #include "SkChecksum.h" | 11 #include "SkChecksum.h" |
13 #include "SkChunkAlloc.h" | 12 #include "SkChunkAlloc.h" |
14 #include "SkDescriptor.h" | 13 #include "SkDescriptor.h" |
15 #include "SkGlyph.h" | 14 #include "SkGlyph.h" |
16 #include "SkScalerContext.h" | 15 #include "SkScalerContext.h" |
17 #include "SkTemplates.h" | 16 #include "SkTemplates.h" |
18 #include "SkTDArray.h" | 17 #include "SkTDArray.h" |
19 | 18 |
20 class SkPaint; | 19 class SkPaint; |
21 | 20 |
22 class SkGlyphCache_Globals; | 21 class SkGlyphCache_Globals; |
23 | 22 |
24 // Enable this locally to add stats for hash-table hit rates. It also extends th
e dump() | 23 // Enable this locally to add stats for hash-table hit rates. It also extends th
e dump() output |
25 // output to show those stats. | 24 // to show those stats. |
26 //#define SK_GLYPHCACHE_TRACK_HASH_STATS | 25 //#define SK_GLYPHCACHE_TRACK_HASH_STATS |
27 | 26 |
28 /** \class SkGlyphCache | 27 /** \class SkGlyphCache |
29 | 28 |
30 This class represents a strike: a specific combination of typeface, size, | 29 This class represents a strike: a specific combination of typeface, size, ma
trix, etc., and |
31 matrix, etc., and holds the glyphs for that strike. Calling any of the | 30 holds the glyphs for that strike. Calling any of the getUnichar.../getGlyphI
D... methods will |
32 getUnichar.../getGlyphID... methods will return the requested glyph, | 31 return the requested glyph, either instantly if it is already cached, or by
first generating |
33 either instantly if it is already cached, or by first generating it and then | 32 it and then adding it to the strike. |
34 adding it to the strike. | |
35 | 33 |
36 The strikes are held in a global list, available to all threads. To interact | 34 The strikes are held in a global list, available to all threads. To interact
with one, call |
37 with one, call either VisitCache() or DetachCache(). | 35 either VisitCache() or DetachCache(). |
38 */ | 36 */ |
39 class SkGlyphCache { | 37 class SkGlyphCache { |
40 public: | 38 public: |
41 /** Returns a glyph with valid fAdvance and fDevKern fields. | 39 /** Returns a glyph with valid fAdvance and fDevKern fields. The remaining f
ields may be |
42 The remaining fields may be valid, but that is not guaranteed. If you | 40 valid, but that is not guaranteed. If you require those, call getUnichar
Metrics or |
43 require those, call getUnicharMetrics or getGlyphIDMetrics instead. | 41 getGlyphIDMetrics instead. |
44 */ | 42 */ |
45 const SkGlyph& getUnicharAdvance(SkUnichar); | 43 const SkGlyph& getUnicharAdvance(SkUnichar); |
46 const SkGlyph& getGlyphIDAdvance(uint16_t); | 44 const SkGlyph& getGlyphIDAdvance(uint16_t); |
47 | 45 |
48 /** Returns a glyph with all fields valid except fImage and fPath, which | 46 /** Returns a glyph with all fields valid except fImage and fPath, which may
be null. If they |
49 may be null. If they are null, call findImage or findPath for those. | 47 are null, call findImage or findPath for those. If they are not null, th
en they are valid. |
50 If they are not null, then they are valid. | |
51 | 48 |
52 This call is potentially slower than the matching ...Advance call. If | 49 This call is potentially slower than the matching ...Advance call. If yo
u only need the |
53 you only need the fAdvance/fDevKern fields, call those instead. | 50 fAdvance/fDevKern fields, call those instead. |
54 */ | 51 */ |
55 const SkGlyph& getUnicharMetrics(SkUnichar); | 52 const SkGlyph& getUnicharMetrics(SkUnichar); |
56 const SkGlyph& getGlyphIDMetrics(uint16_t); | 53 const SkGlyph& getGlyphIDMetrics(uint16_t); |
57 | 54 |
58 /** These are variants that take the device position of the glyph. Call | 55 /** These are variants that take the device position of the glyph. Call thes
e only if you are |
59 these only if you are drawing in subpixel mode. Passing 0, 0 is | 56 drawing in subpixel mode. Passing 0, 0 is effectively the same as callin
g the variants |
60 effectively the same as calling the variants w/o the extra params, tho | 57 w/o the extra params, though a tiny bit slower. |
61 a tiny bit slower. | |
62 */ | 58 */ |
63 const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); | 59 const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); |
64 const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); | 60 const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); |
65 | 61 |
66 /** Return the glyphID for the specified Unichar. If the char has already | 62 /** Return the glyphID for the specified Unichar. If the char has already be
en seen, use the |
67 been seen, use the existing cache entry. If not, ask the scalercontext | 63 existing cache entry. If not, ask the scalercontext to compute it for us
. |
68 to compute it for us. | |
69 */ | 64 */ |
70 uint16_t unicharToGlyph(SkUnichar); | 65 uint16_t unicharToGlyph(SkUnichar); |
71 | 66 |
72 /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to | 67 /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to a char
acter code of zero. |
73 a character code of zero. | |
74 */ | 68 */ |
75 SkUnichar glyphToUnichar(uint16_t); | 69 SkUnichar glyphToUnichar(uint16_t); |
76 | 70 |
77 /** Returns the number of glyphs for this strike. | 71 /** Returns the number of glyphs for this strike. |
78 */ | 72 */ |
79 unsigned getGlyphCount(); | 73 unsigned getGlyphCount(); |
80 | 74 |
81 /** Return the image associated with the glyph. If it has not been generated | 75 /** Return the image associated with the glyph. If it has not been generated
this will |
82 this will trigger that. | 76 trigger that. |
83 */ | 77 */ |
84 const void* findImage(const SkGlyph&); | 78 const void* findImage(const SkGlyph&); |
85 /** Return the Path associated with the glyph. If it has not been generated | 79 |
86 this will trigger that. | 80 /** Return the Path associated with the glyph. If it has not been generated
this will trigger |
| 81 that. |
87 */ | 82 */ |
88 const SkPath* findPath(const SkGlyph&); | 83 const SkPath* findPath(const SkGlyph&); |
89 | 84 |
90 /** Return the vertical metrics for this strike. | 85 /** Return the vertical metrics for this strike. |
91 */ | 86 */ |
92 const SkPaint::FontMetrics& getFontMetrics() const { | 87 const SkPaint::FontMetrics& getFontMetrics() const { |
93 return fFontMetrics; | 88 return fFontMetrics; |
94 } | 89 } |
95 | 90 |
96 const SkDescriptor& getDescriptor() const { return *fDesc; } | 91 const SkDescriptor& getDescriptor() const { return *fDesc; } |
97 | 92 |
98 SkMask::Format getMaskFormat() const { | 93 SkMask::Format getMaskFormat() const { |
99 return fScalerContext->getMaskFormat(); | 94 return fScalerContext->getMaskFormat(); |
100 } | 95 } |
101 | 96 |
102 bool isSubpixel() const { | 97 bool isSubpixel() const { |
103 return fScalerContext->isSubpixel(); | 98 return fScalerContext->isSubpixel(); |
104 } | 99 } |
105 | 100 |
106 void dump() const; | 101 void dump() const; |
107 | 102 |
108 /* AuxProc/Data allow a client to associate data with this cache entry. | 103 /* AuxProc/Data allow a client to associate data with this cache entry. Mul
tiple clients can |
109 Multiple clients can use this, as their data is keyed with a function | 104 use this, as their data is keyed with a function pointer. In addition to
serving as a |
110 pointer. In addition to serving as a key, the function pointer is called | 105 key, the function pointer is called with the data when the glyphcache ob
ject is deleted, |
111 with the data when the glyphcache object is deleted, so the client can | 106 so the client can cleanup their data as well. |
112 cleanup their data as well. NOTE: the auxProc must not try to access | 107 NOTE: the auxProc must not try to access this glyphcache in any way, sin
ce it may be in |
113 this glyphcache in any way, since it may be in the process of being | 108 the process of being deleted. |
114 deleted. | |
115 */ | 109 */ |
116 | 110 |
117 //! If the proc is found, return true and set *dataPtr to its data | 111 //! If the proc is found, return true and set *dataPtr to its data |
118 bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; | 112 bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; |
| 113 |
119 //! Add a proc/data pair to the glyphcache. proc should be non-null | 114 //! Add a proc/data pair to the glyphcache. proc should be non-null |
120 void setAuxProc(void (*auxProc)(void*), void* auxData); | 115 void setAuxProc(void (*auxProc)(void*), void* auxData); |
121 | 116 |
122 SkScalerContext* getScalerContext() const { return fScalerContext; } | 117 SkScalerContext* getScalerContext() const { return fScalerContext; } |
123 | 118 |
124 /** Find a matching cache entry, and call proc() with it. If none is found | 119 /** Find a matching cache entry, and call proc() with it. If none is found c
reate a new one. |
125 create a new one. If the proc() returns true, detach the cache and | 120 If the proc() returns true, detach the cache and return it, otherwise le
ave it and return |
126 return it, otherwise leave it and return NULL. | 121 NULL. |
127 */ | 122 */ |
128 static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, | 123 static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, |
129 bool (*proc)(const SkGlyphCache*, void*), | 124 bool (*proc)(const SkGlyphCache*, void*), |
130 void* context); | 125 void* context); |
131 | 126 |
132 /** Given a strike that was returned by either VisitCache() or DetachCache() | 127 /** Given a strike that was returned by either VisitCache() or DetachCache()
add it back into |
133 add it back into the global cache list (after which the caller should | 128 the global cache list (after which the caller should not reference it an
ymore. |
134 not reference it anymore. | |
135 */ | 129 */ |
136 static void AttachCache(SkGlyphCache*); | 130 static void AttachCache(SkGlyphCache*); |
137 | 131 |
138 /** Detach a strike from the global cache matching the specified descriptor. | 132 /** Detach a strike from the global cache matching the specified descriptor.
Once detached, |
139 Once detached, it can be queried/modified by the current thread, and | 133 it can be queried/modified by the current thread, and when finished, be
reattached to the |
140 when finished, be reattached to the global cache with AttachCache(). | 134 global cache with AttachCache(). While detached, if another request is m
ade with the same |
141 While detached, if another request is made with the same descriptor, | 135 descriptor, a different strike will be generated. This is fine. It does
mean we can have |
142 a different strike will be generated. This is fine. It does mean we | 136 more than 1 strike for the same descriptor, but that will eventually get
purged, and the |
143 can have more than 1 strike for the same descriptor, but that will | 137 win is that different thread will never block each other while a strike
is being used. |
144 eventually get purged, and the win is that different thread will never | |
145 block each other while a strike is being used. | |
146 */ | 138 */ |
147 static SkGlyphCache* DetachCache(SkTypeface* typeface, | 139 static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkDescriptor* d
esc) { |
148 const SkDescriptor* desc) { | |
149 return VisitCache(typeface, desc, DetachProc, NULL); | 140 return VisitCache(typeface, desc, DetachProc, NULL); |
150 } | 141 } |
151 | 142 |
152 static void Dump(); | 143 static void Dump(); |
153 | 144 |
154 #ifdef SK_DEBUG | 145 #ifdef SK_DEBUG |
155 void validate() const; | 146 void validate() const; |
156 #else | 147 #else |
157 void validate() const {} | 148 void validate() const {} |
158 #endif | 149 #endif |
(...skipping 11 matching lines...) Expand all Loading... |
170 } | 161 } |
171 } | 162 } |
172 void forget() { | 163 void forget() { |
173 fCache = NULL; | 164 fCache = NULL; |
174 } | 165 } |
175 private: | 166 private: |
176 const SkGlyphCache* fCache; | 167 const SkGlyphCache* fCache; |
177 }; | 168 }; |
178 | 169 |
179 private: | 170 private: |
180 // we take ownership of the scalercontext | 171 friend class SkGlyphCache_Globals; |
181 SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); | |
182 ~SkGlyphCache(); | |
183 | 172 |
184 enum MetricsType { | 173 enum MetricsType { |
185 kJustAdvance_MetricsType, | 174 kJustAdvance_MetricsType, |
186 kFull_MetricsType | 175 kFull_MetricsType |
187 }; | 176 }; |
188 | 177 |
189 // Return the SkGlyph* associated with MakeID. The id parameter is the combi
ned glyph/x/y | |
190 // id generated by MakeID. If it is just a glyph id then x and y are assuemd
to be zero. | |
191 SkGlyph* lookupByCombinedID(uint32_t id, MetricsType type); | |
192 | |
193 // Return a SkGlyph* associated with unicode id and position x and y. | |
194 SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed
y = 0); | |
195 | |
196 // Return the index of id in the fGlyphArray. If it does | |
197 // not exist, create a new one using MetricsType. | |
198 uint16_t lookupMetrics(uint32_t id, MetricsType type); | |
199 static bool DetachProc(const SkGlyphCache*, void*) { return true; } | |
200 | |
201 SkGlyphCache* fNext, *fPrev; | |
202 SkDescriptor* fDesc; | |
203 SkScalerContext* fScalerContext; | |
204 SkPaint::FontMetrics fFontMetrics; | |
205 | |
206 enum { | 178 enum { |
207 kHashBits = 8, | 179 kHashBits = 8, |
208 kHashCount = 1 << kHashBits, | 180 kHashCount = 1 << kHashBits, |
209 kHashMask = kHashCount - 1 | 181 kHashMask = kHashCount - 1 |
210 }; | 182 }; |
211 | 183 |
212 // A quick lookup to avoid the binary search looking for glyphs in fGlyphArr
ay. | |
213 uint16_t fGlyphHash[kHashCount]; | |
214 // Contains the SkGlyphs that are used by fGlyphHash and fCharToGlyphHash. T
he zero element | |
215 // is reserved for a sentinel SkGlyph that reduces the logic to check for co
llisions in the | |
216 // hash arrays. The zero element has an fID of SkGlyph::kImpossibleID which
never matches | |
217 // any combined id generated for a char or a glyph. | |
218 SkTDArray<SkGlyph> fGlyphArray; | |
219 SkChunkAlloc fGlyphAlloc; | |
220 | |
221 struct CharGlyphRec { | 184 struct CharGlyphRec { |
222 uint32_t fID; // unichar + subpixel | 185 uint32_t fID; // unichar + subpixel |
223 uint16_t fGlyphIndex; | 186 uint16_t fGlyphIndex; |
224 }; | 187 }; |
225 | 188 |
226 // no reason to use the same kHashCount as fGlyphHash, but we do for now | 189 struct AuxProcRec { |
227 // Dynamically allocated when chars are encountered. | 190 AuxProcRec* fNext; |
228 SkAutoTArray<CharGlyphRec> fCharToGlyphHash; | 191 void (*fProc)(void*); |
| 192 void* fData; |
| 193 }; |
| 194 |
| 195 // SkGlyphCache takes ownership of the scalercontext. |
| 196 SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); |
| 197 ~SkGlyphCache(); |
| 198 |
| 199 // Return the SkGlyph* associated with MakeID. The id parameter is the |
| 200 // combined glyph/x/y id generated by MakeID. If it is just a glyph id |
| 201 // then x and y are assumed to be zero. |
| 202 SkGlyph* lookupByCombinedID(uint32_t id, MetricsType type); |
| 203 |
| 204 // Return a SkGlyph* associated with unicode id and position x and y. |
| 205 SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed
y = 0); |
| 206 |
| 207 // Return the index of id in the fGlyphArray. If it does not exist, |
| 208 // create a new one using MetricsType. |
| 209 uint16_t lookupMetrics(uint32_t id, MetricsType type); |
| 210 static bool DetachProc(const SkGlyphCache*, void*) { return true; } |
229 | 211 |
230 // The id arg is a combined id generated by MakeID. | 212 // The id arg is a combined id generated by MakeID. |
231 CharGlyphRec* getCharGlyphRec(uint32_t id); | 213 CharGlyphRec* getCharGlyphRec(uint32_t id); |
232 void adjustCaches(int insertion_index); | 214 void adjustCaches(int insertion_index); |
233 | 215 |
234 static inline unsigned ID2HashIndex(uint32_t h) { | 216 static inline unsigned ID2HashIndex(uint32_t h) { |
235 return SkChecksum::CheapMix(h) & kHashMask; | 217 return SkChecksum::CheapMix(h) & kHashMask; |
236 } | 218 } |
237 | 219 |
| 220 void invokeAndRemoveAuxProcs(); |
| 221 |
| 222 inline static SkGlyphCache* FindTail(SkGlyphCache* head); |
| 223 |
| 224 SkGlyphCache* fNext, *fPrev; |
| 225 SkDescriptor* fDesc; |
| 226 SkScalerContext* fScalerContext; |
| 227 SkPaint::FontMetrics fFontMetrics; |
| 228 |
| 229 // A quick lookup to avoid the binary search looking for glyphs in fGlyphArr
ay. |
| 230 uint16_t fGlyphHash[kHashCount]; |
| 231 |
| 232 // Contains the SkGlyphs that are used by fGlyphHash and fCharToGlyphHash. T
he ~0 element is |
| 233 // reserved for a sentinel SkGlyph that reduces the logic to check for colli
sions in the hash |
| 234 // arrays. The ~0 element has an fID of SkGlyph::kImpossibleID which never m
atches any |
| 235 // combined id generated for a char or a glyph. |
| 236 SkTDArray<SkGlyph> fGlyphArray; |
| 237 SkChunkAlloc fGlyphAlloc; |
| 238 |
| 239 // no reason to use the same kHashCount as fGlyphHash, but we do for now |
| 240 // Dynamically allocated when chars are encountered. |
| 241 SkAutoTArray<CharGlyphRec> fCharToGlyphHash; |
| 242 |
238 // used to track (approx) how much ram is tied-up in this cache | 243 // used to track (approx) how much ram is tied-up in this cache |
239 size_t fMemoryUsed; | 244 size_t fMemoryUsed; |
240 | 245 |
241 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS | 246 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
242 int fHashHitCount; | 247 int fHashHitCount; |
243 int fHashMissCount; | 248 int fHashMissCount; |
244 #endif | 249 #endif |
245 | 250 |
246 struct AuxProcRec { | |
247 AuxProcRec* fNext; | |
248 void (*fProc)(void*); | |
249 void* fData; | |
250 }; | |
251 AuxProcRec* fAuxProcList; | 251 AuxProcRec* fAuxProcList; |
252 void invokeAndRemoveAuxProcs(); | |
253 | |
254 inline static SkGlyphCache* FindTail(SkGlyphCache* head); | |
255 | |
256 friend class SkGlyphCache_Globals; | |
257 }; | 252 }; |
258 | 253 |
259 class SkAutoGlyphCacheBase { | 254 class SkAutoGlyphCacheBase { |
260 public: | 255 public: |
261 SkGlyphCache* getCache() const { return fCache; } | 256 SkGlyphCache* getCache() const { return fCache; } |
262 | 257 |
263 void release() { | 258 void release() { |
264 if (fCache) { | 259 if (fCache) { |
265 SkGlyphCache::AttachCache(fCache); | 260 SkGlyphCache::AttachCache(fCache); |
266 fCache = NULL; | 261 fCache = NULL; |
267 } | 262 } |
268 } | 263 } |
269 | 264 |
270 protected: | 265 protected: |
271 // Hide the constructors so we can't create one of these directly. | 266 // Hide the constructors so we can't create one of these directly. Create Sk
AutoGlyphCache or |
272 // Create SkAutoGlyphCache or SkAutoGlyphCacheNoCache instead. | 267 // SkAutoGlyphCacheNoCache instead. |
273 SkAutoGlyphCacheBase(SkGlyphCache* cache) : fCache(cache) {} | 268 SkAutoGlyphCacheBase(SkGlyphCache* cache) : fCache(cache) {} |
274 SkAutoGlyphCacheBase(SkTypeface* typeface, const SkDescriptor* desc) { | 269 SkAutoGlyphCacheBase(SkTypeface* typeface, const SkDescriptor* desc) { |
275 fCache = SkGlyphCache::DetachCache(typeface, desc); | 270 fCache = SkGlyphCache::DetachCache(typeface, desc); |
276 } | 271 } |
277 SkAutoGlyphCacheBase(const SkPaint& /*paint*/, | 272 SkAutoGlyphCacheBase(const SkPaint& /*paint*/, |
278 const SkSurfaceProps* /*surfaceProps*/, | 273 const SkSurfaceProps* /*surfaceProps*/, |
279 const SkMatrix* /*matrix*/) { | 274 const SkMatrix* /*matrix*/) { |
280 fCache = NULL; | 275 fCache = NULL; |
281 } | 276 } |
282 SkAutoGlyphCacheBase() { | 277 SkAutoGlyphCacheBase() { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 const SkMatrix* matrix) { | 315 const SkMatrix* matrix) { |
321 fCache = paint.detachCache(surfaceProps, matrix, true); | 316 fCache = paint.detachCache(surfaceProps, matrix, true); |
322 } | 317 } |
323 | 318 |
324 private: | 319 private: |
325 SkAutoGlyphCacheNoGamma() : SkAutoGlyphCacheBase() {} | 320 SkAutoGlyphCacheNoGamma() : SkAutoGlyphCacheBase() {} |
326 }; | 321 }; |
327 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamm
a) | 322 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamm
a) |
328 | 323 |
329 #endif | 324 #endif |
OLD | NEW |