1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
5 */
6
7#ifndef SkGlyphCache_DEFINED
8#define SkGlyphCache_DEFINED
9
10#include "SkBitmap.h"
11#include "SkChunkAlloc.h"
12#include "SkDescriptor.h"
13#include "SkGlyph.h"
14#include "SkPaint.h"
15#include "SkTHash.h"
16#include "SkScalerContext.h"
17#include "SkTemplates.h"
18#include "SkTDArray.h"
19
20class SkTraceMemoryDump;
21
22class SkGlyphCache_Globals;
23
24/** \class SkGlyphCache
25
26    This class represents a strike: a specific combination of typeface, size, matrix, etc., and
27    holds the glyphs for that strike. Calling any of the getUnichar.../getGlyphID... methods will
28    return the requested glyph, either instantly if it is already cached, or by first generating
29    it and then adding it to the strike.
30
31    The strikes are held in a global list, available to all threads. To interact with one, call
32    either VisitCache() or DetachCache().
33*/
34class SkGlyphCache {
35public:
36    /** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be
37        valid, but that is not guaranteed. If you require those, call getUnicharMetrics or
38        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 may be null. If they
44        are null, call findImage or findPath for those. If they are not null, then they are valid.
45
46        This call is potentially slower than the matching ...Advance call. If you only need the
47        fAdvance/fDevKern fields, call those instead.
48    */
49    const SkGlyph& getUnicharMetrics(SkUnichar);
50    const SkGlyph& getGlyphIDMetrics(uint16_t);
51
52    /** These are variants that take the device position of the glyph. Call these only if you are
53        drawing in subpixel mode. Passing 0, 0 is effectively the same as calling the variants
54        w/o the extra params, though a tiny bit slower.
55    */
56    const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
57    const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
58
59    /** Return the glyphID for the specified Unichar. If the char has already been seen, use the
60        existing cache entry. If not, ask the scalercontext to compute it for us.
61    */
62    uint16_t unicharToGlyph(SkUnichar);
63
64    /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to a character code of zero.
65    */
66    SkUnichar glyphToUnichar(uint16_t);
67
68    /** Returns the number of glyphs for this strike.
69    */
70    unsigned getGlyphCount() const;
71
72    /** Return the number of glyphs currently cached. */
73    int countCachedGlyphs() const;
74
75    /** Return the image associated with the glyph. If it has not been generated this will
76        trigger that.
77    */
78    const void* findImage(const SkGlyph&);
79
80    /** If the advance axis intersects the glyph's path, append the positions scaled and offset
81        to the array (if non-null), and set the count to the updated array length.
82    */
83    void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
84                        bool yAxis, SkGlyph* , SkScalar* array, int* count);
85
86    /** Return the Path associated with the glyph. If it has not been generated this will trigger
87        that.
88    */
89    const SkPath* findPath(const SkGlyph&);
90
91    /** Return the vertical metrics for this strike.
92    */
93    const SkPaint::FontMetrics& getFontMetrics() const {
94        return fFontMetrics;
95    }
96
97    const SkDescriptor& getDescriptor() const { return *fDesc; }
98
99    SkMask::Format getMaskFormat() const {
100        return fScalerContext->getMaskFormat();
101    }
102
103    bool isSubpixel() const {
104        return fScalerContext->isSubpixel();
105    }
106
107    /** Return the approx RAM usage for this cache. */
108    size_t getMemoryUsed() const { return fMemoryUsed; }
109
110    void dump() const;
111
112    /** AuxProc/Data allow a client to associate data with this cache entry. Multiple clients can
113        use this, as their data is keyed with a function pointer. In addition to serving as a
114        key, the function pointer is called with the data when the glyphcache object is deleted,
115        so the client can cleanup their data as well.
116        NOTE: the auxProc must not try to access this glyphcache in any way, since it may be in
117        the process of being deleted.
118    */
119
120    //! If the proc is found, return true and set *dataPtr to its data
121    bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
122
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    /** Find a matching cache entry, and call proc() with it. If none is found create a new one.
129        If the proc() returns true, detach the cache and return it, otherwise leave it and return
130        nullptr.
131    */
132    static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc,
133                                    bool (*proc)(const SkGlyphCache*, void*),
134                                    void* context);
135
136    /** Given a strike that was returned by either VisitCache() or DetachCache() add it back into
137        the global cache list (after which the caller should not reference it anymore.
138    */
139    static void AttachCache(SkGlyphCache*);
140    using AttachCacheFunctor = SkFunctionWrapper<void, SkGlyphCache, AttachCache>;
141
142    /** Detach a strike from the global cache matching the specified descriptor. Once detached,
143        it can be queried/modified by the current thread, and when finished, be reattached to the
144        global cache with AttachCache(). While detached, if another request is made with the same
145        descriptor, a different strike will be generated. This is fine. It does mean we can have
146        more than 1 strike for the same descriptor, but that will eventually get purged, and the
147        win is that different thread will never block each other while a strike is being used.
148    */
149    static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkDescriptor* desc) {
150        return VisitCache(typeface, desc, DetachProc, nullptr);
151    }
152
153    static void Dump();
154
155    /** Dump memory usage statistics of all the attaches caches in the process using the
156        SkTraceMemoryDump interface.
157    */
158    static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
159
160    typedef void (*Visitor)(const SkGlyphCache&, void* context);
161    static void VisitAll(Visitor, void* context);
162
163#ifdef SK_DEBUG
164    void validate() const;
165#else
166    void validate() const {}
167#endif
168
169    class AutoValidate : SkNoncopyable {
170    public:
171        AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
172            if (fCache) {
173                fCache->validate();
174            }
175        }
176        ~AutoValidate() {
177            if (fCache) {
178                fCache->validate();
179            }
180        }
181        void forget() {
182            fCache = nullptr;
183        }
184    private:
185        const SkGlyphCache* fCache;
186    };
187
188private:
189    friend class SkGlyphCache_Globals;
190
191    enum MetricsType {
192        kJustAdvance_MetricsType,
193        kFull_MetricsType
194    };
195
196    enum {
197        kHashBits           = 8,
198        kHashCount          = 1 << kHashBits,
199        kHashMask           = kHashCount - 1
200    };
201
202    typedef uint32_t PackedGlyphID;    // glyph-index + subpixel-pos
203    typedef uint32_t PackedUnicharID;  // unichar + subpixel-pos
204
205    struct CharGlyphRec {
206        PackedUnicharID    fPackedUnicharID;
207        PackedGlyphID      fPackedGlyphID;
208    };
209
210    struct AuxProcRec {
211        AuxProcRec* fNext;
212        void (*fProc)(void*);
213        void* fData;
214    };
215
216    // SkGlyphCache takes ownership of the scalercontext.
217    SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*);
218    ~SkGlyphCache();
219
220    // Return the SkGlyph* associated with MakeID. The id parameter is the
221    // combined glyph/x/y id generated by MakeID. If it is just a glyph id
222    // then x and y are assumed to be zero.
223    SkGlyph* lookupByPackedGlyphID(PackedGlyphID packedGlyphID, MetricsType type);
224
225    // Return a SkGlyph* associated with unicode id and position x and y.
226    SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed y = 0);
227
228    // Return a new SkGlyph for the glyph ID and subpixel position id. Limit the amount
229    // of work
230    // using type.
231    SkGlyph* allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType type);
232
233    static bool DetachProc(const SkGlyphCache*, void*) { return true; }
234
235    // The id arg is a combined id generated by MakeID.
236    CharGlyphRec* getCharGlyphRec(PackedUnicharID id);
237
238    void invokeAndRemoveAuxProcs();
239
240    inline static SkGlyphCache* FindTail(SkGlyphCache* head);
241
242    static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale,
243                              SkScalar xPos, SkScalar* array, int* count);
244    static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept);
245    static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2],
246                          bool yAxis, SkGlyph::Intercept* intercept);
247    static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis,
248                        SkGlyph::Intercept* intercept);
249    static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis,
250                        SkGlyph::Intercept* intercept);
251    static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis,
252                         SkGlyph::Intercept* intercept);
253    static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph,
254                                                 const SkScalar bounds[2]);
255
256    SkGlyphCache*          fNext;
257    SkGlyphCache*          fPrev;
258    SkDescriptor* const    fDesc;
259    SkScalerContext* const fScalerContext;
260    SkPaint::FontMetrics   fFontMetrics;
261
262    // Map from a combined GlyphID and sub-pixel position to a SkGlyph.
263    SkTHashTable<SkGlyph, PackedGlyphID, SkGlyph::HashTraits> fGlyphMap;
264
265    SkChunkAlloc           fGlyphAlloc;
266
267    SkAutoTArray<CharGlyphRec> fPackedUnicharIDToPackedGlyphID;
268
269    // used to track (approx) how much ram is tied-up in this cache
270    size_t                 fMemoryUsed;
271
272    AuxProcRec*            fAuxProcList;
273};
274
275class SkAutoGlyphCache : public skstd::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor> {
276public:
277    /** deprecated: use get() */
278    SkGlyphCache* getCache() const { return this->get(); }
279
280    SkAutoGlyphCache(SkGlyphCache* cache) : INHERITED(cache) {}
281    SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc)
282        : INHERITED(SkGlyphCache::DetachCache(typeface, desc))
283    {}
284    /** deprecated: always enables fake gamma */
285    SkAutoGlyphCache(const SkPaint& paint,
286                     const SkSurfaceProps* surfaceProps,
287                     const SkMatrix* matrix)
288        : INHERITED(paint.detachCache(surfaceProps, SkPaint::FakeGamma::On, matrix))
289    {}
290    SkAutoGlyphCache(const SkPaint& paint,
291                     const SkSurfaceProps* surfaceProps,
292                     SkPaint::FakeGamma fakeGamma,
293                     const SkMatrix* matrix)
294        : INHERITED(paint.detachCache(surfaceProps, fakeGamma, matrix))
295    {}
296private:
297    using INHERITED = skstd::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor>;
298};
299
300class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCache {
301public:
302    SkAutoGlyphCacheNoGamma(const SkPaint& paint,
303                            const SkSurfaceProps* surfaceProps,
304                            const SkMatrix* matrix)
305        : SkAutoGlyphCache(paint, surfaceProps, SkPaint::FakeGamma::Off, matrix)
306    {}
307};
308#define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache)
309#define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma)
310
311#endif
312