• 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     /** 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     */
getFontMetricsY()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     */
DetachCache(const SkDescriptor * desc)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);
DetachProc(const SkGlyphCache *,void *)162     static bool DetachProc(const SkGlyphCache*, void*) { return true; }
163 
detach(SkGlyphCache ** head)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 
attachToHead(SkGlyphCache ** head)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 
ID2HashIndex(uint32_t id)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 the 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:
SkAutoGlyphCache(SkGlyphCache * cache)242     SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
SkAutoGlyphCache(const SkDescriptor * desc)243     SkAutoGlyphCache(const SkDescriptor* desc)
244     {
245         fCache = SkGlyphCache::DetachCache(desc);
246     }
SkAutoGlyphCache(const SkPaint & paint,const SkMatrix * matrix)247     SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix)
248     {
249         fCache = paint.detachCache(matrix);
250     }
~SkAutoGlyphCache()251     ~SkAutoGlyphCache()
252     {
253         if (fCache)
254             SkGlyphCache::AttachCache(fCache);
255     }
256 
getCache()257     SkGlyphCache*   getCache() const { return fCache; }
258 
release()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 
275