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 cached, 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 /** Return the distance field associated with the glyph. If it has not been generated 96 this will trigger that. 97 */ 98 const void* findDistanceField(const SkGlyph&); 99 100 /** Return the vertical metrics for this strike. 101 */ 102 const SkPaint::FontMetrics& getFontMetrics() const { 103 return fFontMetrics; 104 } 105 106 const SkDescriptor& getDescriptor() const { return *fDesc; } 107 108 SkMask::Format getMaskFormat() const { 109 return fScalerContext->getMaskFormat(); 110 } 111 112 bool isSubpixel() const { 113 return fScalerContext->isSubpixel(); 114 } 115 116 /* AuxProc/Data allow a client to associate data with this cache entry. 117 Multiple clients can use this, as their data is keyed with a function 118 pointer. In addition to serving as a key, the function pointer is called 119 with the data when the glyphcache object is deleted, so the client can 120 cleanup their data as well. NOTE: the auxProc must not try to access 121 this glyphcache in any way, since it may be in the process of being 122 deleted. 123 */ 124 125 //! If the proc is found, return true and set *dataPtr to its data 126 bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; 127 //! Add a proc/data pair to the glyphcache. proc should be non-null 128 void setAuxProc(void (*auxProc)(void*), void* auxData); 129 130 SkScalerContext* getScalerContext() const { return fScalerContext; } 131 132 /** Call proc on all cache entries, stopping early if proc returns true. 133 The proc should not create or delete caches, since it could produce 134 deadlock. 135 */ 136 static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx); 137 138 /** Find a matching cache entry, and call proc() with it. If none is found 139 create a new one. If the proc() returns true, detach the cache and 140 return it, otherwise leave it and return NULL. 141 */ 142 static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, 143 bool (*proc)(const SkGlyphCache*, void*), 144 void* context); 145 146 /** Given a strike that was returned by either VisitCache() or DetachCache() 147 add it back into the global cache list (after which the caller should 148 not reference it anymore. 149 */ 150 static void AttachCache(SkGlyphCache*); 151 152 /** Detach a strike from the global cache matching the specified descriptor. 153 Once detached, it can be queried/modified by the current thread, and 154 when finished, be reattached to the global cache with AttachCache(). 155 While detached, if another request is made with the same descriptor, 156 a different strike will be generated. This is fine. It does mean we 157 can have more than 1 strike for the same descriptor, but that will 158 eventually get purged, and the win is that different thread will never 159 block each other while a strike is being used. 160 */ 161 static SkGlyphCache* DetachCache(SkTypeface* typeface, 162 const SkDescriptor* desc) { 163 return VisitCache(typeface, desc, DetachProc, NULL); 164 } 165 166 #ifdef SK_DEBUG 167 void validate() const; 168 #else 169 void validate() const {} 170 #endif 171 172 class AutoValidate : SkNoncopyable { 173 public: 174 AutoValidate(const SkGlyphCache* cache) : fCache(cache) { 175 if (fCache) { 176 fCache->validate(); 177 } 178 } 179 ~AutoValidate() { 180 if (fCache) { 181 fCache->validate(); 182 } 183 } 184 void forget() { 185 fCache = NULL; 186 } 187 private: 188 const SkGlyphCache* fCache; 189 }; 190 191 private: 192 // we take ownership of the scalercontext 193 SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); 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 SkGlyphCache* fNext, *fPrev; 205 SkDescriptor* fDesc; 206 SkScalerContext* fScalerContext; 207 SkPaint::FontMetrics fFontMetrics; 208 209 enum { 210 kHashBits = 8, 211 kHashCount = 1 << kHashBits, 212 kHashMask = kHashCount - 1 213 }; 214 SkGlyph* fGlyphHash[kHashCount]; 215 SkTDArray<SkGlyph*> fGlyphArray; 216 SkChunkAlloc fGlyphAlloc; 217 218 struct CharGlyphRec { 219 uint32_t fID; // unichar + subpixel 220 SkGlyph* fGlyph; 221 }; 222 // no reason to use the same kHashCount as fGlyphHash, but we do for now 223 CharGlyphRec fCharToGlyphHash[kHashCount]; 224 225 static inline unsigned ID2HashIndex(uint32_t id) { 226 id ^= id >> 16; 227 id ^= id >> 8; 228 return id & kHashMask; 229 } 230 231 // used to track (approx) how much ram is tied-up in this cache 232 size_t fMemoryUsed; 233 234 struct AuxProcRec { 235 AuxProcRec* fNext; 236 void (*fProc)(void*); 237 void* fData; 238 }; 239 AuxProcRec* fAuxProcList; 240 void invokeAndRemoveAuxProcs(); 241 242 inline static SkGlyphCache* FindTail(SkGlyphCache* head); 243 244 friend class SkGlyphCache_Globals; 245 }; 246 247 class SkAutoGlyphCacheBase { 248 public: 249 SkGlyphCache* getCache() const { return fCache; } 250 251 void release() { 252 if (fCache) { 253 SkGlyphCache::AttachCache(fCache); 254 fCache = NULL; 255 } 256 } 257 258 protected: 259 // Hide the constructors so we can't create one of these directly. 260 // Create SkAutoGlyphCache or SkAutoGlyphCacheNoCache instead. 261 SkAutoGlyphCacheBase(SkGlyphCache* cache) : fCache(cache) {} 262 SkAutoGlyphCacheBase(SkTypeface* typeface, const SkDescriptor* desc) { 263 fCache = SkGlyphCache::DetachCache(typeface, desc); 264 } 265 SkAutoGlyphCacheBase(const SkPaint& paint, 266 const SkDeviceProperties* deviceProperties, 267 const SkMatrix* matrix) { 268 fCache = NULL; 269 } 270 SkAutoGlyphCacheBase() { 271 fCache = NULL; 272 } 273 ~SkAutoGlyphCacheBase() { 274 if (fCache) { 275 SkGlyphCache::AttachCache(fCache); 276 } 277 } 278 279 SkGlyphCache* fCache; 280 281 private: 282 static bool DetachProc(const SkGlyphCache*, void*); 283 }; 284 285 class SkAutoGlyphCache : public SkAutoGlyphCacheBase { 286 public: 287 SkAutoGlyphCache(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {} 288 SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) : 289 SkAutoGlyphCacheBase(typeface, desc) {} 290 SkAutoGlyphCache(const SkPaint& paint, 291 const SkDeviceProperties* deviceProperties, 292 const SkMatrix* matrix) { 293 fCache = paint.detachCache(deviceProperties, matrix, false); 294 } 295 296 private: 297 SkAutoGlyphCache() : SkAutoGlyphCacheBase() {} 298 }; 299 #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) 300 301 class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCacheBase { 302 public: 303 SkAutoGlyphCacheNoGamma(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {} 304 SkAutoGlyphCacheNoGamma(SkTypeface* typeface, const SkDescriptor* desc) : 305 SkAutoGlyphCacheBase(typeface, desc) {} 306 SkAutoGlyphCacheNoGamma(const SkPaint& paint, 307 const SkDeviceProperties* deviceProperties, 308 const SkMatrix* matrix) { 309 fCache = paint.detachCache(deviceProperties, matrix, true); 310 } 311 312 private: 313 SkAutoGlyphCacheNoGamma() : SkAutoGlyphCacheBase() {} 314 }; 315 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma) 316 317 #endif 318