• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
76         a character code of zero.
77     */
78     SkUnichar glyphToUnichar(uint16_t);
79 
80     /** Return the image associated with the glyph. If it has not been generated
81         this will trigger that.
82     */
83     const void* findImage(const SkGlyph&);
84     /** Return the Path associated with the glyph. If it has not been generated
85         this will trigger that.
86     */
87     const SkPath* findPath(const SkGlyph&);
88 
89     /** Return the vertical metrics for this strike.
90     */
getFontMetricsY()91     const SkPaint::FontMetrics& getFontMetricsY() const {
92         return fFontMetricsY;
93     }
94 
95     /*  AuxProc/Data allow a client to associate data with this cache entry.
96         Multiple clients can use this, as their data is keyed with a function
97         pointer. In addition to serving as a key, the function pointer is called
98         with the data when the glyphcache object is deleted, so the client can
99         cleanup their data as well. NOTE: the auxProc must not try to access
100         this glyphcache in any way, since it may be in the process of being
101         deleted.
102     */
103 
104     //! If the proc is found, return true and set *dataPtr to its data
105     bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
106     //! Add a proc/data pair to the glyphcache. proc should be non-null
107     void setAuxProc(void (*auxProc)(void*), void* auxData);
108     //! If found, remove the proc/data pair from the glyphcache (does not
109     //  call the proc)
110     void removeAuxProc(void (*auxProc)(void*));
111 
112     /** Call proc on all cache entries, stopping early if proc returns true.
113         The proc should not create or delete caches, since it could produce
114         deadlock.
115     */
116     static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
117 
118     /** Find a matching cache entry, and call proc() with it. If none is found
119         create a new one. If the proc() returns true, detach the cache and
120         return it, otherwise leave it and return NULL.
121     */
122     static SkGlyphCache* VisitCache(const SkDescriptor* desc,
123                                     bool (*proc)(const SkGlyphCache*, void*),
124                                     void* context);
125 
126     /** Given a strike that was returned by either VisitCache() or DetachCache()
127         add it back into the global cache list (after which the caller should
128         not reference it anymore.
129     */
130     static void AttachCache(SkGlyphCache*);
131 
132     /** Detach a strike from the global cache matching the specified descriptor.
133         Once detached, it can be queried/modified by the current thread, and
134         when finished, be reattached to the global cache with AttachCache().
135         While detached, if another request is made with the same descriptor,
136         a different strike will be generated. This is fine. It does mean we
137         can have more than 1 strike for the same descriptor, but that will
138         eventually get purged, and the win is that different thread will never
139         block each other while a strike is being used.
140     */
DetachCache(const SkDescriptor * desc)141     static SkGlyphCache* DetachCache(const SkDescriptor* desc) {
142         return VisitCache(desc, DetachProc, NULL);
143     }
144 
145     /** Return the approximate number of bytes used by the font cache
146     */
147     static size_t GetCacheUsed();
148 
149     /** This can be called to purge old font data, in an attempt to free
150         enough bytes such that the font cache is not using more than the
151         specified number of bytes. It is thread-safe, and may be called at
152         any time.
153         Return true if some amount of the cache was purged.
154     */
155     static bool SetCacheUsed(size_t bytesUsed);
156 
157 private:
158     SkGlyphCache(const SkDescriptor*);
159     ~SkGlyphCache();
160 
161     enum MetricsType {
162         kJustAdvance_MetricsType,
163         kFull_MetricsType
164     };
165 
166     SkGlyph* lookupMetrics(uint32_t id, MetricsType);
DetachProc(const SkGlyphCache *,void *)167     static bool DetachProc(const SkGlyphCache*, void*) { return true; }
168 
detach(SkGlyphCache ** head)169     void detach(SkGlyphCache** head) {
170         if (fPrev) {
171             fPrev->fNext = fNext;
172         } else {
173             *head = fNext;
174         }
175         if (fNext) {
176             fNext->fPrev = fPrev;
177         }
178         fPrev = fNext = NULL;
179     }
180 
attachToHead(SkGlyphCache ** head)181     void attachToHead(SkGlyphCache** head) {
182         SkASSERT(NULL == fPrev && NULL == fNext);
183         if (*head) {
184             (*head)->fPrev = this;
185             fNext = *head;
186         }
187         *head = this;
188     }
189 
190     SkGlyphCache*       fNext, *fPrev;
191     SkDescriptor*       fDesc;
192     SkScalerContext*    fScalerContext;
193     SkPaint::FontMetrics fFontMetricsY;
194 
195     enum {
196         kHashBits   = 8,
197         kHashCount  = 1 << kHashBits,
198         kHashMask   = kHashCount - 1
199     };
200     SkGlyph*            fGlyphHash[kHashCount];
201     SkTDArray<SkGlyph*> fGlyphArray;
202     SkChunkAlloc        fGlyphAlloc;
203     SkChunkAlloc        fImageAlloc;
204 
205     int fMetricsCount, fAdvanceCount;
206 
207     struct CharGlyphRec {
208         uint32_t    fID;    // unichar + subpixel
209         SkGlyph*    fGlyph;
210     };
211     // no reason to use the same kHashCount as fGlyphHash, but we do for now
212     CharGlyphRec    fCharToGlyphHash[kHashCount];
213 
214     enum {
215         // shift so that the top bits fall into kHashBits region
216         kShiftForHashIndex = SkGlyph::kSubShift +
217                              SkGlyph::kSubBits*2 -
218                              kHashBits
219     };
220 
ID2HashIndex(uint32_t id)221     static inline unsigned ID2HashIndex(uint32_t id) {
222         return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
223     }
224 
225     // used to track (approx) how much ram is tied-up in this cache
226     size_t  fMemoryUsed;
227 
228     struct AuxProcRec {
229         AuxProcRec* fNext;
230         void (*fProc)(void*);
231         void* fData;
232     };
233     AuxProcRec* fAuxProcList;
234     void invokeAndRemoveAuxProcs();
235 
236     // This relies on the caller to have already acquired the mutex to access the global cache
237     static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
238 
239     inline static SkGlyphCache* FindTail(SkGlyphCache* head);
240     static size_t ComputeMemoryUsed(const SkGlyphCache* head);
241 
242     friend class SkGlyphCache_Globals;
243 };
244 
245 class SkAutoGlyphCache {
246 public:
SkAutoGlyphCache(SkGlyphCache * cache)247     SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
SkAutoGlyphCache(const SkDescriptor * desc)248     SkAutoGlyphCache(const SkDescriptor* desc)
249     {
250         fCache = SkGlyphCache::DetachCache(desc);
251     }
SkAutoGlyphCache(const SkPaint & paint,const SkMatrix * matrix)252     SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix)
253     {
254         fCache = paint.detachCache(matrix);
255     }
~SkAutoGlyphCache()256     ~SkAutoGlyphCache()
257     {
258         if (fCache)
259             SkGlyphCache::AttachCache(fCache);
260     }
261 
getCache()262     SkGlyphCache*   getCache() const { return fCache; }
263 
release()264     void release()
265     {
266         if (fCache)
267         {
268             SkGlyphCache::AttachCache(fCache);
269             fCache = NULL;
270         }
271     }
272 private:
273     SkGlyphCache*   fCache;
274 
275     static bool DetachProc(const SkGlyphCache*, void*);
276 };
277 
278 #endif
279 
280