Home | History | Annotate | Download | only in core
      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 
     21 struct SkDeviceProperties;
     22 class SkPaint;
     23 
     24 class 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 cached, 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 */
     37 class SkGlyphCache {
     38 public:
     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     /** Return the image associated with the glyph. If it has not been generated
     80         this will trigger that.
     81     */
     82     const void* findImage(const SkGlyph&);
     83     /** Return the Path associated with the glyph. If it has not been generated
     84         this will trigger that.
     85     */
     86     const SkPath* findPath(const SkGlyph&);
     87     /** Return the distance field associated with the glyph. If it has not been generated
     88      this will trigger that.
     89      */
     90     const void* findDistanceField(const SkGlyph&);
     91 
     92     /** Return the vertical metrics for this strike.
     93     */
     94     const SkPaint::FontMetrics& getFontMetrics() const {
     95         return fFontMetrics;
     96     }
     97 
     98     const SkDescriptor& getDescriptor() const { return *fDesc; }
     99 
    100     SkMask::Format getMaskFormat() const {
    101         return fScalerContext->getMaskFormat();
    102     }
    103 
    104     bool isSubpixel() const {
    105         return fScalerContext->isSubpixel();
    106     }
    107 
    108     /*  AuxProc/Data allow a client to associate data with this cache entry.
    109         Multiple clients can use this, as their data is keyed with a function
    110         pointer. In addition to serving as a key, the function pointer is called
    111         with the data when the glyphcache object is deleted, so the client can
    112         cleanup their data as well. NOTE: the auxProc must not try to access
    113         this glyphcache in any way, since it may be in the process of being
    114         deleted.
    115     */
    116 
    117     //! If the proc is found, return true and set *dataPtr to its data
    118     bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
    119     //! Add a proc/data pair to the glyphcache. proc should be non-null
    120     void setAuxProc(void (*auxProc)(void*), void* auxData);
    121 
    122     SkScalerContext* getScalerContext() const { return fScalerContext; }
    123 
    124     /** Find a matching cache entry, and call proc() with it. If none is found
    125         create a new one. If the proc() returns true, detach the cache and
    126         return it, otherwise leave it and return NULL.
    127     */
    128     static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc,
    129                                     bool (*proc)(const SkGlyphCache*, void*),
    130                                     void* context);
    131 
    132     /** Given a strike that was returned by either VisitCache() or DetachCache()
    133         add it back into the global cache list (after which the caller should
    134         not reference it anymore.
    135     */
    136     static void AttachCache(SkGlyphCache*);
    137 
    138     /** Detach a strike from the global cache matching the specified descriptor.
    139         Once detached, it can be queried/modified by the current thread, and
    140         when finished, be reattached to the global cache with AttachCache().
    141         While detached, if another request is made with the same descriptor,
    142         a different strike will be generated. This is fine. It does mean we
    143         can have more than 1 strike for the same descriptor, but that will
    144         eventually get purged, and the win is that different thread will never
    145         block each other while a strike is being used.
    146     */
    147     static SkGlyphCache* DetachCache(SkTypeface* typeface,
    148                                      const SkDescriptor* desc) {
    149         return VisitCache(typeface, desc, DetachProc, NULL);
    150     }
    151 
    152 #ifdef SK_DEBUG
    153     void validate() const;
    154 #else
    155     void validate() const {}
    156 #endif
    157 
    158     class AutoValidate : SkNoncopyable {
    159     public:
    160         AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
    161             if (fCache) {
    162                 fCache->validate();
    163             }
    164         }
    165         ~AutoValidate() {
    166             if (fCache) {
    167                 fCache->validate();
    168             }
    169         }
    170         void forget() {
    171             fCache = NULL;
    172         }
    173     private:
    174         const SkGlyphCache* fCache;
    175     };
    176 
    177 private:
    178     // we take ownership of the scalercontext
    179     SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*);
    180     ~SkGlyphCache();
    181 
    182     enum MetricsType {
    183         kJustAdvance_MetricsType,
    184         kFull_MetricsType
    185     };
    186 
    187     SkGlyph* lookupMetrics(uint32_t id, MetricsType);
    188     static bool DetachProc(const SkGlyphCache*, void*) { return true; }
    189 
    190     SkGlyphCache*       fNext, *fPrev;
    191     SkDescriptor*       fDesc;
    192     SkScalerContext*    fScalerContext;
    193     SkPaint::FontMetrics fFontMetrics;
    194 
    195     enum {
    196         kHashBits   = 8,
    197         kHashCount  = 1 << kHashBits,
    198         kHashMask   = kHashCount - 1
    199     };
    200     SkGlyph*            fGlyphHash[kHashCount];
    201     SkTDArray<SkGlyph*> fGlyphArray;
    202     SkChunkAlloc        fGlyphAlloc;
    203 
    204     struct CharGlyphRec {
    205         uint32_t    fID;    // unichar + subpixel
    206         SkGlyph*    fGlyph;
    207     };
    208     // no reason to use the same kHashCount as fGlyphHash, but we do for now
    209     CharGlyphRec    fCharToGlyphHash[kHashCount];
    210 
    211     static inline unsigned ID2HashIndex(uint32_t id) {
    212         id ^= id >> 16;
    213         id ^= id >> 8;
    214         return id & kHashMask;
    215     }
    216 
    217     // used to track (approx) how much ram is tied-up in this cache
    218     size_t  fMemoryUsed;
    219 
    220     struct AuxProcRec {
    221         AuxProcRec* fNext;
    222         void (*fProc)(void*);
    223         void* fData;
    224     };
    225     AuxProcRec* fAuxProcList;
    226     void invokeAndRemoveAuxProcs();
    227 
    228     inline static SkGlyphCache* FindTail(SkGlyphCache* head);
    229 
    230     friend class SkGlyphCache_Globals;
    231 };
    232 
    233 class SkAutoGlyphCacheBase {
    234 public:
    235     SkGlyphCache* getCache() const { return fCache; }
    236 
    237     void release() {
    238         if (fCache) {
    239             SkGlyphCache::AttachCache(fCache);
    240             fCache = NULL;
    241         }
    242     }
    243 
    244 protected:
    245     // Hide the constructors so we can't create one of these directly.
    246     // Create SkAutoGlyphCache or SkAutoGlyphCacheNoCache instead.
    247     SkAutoGlyphCacheBase(SkGlyphCache* cache) : fCache(cache) {}
    248     SkAutoGlyphCacheBase(SkTypeface* typeface, const SkDescriptor* desc) {
    249         fCache = SkGlyphCache::DetachCache(typeface, desc);
    250     }
    251     SkAutoGlyphCacheBase(const SkPaint& paint,
    252                          const SkDeviceProperties* deviceProperties,
    253                          const SkMatrix* matrix) {
    254         fCache = NULL;
    255     }
    256     SkAutoGlyphCacheBase() {
    257         fCache = NULL;
    258     }
    259     ~SkAutoGlyphCacheBase() {
    260         if (fCache) {
    261             SkGlyphCache::AttachCache(fCache);
    262         }
    263     }
    264 
    265     SkGlyphCache*   fCache;
    266 
    267 private:
    268     static bool DetachProc(const SkGlyphCache*, void*);
    269 };
    270 
    271 class SkAutoGlyphCache : public SkAutoGlyphCacheBase {
    272 public:
    273     SkAutoGlyphCache(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {}
    274     SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) :
    275         SkAutoGlyphCacheBase(typeface, desc) {}
    276     SkAutoGlyphCache(const SkPaint& paint,
    277                      const SkDeviceProperties* deviceProperties,
    278                      const SkMatrix* matrix) {
    279         fCache = paint.detachCache(deviceProperties, matrix, false);
    280     }
    281 
    282 private:
    283     SkAutoGlyphCache() : SkAutoGlyphCacheBase() {}
    284 };
    285 #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache)
    286 
    287 class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCacheBase {
    288 public:
    289     SkAutoGlyphCacheNoGamma(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {}
    290     SkAutoGlyphCacheNoGamma(SkTypeface* typeface, const SkDescriptor* desc) :
    291         SkAutoGlyphCacheBase(typeface, desc) {}
    292     SkAutoGlyphCacheNoGamma(const SkPaint& paint,
    293                             const SkDeviceProperties* deviceProperties,
    294                             const SkMatrix* matrix) {
    295         fCache = paint.detachCache(deviceProperties, matrix, true);
    296     }
    297 
    298 private:
    299     SkAutoGlyphCacheNoGamma() : SkAutoGlyphCacheBase() {}
    300 };
    301 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma)
    302 
    303 #endif
    304