OLD | NEW |
| (Empty) |
1 /* 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 | |
27 class SkPaint; | |
28 | |
29 class 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 */ | |
42 class SkGlyphCache { | |
43 public: | |
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 | |
152 private: | |
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 th
e 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 | |
240 class SkAutoGlyphCache { | |
241 public: | |
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 } | |
267 private: | |
268 SkGlyphCache* fCache; | |
269 | |
270 static bool DetachProc(const SkGlyphCache*, void*); | |
271 }; | |
272 | |
273 #endif | |
274 | |
OLD | NEW |