Home | History | Annotate | Download | only in core
      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 
     20 class SkTraceMemoryDump;
     21 
     22 class 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 */
     34 class SkGlyphCache {
     35 public:
     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 
    188 private:
    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 
    275 class SkAutoGlyphCache : public skstd::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor> {
    276 public:
    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     {}
    296 private:
    297     using INHERITED = skstd::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor>;
    298 };
    299 
    300 class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCache {
    301 public:
    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