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