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