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 "SkGlyph.h"
17#include "SkScalerContext.h"
18#include "SkTemplates.h"
19#include "SkTDArray.h"
20
21struct SkDeviceProperties;
22class SkPaint;
23
24class SkGlyphCache_Globals;
25
26/** \class SkGlyphCache
27
28    This class represents a strike: a specific combination of typeface, size,
29    matrix, etc., and holds the glyphs for that strike. Calling any of the
30    getUnichar.../getGlyphID... methods will return the requested glyph,
31    either instantly if it is already cached, or by first generating it and then
32    adding it to the strike.
33
34    The strikes are held in a global list, available to all threads. To interact
35    with one, call either VisitCache() or DetachCache().
36*/
37class SkGlyphCache {
38public:
39    /** Returns a glyph with valid fAdvance and fDevKern fields.
40        The remaining fields may be valid, but that is not guaranteed. If you
41        require those, call getUnicharMetrics or getGlyphIDMetrics instead.
42    */
43    const SkGlyph& getUnicharAdvance(SkUnichar);
44    const SkGlyph& getGlyphIDAdvance(uint16_t);
45
46    /** Returns a glyph with all fields valid except fImage and fPath, which
47        may be null. If they are null, call findImage or findPath for those.
48        If they are not null, then they are valid.
49
50        This call is potentially slower than the matching ...Advance call. If
51        you only need the fAdvance/fDevKern fields, call those instead.
52    */
53    const SkGlyph& getUnicharMetrics(SkUnichar);
54    const SkGlyph& getGlyphIDMetrics(uint16_t);
55
56    /** These are variants that take the device position of the glyph. Call
57        these only if you are drawing in subpixel mode. Passing 0, 0 is
58        effectively the same as calling the variants w/o the extra params, tho
59        a tiny bit slower.
60    */
61    const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
62    const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
63
64    /** Return the glyphID for the specified Unichar. If the char has already
65        been seen, use the existing cache entry. If not, ask the scalercontext
66        to compute it for us.
67    */
68    uint16_t unicharToGlyph(SkUnichar);
69
70    /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
71        a character code of zero.
72    */
73    SkUnichar glyphToUnichar(uint16_t);
74
75    /** Returns the number of glyphs for this strike.
76    */
77    unsigned getGlyphCount();
78
79#ifdef SK_BUILD_FOR_ANDROID
80    /** Returns the base glyph count for this strike.
81    */
82    unsigned getBaseGlyphCount(SkUnichar charCode) const {
83        return fScalerContext->getBaseGlyphCount(charCode);
84    }
85#endif
86
87    /** Return the image associated with the glyph. If it has not been generated
88        this will trigger that.
89    */
90    const void* findImage(const SkGlyph&);
91    /** Return the Path associated with the glyph. If it has not been generated
92        this will trigger that.
93    */
94    const SkPath* findPath(const SkGlyph&);
95    /** Return the distance field associated with the glyph. If it has not been generated
96     this will trigger that.
97     */
98    const void* findDistanceField(const SkGlyph&);
99
100    /** Return the vertical metrics for this strike.
101    */
102    const SkPaint::FontMetrics& getFontMetrics() const {
103        return fFontMetrics;
104    }
105
106    const SkDescriptor& getDescriptor() const { return *fDesc; }
107
108    SkMask::Format getMaskFormat() const {
109        return fScalerContext->getMaskFormat();
110    }
111
112    bool isSubpixel() const {
113        return fScalerContext->isSubpixel();
114    }
115
116    /*  AuxProc/Data allow a client to associate data with this cache entry.
117        Multiple clients can use this, as their data is keyed with a function
118        pointer. In addition to serving as a key, the function pointer is called
119        with the data when the glyphcache object is deleted, so the client can
120        cleanup their data as well. NOTE: the auxProc must not try to access
121        this glyphcache in any way, since it may be in the process of being
122        deleted.
123    */
124
125    //! If the proc is found, return true and set *dataPtr to its data
126    bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
127    //! Add a proc/data pair to the glyphcache. proc should be non-null
128    void setAuxProc(void (*auxProc)(void*), void* auxData);
129
130    SkScalerContext* getScalerContext() const { return fScalerContext; }
131
132    /** Call proc on all cache entries, stopping early if proc returns true.
133        The proc should not create or delete caches, since it could produce
134        deadlock.
135    */
136    static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
137
138    /** Find a matching cache entry, and call proc() with it. If none is found
139        create a new one. If the proc() returns true, detach the cache and
140        return it, otherwise leave it and return NULL.
141    */
142    static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc,
143                                    bool (*proc)(const SkGlyphCache*, void*),
144                                    void* context);
145
146    /** Given a strike that was returned by either VisitCache() or DetachCache()
147        add it back into the global cache list (after which the caller should
148        not reference it anymore.
149    */
150    static void AttachCache(SkGlyphCache*);
151
152    /** Detach a strike from the global cache matching the specified descriptor.
153        Once detached, it can be queried/modified by the current thread, and
154        when finished, be reattached to the global cache with AttachCache().
155        While detached, if another request is made with the same descriptor,
156        a different strike will be generated. This is fine. It does mean we
157        can have more than 1 strike for the same descriptor, but that will
158        eventually get purged, and the win is that different thread will never
159        block each other while a strike is being used.
160    */
161    static SkGlyphCache* DetachCache(SkTypeface* typeface,
162                                     const SkDescriptor* desc) {
163        return VisitCache(typeface, desc, DetachProc, NULL);
164    }
165
166#ifdef SK_DEBUG
167    void validate() const;
168#else
169    void validate() const {}
170#endif
171
172    class AutoValidate : SkNoncopyable {
173    public:
174        AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
175            if (fCache) {
176                fCache->validate();
177            }
178        }
179        ~AutoValidate() {
180            if (fCache) {
181                fCache->validate();
182            }
183        }
184        void forget() {
185            fCache = NULL;
186        }
187    private:
188        const SkGlyphCache* fCache;
189    };
190
191private:
192    // we take ownership of the scalercontext
193    SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*);
194    ~SkGlyphCache();
195
196    enum MetricsType {
197        kJustAdvance_MetricsType,
198        kFull_MetricsType
199    };
200
201    SkGlyph* lookupMetrics(uint32_t id, MetricsType);
202    static bool DetachProc(const SkGlyphCache*, void*) { return true; }
203
204    SkGlyphCache*       fNext, *fPrev;
205    SkDescriptor*       fDesc;
206    SkScalerContext*    fScalerContext;
207    SkPaint::FontMetrics fFontMetrics;
208
209    enum {
210        kHashBits   = 8,
211        kHashCount  = 1 << kHashBits,
212        kHashMask   = kHashCount - 1
213    };
214    SkGlyph*            fGlyphHash[kHashCount];
215    SkTDArray<SkGlyph*> fGlyphArray;
216    SkChunkAlloc        fGlyphAlloc;
217
218    struct CharGlyphRec {
219        uint32_t    fID;    // unichar + subpixel
220        SkGlyph*    fGlyph;
221    };
222    // no reason to use the same kHashCount as fGlyphHash, but we do for now
223    CharGlyphRec    fCharToGlyphHash[kHashCount];
224
225    static inline unsigned ID2HashIndex(uint32_t id) {
226        id ^= id >> 16;
227        id ^= id >> 8;
228        return id & kHashMask;
229    }
230
231    // used to track (approx) how much ram is tied-up in this cache
232    size_t  fMemoryUsed;
233
234    struct AuxProcRec {
235        AuxProcRec* fNext;
236        void (*fProc)(void*);
237        void* fData;
238    };
239    AuxProcRec* fAuxProcList;
240    void invokeAndRemoveAuxProcs();
241
242    inline static SkGlyphCache* FindTail(SkGlyphCache* head);
243
244    friend class SkGlyphCache_Globals;
245};
246
247class SkAutoGlyphCacheBase {
248public:
249    SkGlyphCache* getCache() const { return fCache; }
250
251    void release() {
252        if (fCache) {
253            SkGlyphCache::AttachCache(fCache);
254            fCache = NULL;
255        }
256    }
257
258protected:
259    // Hide the constructors so we can't create one of these directly.
260    // Create SkAutoGlyphCache or SkAutoGlyphCacheNoCache instead.
261    SkAutoGlyphCacheBase(SkGlyphCache* cache) : fCache(cache) {}
262    SkAutoGlyphCacheBase(SkTypeface* typeface, const SkDescriptor* desc) {
263        fCache = SkGlyphCache::DetachCache(typeface, desc);
264    }
265    SkAutoGlyphCacheBase(const SkPaint& paint,
266                         const SkDeviceProperties* deviceProperties,
267                         const SkMatrix* matrix) {
268        fCache = NULL;
269    }
270    SkAutoGlyphCacheBase() {
271        fCache = NULL;
272    }
273    ~SkAutoGlyphCacheBase() {
274        if (fCache) {
275            SkGlyphCache::AttachCache(fCache);
276        }
277    }
278
279    SkGlyphCache*   fCache;
280
281private:
282    static bool DetachProc(const SkGlyphCache*, void*);
283};
284
285class SkAutoGlyphCache : public SkAutoGlyphCacheBase {
286public:
287    SkAutoGlyphCache(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {}
288    SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) :
289        SkAutoGlyphCacheBase(typeface, desc) {}
290    SkAutoGlyphCache(const SkPaint& paint,
291                     const SkDeviceProperties* deviceProperties,
292                     const SkMatrix* matrix) {
293        fCache = paint.detachCache(deviceProperties, matrix, false);
294    }
295
296private:
297    SkAutoGlyphCache() : SkAutoGlyphCacheBase() {}
298};
299#define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache)
300
301class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCacheBase {
302public:
303    SkAutoGlyphCacheNoGamma(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {}
304    SkAutoGlyphCacheNoGamma(SkTypeface* typeface, const SkDescriptor* desc) :
305        SkAutoGlyphCacheBase(typeface, desc) {}
306    SkAutoGlyphCacheNoGamma(const SkPaint& paint,
307                            const SkDeviceProperties* deviceProperties,
308                            const SkMatrix* matrix) {
309        fCache = paint.detachCache(deviceProperties, matrix, true);
310    }
311
312private:
313    SkAutoGlyphCacheNoGamma() : SkAutoGlyphCacheBase() {}
314};
315#define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma)
316
317#endif
318