1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2006 The Android Open Source Project
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifndef SkGlyphCache_DEFINED
11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define SkGlyphCache_DEFINED
12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBitmap.h"
14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkChunkAlloc.h"
15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkDescriptor.h"
161ef6e7aa2ca040bc9a47708d832f21e22ae474acbungeman@google.com#include "SkGlyph.h"
17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkScalerContext.h"
18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkTemplates.h"
197fe2414be8d83797ff0c450a79bc2de165171555mike@reedtribe.org#include "SkTDArray.h"
20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
214efd34721cb0e87078ae06a03cd905ba8e8b7c29bungeman@google.comstruct SkDeviceProperties;
22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comclass SkPaint;
23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comclass SkGlyphCache_Globals;
25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
26bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/** \class SkGlyphCache
27bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    This class represents a strike: a specific combination of typeface, size,
29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    matrix, etc., and holds the glyphs for that strike. Calling any of the
30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    getUnichar.../getGlyphID... methods will return the requested glyph,
31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    either instantly if it is already cahced, or by first generating it and then
32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    adding it to the strike.
33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    The strikes are held in a global list, available to all threads. To interact
35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    with one, call either VisitCache() or DetachCache().
36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/
37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comclass SkGlyphCache {
38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.compublic:
39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Returns a glyph with valid fAdvance and fDevKern fields.
40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        The remaining fields may be valid, but that is not guaranteed. If you
41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        require those, call getUnicharMetrics or getGlyphIDMetrics instead.
42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkGlyph& getUnicharAdvance(SkUnichar);
44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkGlyph& getGlyphIDAdvance(uint16_t);
45b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
46bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Returns a glyph with all fields valid except fImage and fPath, which
47bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        may be null. If they are null, call findImage or findPath for those.
48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        If they are not null, then they are valid.
49b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        This call is potentially slower than the matching ...Advance call. If
51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        you only need the fAdvance/fDevKern fields, call those instead.
52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkGlyph& getUnicharMetrics(SkUnichar);
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkGlyph& getGlyphIDMetrics(uint16_t);
55b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** These are variants that take the device position of the glyph. Call
57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        these only if you are drawing in subpixel mode. Passing 0, 0 is
58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        effectively the same as calling the variants w/o the extra params, tho
59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        a tiny bit slower.
60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
63b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Return the glyphID for the specified Unichar. If the char has already
65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        been seen, use the existing cache entry. If not, ask the scalercontext
66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        to compute it for us.
67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint16_t unicharToGlyph(SkUnichar);
69b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
70739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
71739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com        a character code of zero.
72739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    */
73739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    SkUnichar glyphToUnichar(uint16_t);
74739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com
75019978975b2cb2b2cfe270c72b53db0326002401ctguil@chromium.org    /** Returns the number of glyphs for this strike.
76019978975b2cb2b2cfe270c72b53db0326002401ctguil@chromium.org    */
77019978975b2cb2b2cfe270c72b53db0326002401ctguil@chromium.org    unsigned getGlyphCount();
78019978975b2cb2b2cfe270c72b53db0326002401ctguil@chromium.org
79f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID
80f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com    /** Returns the base glyph count for this strike.
81f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com    */
82f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com    unsigned getBaseGlyphCount(SkUnichar charCode) const {
83f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com        return fScalerContext->getBaseGlyphCount(charCode);
84f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com    }
85f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com#endif
86f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com
87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Return the image associated with the glyph. If it has not been generated
88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this will trigger that.
89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const void* findImage(const SkGlyph&);
91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Return the Path associated with the glyph. If it has not been generated
92bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this will trigger that.
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkPath* findPath(const SkGlyph&);
95bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
96bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Return the vertical metrics for this strike.
97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
982f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    const SkPaint::FontMetrics& getFontMetrics() const {
992f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com        return fFontMetrics;
100bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
101e216b62841acd5db9d91b63960805568259a2e0ereed@android.com
102e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    const SkDescriptor& getDescriptor() const { return *fDesc; }
103e216b62841acd5db9d91b63960805568259a2e0ereed@android.com
104b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com    SkMask::Format getMaskFormat() const {
105b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com        return fScalerContext->getMaskFormat();
106b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com    }
107b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
10825802794590081d85749a99ff8490b738d5161ffreed@google.com    bool isSubpixel() const {
10925802794590081d85749a99ff8490b738d5161ffreed@google.com        return fScalerContext->isSubpixel();
11025802794590081d85749a99ff8490b738d5161ffreed@google.com    }
11125802794590081d85749a99ff8490b738d5161ffreed@google.com
112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /*  AuxProc/Data allow a client to associate data with this cache entry.
113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        Multiple clients can use this, as their data is keyed with a function
114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        pointer. In addition to serving as a key, the function pointer is called
115bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        with the data when the glyphcache object is deleted, so the client can
116bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        cleanup their data as well. NOTE: the auxProc must not try to access
117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this glyphcache in any way, since it may be in the process of being
118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        deleted.
119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
120b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    //! If the proc is found, return true and set *dataPtr to its data
122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    //! Add a proc/data pair to the glyphcache. proc should be non-null
124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    void setAuxProc(void (*auxProc)(void*), void* auxData);
125bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
126a49cfc38fbbd85f8024eb7880de129bf15c0b4d9djsollen@google.com    SkScalerContext* getScalerContext() const { return fScalerContext; }
127a49cfc38fbbd85f8024eb7880de129bf15c0b4d9djsollen@google.com
128bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Call proc on all cache entries, stopping early if proc returns true.
129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        The proc should not create or delete caches, since it could produce
130bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        deadlock.
131bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
133b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
134bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Find a matching cache entry, and call proc() with it. If none is found
135bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        create a new one. If the proc() returns true, detach the cache and
136bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return it, otherwise leave it and return NULL.
137bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
13878341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com    static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc,
139bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                    bool (*proc)(const SkGlyphCache*, void*),
140bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                    void* context);
141b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Given a strike that was returned by either VisitCache() or DetachCache()
143bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        add it back into the global cache list (after which the caller should
144bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        not reference it anymore.
145bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static void AttachCache(SkGlyphCache*);
147bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
148bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /** Detach a strike from the global cache matching the specified descriptor.
149bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        Once detached, it can be queried/modified by the current thread, and
150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        when finished, be reattached to the global cache with AttachCache().
151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        While detached, if another request is made with the same descriptor,
152bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        a different strike will be generated. This is fine. It does mean we
153bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        can have more than 1 strike for the same descriptor, but that will
154bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        eventually get purged, and the win is that different thread will never
155bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        block each other while a strike is being used.
156bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
15778341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com    static SkGlyphCache* DetachCache(SkTypeface* typeface,
15878341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com                                     const SkDescriptor* desc) {
15978341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com        return VisitCache(typeface, desc, DetachProc, NULL);
160bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
161bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
162e216b62841acd5db9d91b63960805568259a2e0ereed@android.com#ifdef SK_DEBUG
163e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    void validate() const;
164e216b62841acd5db9d91b63960805568259a2e0ereed@android.com#else
165e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    void validate() const {}
166e216b62841acd5db9d91b63960805568259a2e0ereed@android.com#endif
167e216b62841acd5db9d91b63960805568259a2e0ereed@android.com
168e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    class AutoValidate : SkNoncopyable {
169e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    public:
170e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
171e216b62841acd5db9d91b63960805568259a2e0ereed@android.com            if (fCache) {
172e216b62841acd5db9d91b63960805568259a2e0ereed@android.com                fCache->validate();
173e216b62841acd5db9d91b63960805568259a2e0ereed@android.com            }
174e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        }
175e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        ~AutoValidate() {
176e216b62841acd5db9d91b63960805568259a2e0ereed@android.com            if (fCache) {
177e216b62841acd5db9d91b63960805568259a2e0ereed@android.com                fCache->validate();
178e216b62841acd5db9d91b63960805568259a2e0ereed@android.com            }
179e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        }
180e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        void forget() {
181e216b62841acd5db9d91b63960805568259a2e0ereed@android.com            fCache = NULL;
182e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        }
183e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    private:
184e216b62841acd5db9d91b63960805568259a2e0ereed@android.com        const SkGlyphCache* fCache;
185e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    };
186b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
187bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comprivate:
18842eacd7f693510758d71fdb07805a240d6176372reed@google.com    // we take ownership of the scalercontext
18942eacd7f693510758d71fdb07805a240d6176372reed@google.com    SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*);
190bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    ~SkGlyphCache();
191b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
192bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    enum MetricsType {
193bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        kJustAdvance_MetricsType,
194bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        kFull_MetricsType
195bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    };
196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
197bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph* lookupMetrics(uint32_t id, MetricsType);
198bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static bool DetachProc(const SkGlyphCache*, void*) { return true; }
199bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
200bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    void detach(SkGlyphCache** head) {
201bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (fPrev) {
202bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fPrev->fNext = fNext;
203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            *head = fNext;
205bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
206bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (fNext) {
207bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fNext->fPrev = fPrev;
208bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
209bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fPrev = fNext = NULL;
210bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
211b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
212bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    void attachToHead(SkGlyphCache** head) {
213bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(NULL == fPrev && NULL == fNext);
214bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (*head) {
215bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            (*head)->fPrev = this;
216bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fNext = *head;
217bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
218bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        *head = this;
219bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
220bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
221bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyphCache*       fNext, *fPrev;
222bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkDescriptor*       fDesc;
223bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScalerContext*    fScalerContext;
2242f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    SkPaint::FontMetrics fFontMetrics;
225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
226bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    enum {
2273fba7f811a7f7344b1132003eb7048884343a7acreed@google.com        kHashBits   = 8,
228bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        kHashCount  = 1 << kHashBits,
229bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        kHashMask   = kHashCount - 1
230bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    };
231bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph*            fGlyphHash[kHashCount];
232bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkTDArray<SkGlyph*> fGlyphArray;
233bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkChunkAlloc        fGlyphAlloc;
234b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int fMetricsCount, fAdvanceCount;
236bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
237bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    struct CharGlyphRec {
238bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        uint32_t    fID;    // unichar + subpixel
239bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkGlyph*    fGlyph;
240bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    };
241bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // no reason to use the same kHashCount as fGlyphHash, but we do for now
242bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    CharGlyphRec    fCharToGlyphHash[kHashCount];
243b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
244bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static inline unsigned ID2HashIndex(uint32_t id) {
24544b0009949b3b5d79999bdb0147496f05272308creed@google.com        id ^= id >> 16;
24644b0009949b3b5d79999bdb0147496f05272308creed@google.com        id ^= id >> 8;
24744b0009949b3b5d79999bdb0147496f05272308creed@google.com        return id & kHashMask;
248bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
249b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
250bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // used to track (approx) how much ram is tied-up in this cache
251bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    size_t  fMemoryUsed;
252bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
253bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    struct AuxProcRec {
254bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        AuxProcRec* fNext;
255bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        void (*fProc)(void*);
256bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        void* fData;
257bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    };
258bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    AuxProcRec* fAuxProcList;
259bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    void invokeAndRemoveAuxProcs();
260bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
261bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // This relies on the caller to have already acquired the mutex to access the global cache
262bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
263bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
264bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    inline static SkGlyphCache* FindTail(SkGlyphCache* head);
265bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
266bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    friend class SkGlyphCache_Globals;
267bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com};
268bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
269bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comclass SkAutoGlyphCache {
270bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.compublic:
271bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
27278341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com    SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) {
27378341a3cbe1c3e6d9aa6aa1ff390aa9aac1ede4freed@google.com        fCache = SkGlyphCache::DetachCache(typeface, desc);
274bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
2754efd34721cb0e87078ae06a03cd905ba8e8b7c29bungeman@google.com    SkAutoGlyphCache(const SkPaint& paint,
2764efd34721cb0e87078ae06a03cd905ba8e8b7c29bungeman@google.com                     const SkDeviceProperties* deviceProperties,
2774efd34721cb0e87078ae06a03cd905ba8e8b7c29bungeman@google.com                     const SkMatrix* matrix) {
2784efd34721cb0e87078ae06a03cd905ba8e8b7c29bungeman@google.com        fCache = paint.detachCache(deviceProperties, matrix);
279bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
2804b3bf9c2c863ad28e883f6f8372f46d5876480f5mike@reedtribe.org    ~SkAutoGlyphCache() {
2814b3bf9c2c863ad28e883f6f8372f46d5876480f5mike@reedtribe.org        if (fCache) {
282bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkGlyphCache::AttachCache(fCache);
2834b3bf9c2c863ad28e883f6f8372f46d5876480f5mike@reedtribe.org        }
284bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
285bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2864b3bf9c2c863ad28e883f6f8372f46d5876480f5mike@reedtribe.org    SkGlyphCache* getCache() const { return fCache; }
287bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2884b3bf9c2c863ad28e883f6f8372f46d5876480f5mike@reedtribe.org    void release() {
2894b3bf9c2c863ad28e883f6f8372f46d5876480f5mike@reedtribe.org        if (fCache) {
290bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkGlyphCache::AttachCache(fCache);
291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fCache = NULL;
292bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
293bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
2944b3bf9c2c863ad28e883f6f8372f46d5876480f5mike@reedtribe.org
295bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comprivate:
296bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyphCache*   fCache;
297b41ee2a22d7d651c58c173955a5dbdec23f2da45reed@google.com
298bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static bool DetachProc(const SkGlyphCache*, void*);
299bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com};
300bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
301bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
302