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