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 cahced, 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
96    /** Return the vertical metrics for this strike.
97    */
98    const SkPaint::FontMetrics& getFontMetrics() const {
99        return fFontMetrics;
100    }
101
102    const SkDescriptor& getDescriptor() const { return *fDesc; }
103
104    SkMask::Format getMaskFormat() const {
105        return fScalerContext->getMaskFormat();
106    }
107
108    bool isSubpixel() const {
109        return fScalerContext->isSubpixel();
110    }
111
112    /*  AuxProc/Data allow a client to associate data with this cache entry.
113        Multiple clients can use this, as their data is keyed with a function
114        pointer. In addition to serving as a key, the function pointer is called
115        with the data when the glyphcache object is deleted, so the client can
116        cleanup their data as well. NOTE: the auxProc must not try to access
117        this glyphcache in any way, since it may be in the process of being
118        deleted.
119    */
120
121    //! If the proc is found, return true and set *dataPtr to its data
122    bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
123    //! Add a proc/data pair to the glyphcache. proc should be non-null
124    void setAuxProc(void (*auxProc)(void*), void* auxData);
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(SkTypeface*, 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(SkTypeface* typeface,
158                                     const SkDescriptor* desc) {
159        return VisitCache(typeface, desc, DetachProc, NULL);
160    }
161
162#ifdef SK_DEBUG
163    void validate() const;
164#else
165    void validate() const {}
166#endif
167
168    class AutoValidate : SkNoncopyable {
169    public:
170        AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
171            if (fCache) {
172                fCache->validate();
173            }
174        }
175        ~AutoValidate() {
176            if (fCache) {
177                fCache->validate();
178            }
179        }
180        void forget() {
181            fCache = NULL;
182        }
183    private:
184        const SkGlyphCache* fCache;
185    };
186
187private:
188    // we take ownership of the scalercontext
189    SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*);
190    ~SkGlyphCache();
191
192    enum MetricsType {
193        kJustAdvance_MetricsType,
194        kFull_MetricsType
195    };
196
197    SkGlyph* lookupMetrics(uint32_t id, MetricsType);
198    static bool DetachProc(const SkGlyphCache*, void*) { return true; }
199
200    SkGlyphCache*       fNext, *fPrev;
201    SkDescriptor*       fDesc;
202    SkScalerContext*    fScalerContext;
203    SkPaint::FontMetrics fFontMetrics;
204
205    enum {
206        kHashBits   = 8,
207        kHashCount  = 1 << kHashBits,
208        kHashMask   = kHashCount - 1
209    };
210    SkGlyph*            fGlyphHash[kHashCount];
211    SkTDArray<SkGlyph*> fGlyphArray;
212    SkChunkAlloc        fGlyphAlloc;
213
214    struct CharGlyphRec {
215        uint32_t    fID;    // unichar + subpixel
216        SkGlyph*    fGlyph;
217    };
218    // no reason to use the same kHashCount as fGlyphHash, but we do for now
219    CharGlyphRec    fCharToGlyphHash[kHashCount];
220
221    static inline unsigned ID2HashIndex(uint32_t id) {
222        id ^= id >> 16;
223        id ^= id >> 8;
224        return id & kHashMask;
225    }
226
227    // used to track (approx) how much ram is tied-up in this cache
228    size_t  fMemoryUsed;
229
230    struct AuxProcRec {
231        AuxProcRec* fNext;
232        void (*fProc)(void*);
233        void* fData;
234    };
235    AuxProcRec* fAuxProcList;
236    void invokeAndRemoveAuxProcs();
237
238    inline static SkGlyphCache* FindTail(SkGlyphCache* head);
239
240    friend class SkGlyphCache_Globals;
241};
242
243class SkAutoGlyphCache {
244public:
245    SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
246    SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) {
247        fCache = SkGlyphCache::DetachCache(typeface, desc);
248    }
249    SkAutoGlyphCache(const SkPaint& paint,
250                     const SkDeviceProperties* deviceProperties,
251                     const SkMatrix* matrix) {
252        fCache = paint.detachCache(deviceProperties, matrix);
253    }
254    ~SkAutoGlyphCache() {
255        if (fCache) {
256            SkGlyphCache::AttachCache(fCache);
257        }
258    }
259
260    SkGlyphCache* getCache() const { return fCache; }
261
262    void release() {
263        if (fCache) {
264            SkGlyphCache::AttachCache(fCache);
265            fCache = NULL;
266        }
267    }
268
269private:
270    SkGlyphCache*   fCache;
271
272    static bool DetachProc(const SkGlyphCache*, void*);
273};
274#define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache)
275
276#endif
277