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