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 19class SkPaint; 20 21class 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*/ 34class SkGlyphCache { 35public: 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 */ 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 */ 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 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 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(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(const SkDescriptor* desc) { 158 return VisitCache(desc, DetachProc, NULL); 159 } 160 161 /** Return the approximate number of bytes used by the font cache 162 */ 163 static size_t GetCacheUsed(); 164 165 /** This can be called to purge old font data, in an attempt to free 166 enough bytes such that the font cache is not using more than the 167 specified number of bytes. It is thread-safe, and may be called at 168 any time. 169 Return true if some amount of the cache was purged. 170 */ 171 static bool SetCacheUsed(size_t bytesUsed); 172 173#ifdef SK_DEBUG 174 void validate() const; 175#else 176 void validate() const {} 177#endif 178 179 class AutoValidate : SkNoncopyable { 180 public: 181 AutoValidate(const SkGlyphCache* cache) : fCache(cache) { 182 if (fCache) { 183 fCache->validate(); 184 } 185 } 186 ~AutoValidate() { 187 if (fCache) { 188 fCache->validate(); 189 } 190 } 191 void forget() { 192 fCache = NULL; 193 } 194 private: 195 const SkGlyphCache* fCache; 196 }; 197 198private: 199 SkGlyphCache(const SkDescriptor*); 200 ~SkGlyphCache(); 201 202 enum MetricsType { 203 kJustAdvance_MetricsType, 204 kFull_MetricsType 205 }; 206 207 SkGlyph* lookupMetrics(uint32_t id, MetricsType); 208 static bool DetachProc(const SkGlyphCache*, void*) { return true; } 209 210 void detach(SkGlyphCache** head) { 211 if (fPrev) { 212 fPrev->fNext = fNext; 213 } else { 214 *head = fNext; 215 } 216 if (fNext) { 217 fNext->fPrev = fPrev; 218 } 219 fPrev = fNext = NULL; 220 } 221 222 void attachToHead(SkGlyphCache** head) { 223 SkASSERT(NULL == fPrev && NULL == fNext); 224 if (*head) { 225 (*head)->fPrev = this; 226 fNext = *head; 227 } 228 *head = this; 229 } 230 231 SkGlyphCache* fNext, *fPrev; 232 SkDescriptor* fDesc; 233 SkScalerContext* fScalerContext; 234 SkPaint::FontMetrics fFontMetricsY; 235 236 enum { 237 kHashBits = 12, 238 kHashCount = 1 << kHashBits, 239 kHashMask = kHashCount - 1 240 }; 241 SkGlyph* fGlyphHash[kHashCount]; 242 SkTDArray<SkGlyph*> fGlyphArray; 243 SkChunkAlloc fGlyphAlloc; 244 SkChunkAlloc fImageAlloc; 245 246 int fMetricsCount, fAdvanceCount; 247 248 struct CharGlyphRec { 249 uint32_t fID; // unichar + subpixel 250 SkGlyph* fGlyph; 251 }; 252 // no reason to use the same kHashCount as fGlyphHash, but we do for now 253 CharGlyphRec fCharToGlyphHash[kHashCount]; 254 255 enum { 256 // shift so that the top bits fall into kHashBits region 257 kShiftForHashIndex = SkGlyph::kSubShift + 258 SkGlyph::kSubBits*2 - 259 kHashBits 260 }; 261 262 static inline unsigned ID2HashIndex(uint32_t id) { 263 return (id ^ (id >> kShiftForHashIndex)) & kHashMask; 264 } 265 266 // used to track (approx) how much ram is tied-up in this cache 267 size_t fMemoryUsed; 268 269 struct AuxProcRec { 270 AuxProcRec* fNext; 271 void (*fProc)(void*); 272 void* fData; 273 }; 274 AuxProcRec* fAuxProcList; 275 void invokeAndRemoveAuxProcs(); 276 277 // This relies on the caller to have already acquired the mutex to access the global cache 278 static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded); 279 280 inline static SkGlyphCache* FindTail(SkGlyphCache* head); 281 static size_t ComputeMemoryUsed(const SkGlyphCache* head); 282 283 friend class SkGlyphCache_Globals; 284}; 285 286class SkAutoGlyphCache { 287public: 288 SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} 289 SkAutoGlyphCache(const SkDescriptor* desc) { 290 fCache = SkGlyphCache::DetachCache(desc); 291 } 292 SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix) { 293 fCache = paint.detachCache(matrix); 294 } 295 ~SkAutoGlyphCache() { 296 if (fCache) { 297 SkGlyphCache::AttachCache(fCache); 298 } 299 } 300 301 SkGlyphCache* getCache() const { return fCache; } 302 303 void release() { 304 if (fCache) { 305 SkGlyphCache::AttachCache(fCache); 306 fCache = NULL; 307 } 308 } 309 310private: 311 SkGlyphCache* fCache; 312 313 static bool DetachProc(const SkGlyphCache*, void*); 314}; 315 316#endif 317 318