Home | History | Annotate | Download | only in core
      1 /* libs/graphics/sgl/SkGlyphCache.h
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #ifndef SkGlyphCache_DEFINED
     19 #define SkGlyphCache_DEFINED
     20 
     21 #include "SkBitmap.h"
     22 #include "SkChunkAlloc.h"
     23 #include "SkDescriptor.h"
     24 #include "SkScalerContext.h"
     25 #include "SkTemplates.h"
     26 
     27 class SkPaint;
     28 
     29 class SkGlyphCache_Globals;
     30 
     31 /** \class SkGlyphCache
     32 
     33     This class represents a strike: a specific combination of typeface, size,
     34     matrix, etc., and holds the glyphs for that strike. Calling any of the
     35     getUnichar.../getGlyphID... methods will return the requested glyph,
     36     either instantly if it is already cahced, or by first generating it and then
     37     adding it to the strike.
     38 
     39     The strikes are held in a global list, available to all threads. To interact
     40     with one, call either VisitCache() or DetachCache().
     41 */
     42 class SkGlyphCache {
     43 public:
     44     /** Returns a glyph with valid fAdvance and fDevKern fields.
     45         The remaining fields may be valid, but that is not guaranteed. If you
     46         require those, call getUnicharMetrics or getGlyphIDMetrics instead.
     47     */
     48     const SkGlyph& getUnicharAdvance(SkUnichar);
     49     const SkGlyph& getGlyphIDAdvance(uint16_t);
     50 
     51     /** Returns a glyph with all fields valid except fImage and fPath, which
     52         may be null. If they are null, call findImage or findPath for those.
     53         If they are not null, then they are valid.
     54 
     55         This call is potentially slower than the matching ...Advance call. If
     56         you only need the fAdvance/fDevKern fields, call those instead.
     57     */
     58     const SkGlyph& getUnicharMetrics(SkUnichar);
     59     const SkGlyph& getGlyphIDMetrics(uint16_t);
     60 
     61     /** These are variants that take the device position of the glyph. Call
     62         these only if you are drawing in subpixel mode. Passing 0, 0 is
     63         effectively the same as calling the variants w/o the extra params, tho
     64         a tiny bit slower.
     65     */
     66     const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
     67     const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
     68 
     69     /** Return the glyphID for the specified Unichar. If the char has already
     70         been seen, use the existing cache entry. If not, ask the scalercontext
     71         to compute it for us.
     72     */
     73     uint16_t unicharToGlyph(SkUnichar);
     74 
     75     /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
     76         a character code of zero.
     77     */
     78     SkUnichar glyphToUnichar(uint16_t);
     79 
     80     /** Returns the number of glyphs for this strike.
     81     */
     82     unsigned getGlyphCount();
     83 
     84     /** Return the image associated with the glyph. If it has not been generated
     85         this will trigger that.
     86     */
     87     const void* findImage(const SkGlyph&);
     88     /** Return the Path associated with the glyph. If it has not been generated
     89         this will trigger that.
     90     */
     91     const SkPath* findPath(const SkGlyph&);
     92 
     93     /** Return the vertical metrics for this strike.
     94     */
     95     const SkPaint::FontMetrics& getFontMetricsY() const {
     96         return fFontMetricsY;
     97     }
     98 
     99     const SkDescriptor& getDescriptor() const { return *fDesc; }
    100 
    101     SkMask::Format getMaskFormat() const {
    102         return fScalerContext->getMaskFormat();
    103     }
    104 
    105     /*  AuxProc/Data allow a client to associate data with this cache entry.
    106         Multiple clients can use this, as their data is keyed with a function
    107         pointer. In addition to serving as a key, the function pointer is called
    108         with the data when the glyphcache object is deleted, so the client can
    109         cleanup their data as well. NOTE: the auxProc must not try to access
    110         this glyphcache in any way, since it may be in the process of being
    111         deleted.
    112     */
    113 
    114     //! If the proc is found, return true and set *dataPtr to its data
    115     bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
    116     //! Add a proc/data pair to the glyphcache. proc should be non-null
    117     void setAuxProc(void (*auxProc)(void*), void* auxData);
    118     //! If found, remove the proc/data pair from the glyphcache (does not
    119     //  call the proc)
    120     void removeAuxProc(void (*auxProc)(void*));
    121 
    122     /** Call proc on all cache entries, stopping early if proc returns true.
    123         The proc should not create or delete caches, since it could produce
    124         deadlock.
    125     */
    126     static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
    127 
    128     /** Find a matching cache entry, and call proc() with it. If none is found
    129         create a new one. If the proc() returns true, detach the cache and
    130         return it, otherwise leave it and return NULL.
    131     */
    132     static SkGlyphCache* VisitCache(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()
    137         add it back into the global cache list (after which the caller should
    138         not reference it anymore.
    139     */
    140     static void AttachCache(SkGlyphCache*);
    141 
    142     /** Detach a strike from the global cache matching the specified descriptor.
    143         Once detached, it can be queried/modified by the current thread, and
    144         when finished, be reattached to the global cache with AttachCache().
    145         While detached, if another request is made with the same descriptor,
    146         a different strike will be generated. This is fine. It does mean we
    147         can have more than 1 strike for the same descriptor, but that will
    148         eventually get purged, and the win is that different thread will never
    149         block each other while a strike is being used.
    150     */
    151     static SkGlyphCache* DetachCache(const SkDescriptor* desc) {
    152         return VisitCache(desc, DetachProc, NULL);
    153     }
    154 
    155     /** Return the approximate number of bytes used by the font cache
    156     */
    157     static size_t GetCacheUsed();
    158 
    159     /** This can be called to purge old font data, in an attempt to free
    160         enough bytes such that the font cache is not using more than the
    161         specified number of bytes. It is thread-safe, and may be called at
    162         any time.
    163         Return true if some amount of the cache was purged.
    164     */
    165     static bool SetCacheUsed(size_t bytesUsed);
    166 
    167 #ifdef SK_DEBUG
    168     void validate() const;
    169 #else
    170     void validate() const {}
    171 #endif
    172 
    173     class AutoValidate : SkNoncopyable {
    174     public:
    175         AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
    176             if (fCache) {
    177                 fCache->validate();
    178             }
    179         }
    180         ~AutoValidate() {
    181             if (fCache) {
    182                 fCache->validate();
    183             }
    184         }
    185         void forget() {
    186             fCache = NULL;
    187         }
    188     private:
    189         const SkGlyphCache* fCache;
    190     };
    191 
    192 private:
    193     SkGlyphCache(const SkDescriptor*);
    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     void detach(SkGlyphCache** head) {
    205         if (fPrev) {
    206             fPrev->fNext = fNext;
    207         } else {
    208             *head = fNext;
    209         }
    210         if (fNext) {
    211             fNext->fPrev = fPrev;
    212         }
    213         fPrev = fNext = NULL;
    214     }
    215 
    216     void attachToHead(SkGlyphCache** head) {
    217         SkASSERT(NULL == fPrev && NULL == fNext);
    218         if (*head) {
    219             (*head)->fPrev = this;
    220             fNext = *head;
    221         }
    222         *head = this;
    223     }
    224 
    225     SkGlyphCache*       fNext, *fPrev;
    226     SkDescriptor*       fDesc;
    227     SkScalerContext*    fScalerContext;
    228     SkPaint::FontMetrics fFontMetricsY;
    229 
    230     enum {
    231         kHashBits   = 8,
    232         kHashCount  = 1 << kHashBits,
    233         kHashMask   = kHashCount - 1
    234     };
    235     SkGlyph*            fGlyphHash[kHashCount];
    236     SkTDArray<SkGlyph*> fGlyphArray;
    237     SkChunkAlloc        fGlyphAlloc;
    238     SkChunkAlloc        fImageAlloc;
    239 
    240     int fMetricsCount, fAdvanceCount;
    241 
    242     struct CharGlyphRec {
    243         uint32_t    fID;    // unichar + subpixel
    244         SkGlyph*    fGlyph;
    245     };
    246     // no reason to use the same kHashCount as fGlyphHash, but we do for now
    247     CharGlyphRec    fCharToGlyphHash[kHashCount];
    248 
    249     enum {
    250         // shift so that the top bits fall into kHashBits region
    251         kShiftForHashIndex = SkGlyph::kSubShift +
    252                              SkGlyph::kSubBits*2 -
    253                              kHashBits
    254     };
    255 
    256     static inline unsigned ID2HashIndex(uint32_t id) {
    257         return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
    258     }
    259 
    260     // used to track (approx) how much ram is tied-up in this cache
    261     size_t  fMemoryUsed;
    262 
    263     struct AuxProcRec {
    264         AuxProcRec* fNext;
    265         void (*fProc)(void*);
    266         void* fData;
    267     };
    268     AuxProcRec* fAuxProcList;
    269     void invokeAndRemoveAuxProcs();
    270 
    271     // This relies on the caller to have already acquired the mutex to access the global cache
    272     static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
    273 
    274     inline static SkGlyphCache* FindTail(SkGlyphCache* head);
    275     static size_t ComputeMemoryUsed(const SkGlyphCache* head);
    276 
    277     friend class SkGlyphCache_Globals;
    278 };
    279 
    280 class SkAutoGlyphCache {
    281 public:
    282     SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
    283     SkAutoGlyphCache(const SkDescriptor* desc) {
    284         fCache = SkGlyphCache::DetachCache(desc);
    285     }
    286     SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix) {
    287         fCache = paint.detachCache(matrix);
    288     }
    289     ~SkAutoGlyphCache() {
    290         if (fCache) {
    291             SkGlyphCache::AttachCache(fCache);
    292         }
    293     }
    294 
    295     SkGlyphCache* getCache() const { return fCache; }
    296 
    297     void release() {
    298         if (fCache) {
    299             SkGlyphCache::AttachCache(fCache);
    300             fCache = NULL;
    301         }
    302     }
    303 
    304 private:
    305     SkGlyphCache*   fCache;
    306 
    307     static bool DetachProc(const SkGlyphCache*, void*);
    308 };
    309 
    310 #endif
    311 
    312