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