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     /** Return the image associated with the glyph. If it has not been generated
     81         this will trigger that.
     82     */
     83     const void* findImage(const SkGlyph&);
     84     /** Return the Path associated with the glyph. If it has not been generated
     85         this will trigger that.
     86     */
     87     const SkPath* findPath(const SkGlyph&);
     88 
     89     /** Return the vertical metrics for this strike.
     90     */
     91     const SkPaint::FontMetrics& getFontMetricsY() const {
     92         return fFontMetricsY;
     93     }
     94 
     95     /*  AuxProc/Data allow a client to associate data with this cache entry.
     96         Multiple clients can use this, as their data is keyed with a function
     97         pointer. In addition to serving as a key, the function pointer is called
     98         with the data when the glyphcache object is deleted, so the client can
     99         cleanup their data as well. NOTE: the auxProc must not try to access
    100         this glyphcache in any way, since it may be in the process of being
    101         deleted.
    102     */
    103 
    104     //! If the proc is found, return true and set *dataPtr to its data
    105     bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
    106     //! Add a proc/data pair to the glyphcache. proc should be non-null
    107     void setAuxProc(void (*auxProc)(void*), void* auxData);
    108     //! If found, remove the proc/data pair from the glyphcache (does not
    109     //  call the proc)
    110     void removeAuxProc(void (*auxProc)(void*));
    111 
    112     /** Call proc on all cache entries, stopping early if proc returns true.
    113         The proc should not create or delete caches, since it could produce
    114         deadlock.
    115     */
    116     static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
    117 
    118     /** Find a matching cache entry, and call proc() with it. If none is found
    119         create a new one. If the proc() returns true, detach the cache and
    120         return it, otherwise leave it and return NULL.
    121     */
    122     static SkGlyphCache* VisitCache(const SkDescriptor* desc,
    123                                     bool (*proc)(const SkGlyphCache*, void*),
    124                                     void* context);
    125 
    126     /** Given a strike that was returned by either VisitCache() or DetachCache()
    127         add it back into the global cache list (after which the caller should
    128         not reference it anymore.
    129     */
    130     static void AttachCache(SkGlyphCache*);
    131 
    132     /** Detach a strike from the global cache matching the specified descriptor.
    133         Once detached, it can be queried/modified by the current thread, and
    134         when finished, be reattached to the global cache with AttachCache().
    135         While detached, if another request is made with the same descriptor,
    136         a different strike will be generated. This is fine. It does mean we
    137         can have more than 1 strike for the same descriptor, but that will
    138         eventually get purged, and the win is that different thread will never
    139         block each other while a strike is being used.
    140     */
    141     static SkGlyphCache* DetachCache(const SkDescriptor* desc) {
    142         return VisitCache(desc, DetachProc, NULL);
    143     }
    144 
    145     /** Return the approximate number of bytes used by the font cache
    146     */
    147     static size_t GetCacheUsed();
    148 
    149     /** This can be called to purge old font data, in an attempt to free
    150         enough bytes such that the font cache is not using more than the
    151         specified number of bytes. It is thread-safe, and may be called at
    152         any time.
    153         Return true if some amount of the cache was purged.
    154     */
    155     static bool SetCacheUsed(size_t bytesUsed);
    156 
    157 private:
    158     SkGlyphCache(const SkDescriptor*);
    159     ~SkGlyphCache();
    160 
    161     enum MetricsType {
    162         kJustAdvance_MetricsType,
    163         kFull_MetricsType
    164     };
    165 
    166     SkGlyph* lookupMetrics(uint32_t id, MetricsType);
    167     static bool DetachProc(const SkGlyphCache*, void*) { return true; }
    168 
    169     void detach(SkGlyphCache** head) {
    170         if (fPrev) {
    171             fPrev->fNext = fNext;
    172         } else {
    173             *head = fNext;
    174         }
    175         if (fNext) {
    176             fNext->fPrev = fPrev;
    177         }
    178         fPrev = fNext = NULL;
    179     }
    180 
    181     void attachToHead(SkGlyphCache** head) {
    182         SkASSERT(NULL == fPrev && NULL == fNext);
    183         if (*head) {
    184             (*head)->fPrev = this;
    185             fNext = *head;
    186         }
    187         *head = this;
    188     }
    189 
    190     SkGlyphCache*       fNext, *fPrev;
    191     SkDescriptor*       fDesc;
    192     SkScalerContext*    fScalerContext;
    193     SkPaint::FontMetrics fFontMetricsY;
    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     SkChunkAlloc        fImageAlloc;
    204 
    205     int fMetricsCount, fAdvanceCount;
    206 
    207     struct CharGlyphRec {
    208         uint32_t    fID;    // unichar + subpixel
    209         SkGlyph*    fGlyph;
    210     };
    211     // no reason to use the same kHashCount as fGlyphHash, but we do for now
    212     CharGlyphRec    fCharToGlyphHash[kHashCount];
    213 
    214     enum {
    215         // shift so that the top bits fall into kHashBits region
    216         kShiftForHashIndex = SkGlyph::kSubShift +
    217                              SkGlyph::kSubBits*2 -
    218                              kHashBits
    219     };
    220 
    221     static inline unsigned ID2HashIndex(uint32_t id) {
    222         return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
    223     }
    224 
    225     // used to track (approx) how much ram is tied-up in this cache
    226     size_t  fMemoryUsed;
    227 
    228     struct AuxProcRec {
    229         AuxProcRec* fNext;
    230         void (*fProc)(void*);
    231         void* fData;
    232     };
    233     AuxProcRec* fAuxProcList;
    234     void invokeAndRemoveAuxProcs();
    235 
    236     // This relies on the caller to have already acquired the mutex to access the global cache
    237     static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded);
    238 
    239     inline static SkGlyphCache* FindTail(SkGlyphCache* head);
    240     static size_t ComputeMemoryUsed(const SkGlyphCache* head);
    241 
    242     friend class SkGlyphCache_Globals;
    243 };
    244 
    245 class SkAutoGlyphCache {
    246 public:
    247     SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
    248     SkAutoGlyphCache(const SkDescriptor* desc)
    249     {
    250         fCache = SkGlyphCache::DetachCache(desc);
    251     }
    252     SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix)
    253     {
    254         fCache = paint.detachCache(matrix);
    255     }
    256     ~SkAutoGlyphCache()
    257     {
    258         if (fCache)
    259             SkGlyphCache::AttachCache(fCache);
    260     }
    261 
    262     SkGlyphCache*   getCache() const { return fCache; }
    263 
    264     void release()
    265     {
    266         if (fCache)
    267         {
    268             SkGlyphCache::AttachCache(fCache);
    269             fCache = NULL;
    270         }
    271     }
    272 private:
    273     SkGlyphCache*   fCache;
    274 
    275     static bool DetachProc(const SkGlyphCache*, void*);
    276 };
    277 
    278 #endif
    279 
    280