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 "SkScalerContext.h"
17#include "SkTemplates.h"
18
19class SkPaint;
20
21class SkGlyphCache_Globals;
22
23/** \class SkGlyphCache
24
25    This class represents a strike: a specific combination of typeface, size,
26    matrix, etc., and holds the glyphs for that strike. Calling any of the
27    getUnichar.../getGlyphID... methods will return the requested glyph,
28    either instantly if it is already cahced, or by first generating it and then
29    adding it to the strike.
30
31    The strikes are held in a global list, available to all threads. To interact
32    with one, call either VisitCache() or DetachCache().
33*/
34class SkGlyphCache {
35public:
36    /** Returns a glyph with valid fAdvance and fDevKern fields.
37        The remaining fields may be valid, but that is not guaranteed. If you
38        require those, call getUnicharMetrics or getGlyphIDMetrics instead.
39    */
40    const SkGlyph& getUnicharAdvance(SkUnichar);
41    const SkGlyph& getGlyphIDAdvance(uint16_t);
42
43    /** Returns a glyph with all fields valid except fImage and fPath, which
44        may be null. If they are null, call findImage or findPath for those.
45        If they are not null, then they are valid.
46
47        This call is potentially slower than the matching ...Advance call. If
48        you only need the fAdvance/fDevKern fields, call those instead.
49    */
50    const SkGlyph& getUnicharMetrics(SkUnichar);
51    const SkGlyph& getGlyphIDMetrics(uint16_t);
52
53    /** These are variants that take the device position of the glyph. Call
54        these only if you are drawing in subpixel mode. Passing 0, 0 is
55        effectively the same as calling the variants w/o the extra params, tho
56        a tiny bit slower.
57    */
58    const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
59    const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
60
61    /** Return the glyphID for the specified Unichar. If the char has already
62        been seen, use the existing cache entry. If not, ask the scalercontext
63        to compute it for us.
64    */
65    uint16_t unicharToGlyph(SkUnichar);
66
67    /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
68        a character code of zero.
69    */
70    SkUnichar glyphToUnichar(uint16_t);
71
72    /** Returns the number of glyphs for this strike.
73    */
74    unsigned getGlyphCount();
75
76#ifdef SK_BUILD_FOR_ANDROID
77    /** Returns the base glyph count for this strike.
78    */
79    unsigned getBaseGlyphCount(SkUnichar charCode) const {
80        return fScalerContext->getBaseGlyphCount(charCode);
81    }
82#endif
83
84    /** Return the image associated with the glyph. If it has not been generated
85        this will trigger that.
86    */
87    const void* findImage(const SkGlyph&);
88    /** Return the Path associated with the glyph. If it has not been generated
89        this will trigger that.
90    */
91    const SkPath* findPath(const SkGlyph&);
92
93    /** Return the vertical metrics for this strike.
94    */
95    const SkPaint::FontMetrics& getFontMetricsY() const {
96        return fFontMetricsY;
97    }
98
99    const SkDescriptor& getDescriptor() const { return *fDesc; }
100
101    SkMask::Format getMaskFormat() const {
102        return fScalerContext->getMaskFormat();
103    }
104
105    bool isSubpixel() const {
106        return fScalerContext->isSubpixel();
107    }
108
109    /*  AuxProc/Data allow a client to associate data with this cache entry.
110        Multiple clients can use this, as their data is keyed with a function
111        pointer. In addition to serving as a key, the function pointer is called
112        with the data when the glyphcache object is deleted, so the client can
113        cleanup their data as well. NOTE: the auxProc must not try to access
114        this glyphcache in any way, since it may be in the process of being
115        deleted.
116    */
117
118    //! If the proc is found, return true and set *dataPtr to its data
119    bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
120    //! Add a proc/data pair to the glyphcache. proc should be non-null
121    void setAuxProc(void (*auxProc)(void*), void* auxData);
122    //! If found, remove the proc/data pair from the glyphcache (does not
123    //  call the proc)
124    void removeAuxProc(void (*auxProc)(void*));
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(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(const SkDescriptor* desc) {
158        return VisitCache(desc, DetachProc, NULL);
159    }
160
161    /** Return the approximate number of bytes used by the font cache
162    */
163    static size_t GetCacheUsed();
164
165    /** This can be called to purge old font data, in an attempt to free
166        enough bytes such that the font cache is not using more than the
167        specified number of bytes. It is thread-safe, and may be called at
168        any time.
169        Return true if some amount of the cache was purged.
170    */
171    static bool SetCacheUsed(size_t bytesUsed);
172
173#ifdef SK_DEBUG
174    void validate() const;
175#else
176    void validate() const {}
177#endif
178
179    class AutoValidate : SkNoncopyable {
180    public:
181        AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
182            if (fCache) {
183                fCache->validate();
184            }
185        }
186        ~AutoValidate() {
187            if (fCache) {
188                fCache->validate();
189            }
190        }
191        void forget() {
192            fCache = NULL;
193        }
194    private:
195        const SkGlyphCache* fCache;
196    };
197
198private:
199    SkGlyphCache(const SkDescriptor*);
200    ~SkGlyphCache();
201
202    enum MetricsType {
203        kJustAdvance_MetricsType,
204        kFull_MetricsType
205    };
206
207    SkGlyph* lookupMetrics(uint32_t id, MetricsType);
208    static bool DetachProc(const SkGlyphCache*, void*) { return true; }
209
210    void detach(SkGlyphCache** head) {
211        if (fPrev) {
212            fPrev->fNext = fNext;
213        } else {
214            *head = fNext;
215        }
216        if (fNext) {
217            fNext->fPrev = fPrev;
218        }
219        fPrev = fNext = NULL;
220    }
221
222    void attachToHead(SkGlyphCache** head) {
223        SkASSERT(NULL == fPrev && NULL == fNext);
224        if (*head) {
225            (*head)->fPrev = this;
226            fNext = *head;
227        }
228        *head = this;
229    }
230
231    SkGlyphCache*       fNext, *fPrev;
232    SkDescriptor*       fDesc;
233    SkScalerContext*    fScalerContext;
234    SkPaint::FontMetrics fFontMetricsY;
235
236    enum {
237        kHashBits   = 12,
238        kHashCount  = 1 << kHashBits,
239        kHashMask   = kHashCount - 1
240    };
241    SkGlyph*            fGlyphHash[kHashCount];
242    SkTDArray<SkGlyph*> fGlyphArray;
243    SkChunkAlloc        fGlyphAlloc;
244    SkChunkAlloc        fImageAlloc;
245
246    int fMetricsCount, fAdvanceCount;
247
248    struct CharGlyphRec {
249        uint32_t    fID;    // unichar + subpixel
250        SkGlyph*    fGlyph;
251    };
252    // no reason to use the same kHashCount as fGlyphHash, but we do for now
253    CharGlyphRec    fCharToGlyphHash[kHashCount];
254
255    enum {
256        // shift so that the top bits fall into kHashBits region
257        kShiftForHashIndex = SkGlyph::kSubShift +
258                             SkGlyph::kSubBits*2 -
259                             kHashBits
260    };
261
262    static inline unsigned ID2HashIndex(uint32_t id) {
263        return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
264    }
265
266    // used to track (approx) how much ram is tied-up in this cache
267    size_t  fMemoryUsed;
268
269    struct AuxProcRec {
270        AuxProcRec* fNext;
271        void (*fProc)(void*);
272        void* fData;
273    };
274    AuxProcRec* fAuxProcList;
275    void invokeAndRemoveAuxProcs();
276
277    // This relies on the caller to have already acquired the mutex to access the global cache
278    static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
279
280    inline static SkGlyphCache* FindTail(SkGlyphCache* head);
281    static size_t ComputeMemoryUsed(const SkGlyphCache* head);
282
283    friend class SkGlyphCache_Globals;
284};
285
286class SkAutoGlyphCache {
287public:
288    SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
289    SkAutoGlyphCache(const SkDescriptor* desc) {
290        fCache = SkGlyphCache::DetachCache(desc);
291    }
292    SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix) {
293        fCache = paint.detachCache(matrix);
294    }
295    ~SkAutoGlyphCache() {
296        if (fCache) {
297            SkGlyphCache::AttachCache(fCache);
298        }
299    }
300
301    SkGlyphCache* getCache() const { return fCache; }
302
303    void release() {
304        if (fCache) {
305            SkGlyphCache::AttachCache(fCache);
306            fCache = NULL;
307        }
308    }
309
310private:
311    SkGlyphCache*   fCache;
312
313    static bool DetachProc(const SkGlyphCache*, void*);
314};
315
316#endif
317
318