1 /* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkGlyphCache_DEFINED 9 #define SkGlyphCache_DEFINED 10 11 #include "SkBitmap.h" 12 #include "SkChecksum.h" 13 #include "SkChunkAlloc.h" 14 #include "SkDescriptor.h" 15 #include "SkGlyph.h" 16 #include "SkScalerContext.h" 17 #include "SkTemplates.h" 18 #include "SkTDArray.h" 19 20 struct SkDeviceProperties; 21 class SkPaint; 22 23 class SkGlyphCache_Globals; 24 25 // Enable this locally to add stats for hash-table hit rates. It also extends the dump() 26 // output to show those stats. 27 //#define SK_GLYPHCACHE_TRACK_HASH_STATS 28 29 /** \class SkGlyphCache 30 31 This class represents a strike: a specific combination of typeface, size, 32 matrix, etc., and holds the glyphs for that strike. Calling any of the 33 getUnichar.../getGlyphID... methods will return the requested glyph, 34 either instantly if it is already cached, or by first generating it and then 35 adding it to the strike. 36 37 The strikes are held in a global list, available to all threads. To interact 38 with one, call either VisitCache() or DetachCache(). 39 */ 40 class SkGlyphCache { 41 public: 42 /** Returns a glyph with valid fAdvance and fDevKern fields. 43 The remaining fields may be valid, but that is not guaranteed. If you 44 require those, call getUnicharMetrics or getGlyphIDMetrics instead. 45 */ 46 const SkGlyph& getUnicharAdvance(SkUnichar); 47 const SkGlyph& getGlyphIDAdvance(uint16_t); 48 49 /** Returns a glyph with all fields valid except fImage and fPath, which 50 may be null. If they are null, call findImage or findPath for those. 51 If they are not null, then they are valid. 52 53 This call is potentially slower than the matching ...Advance call. If 54 you only need the fAdvance/fDevKern fields, call those instead. 55 */ 56 const SkGlyph& getUnicharMetrics(SkUnichar); 57 const SkGlyph& getGlyphIDMetrics(uint16_t); 58 59 /** These are variants that take the device position of the glyph. Call 60 these only if you are drawing in subpixel mode. Passing 0, 0 is 61 effectively the same as calling the variants w/o the extra params, tho 62 a tiny bit slower. 63 */ 64 const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); 65 const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); 66 67 /** Return the glyphID for the specified Unichar. If the char has already 68 been seen, use the existing cache entry. If not, ask the scalercontext 69 to compute it for us. 70 */ 71 uint16_t unicharToGlyph(SkUnichar); 72 73 /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to 74 a character code of zero. 75 */ 76 SkUnichar glyphToUnichar(uint16_t); 77 78 /** Returns the number of glyphs for this strike. 79 */ 80 unsigned getGlyphCount(); 81 82 /** Return the image associated with the glyph. If it has not been generated 83 this will trigger that. 84 */ 85 const void* findImage(const SkGlyph&); 86 /** Return the Path associated with the glyph. If it has not been generated 87 this will trigger that. 88 */ 89 const SkPath* findPath(const SkGlyph&); 90 91 /** Return the vertical metrics for this strike. 92 */ getFontMetrics()93 const SkPaint::FontMetrics& getFontMetrics() const { 94 return fFontMetrics; 95 } 96 getDescriptor()97 const SkDescriptor& getDescriptor() const { return *fDesc; } 98 getMaskFormat()99 SkMask::Format getMaskFormat() const { 100 return fScalerContext->getMaskFormat(); 101 } 102 isSubpixel()103 bool isSubpixel() const { 104 return fScalerContext->isSubpixel(); 105 } 106 107 void dump() const; 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 getScalerContext()123 SkScalerContext* getScalerContext() const { return fScalerContext; } 124 125 /** Find a matching cache entry, and call proc() with it. If none is found 126 create a new one. If the proc() returns true, detach the cache and 127 return it, otherwise leave it and return NULL. 128 */ 129 static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, 130 bool (*proc)(const SkGlyphCache*, void*), 131 void* context); 132 133 /** Given a strike that was returned by either VisitCache() or DetachCache() 134 add it back into the global cache list (after which the caller should 135 not reference it anymore. 136 */ 137 static void AttachCache(SkGlyphCache*); 138 139 /** Detach a strike from the global cache matching the specified descriptor. 140 Once detached, it can be queried/modified by the current thread, and 141 when finished, be reattached to the global cache with AttachCache(). 142 While detached, if another request is made with the same descriptor, 143 a different strike will be generated. This is fine. It does mean we 144 can have more than 1 strike for the same descriptor, but that will 145 eventually get purged, and the win is that different thread will never 146 block each other while a strike is being used. 147 */ DetachCache(SkTypeface * typeface,const SkDescriptor * desc)148 static SkGlyphCache* DetachCache(SkTypeface* typeface, 149 const SkDescriptor* desc) { 150 return VisitCache(typeface, desc, DetachProc, NULL); 151 } 152 153 static void Dump(); 154 155 #ifdef SK_DEBUG 156 void validate() const; 157 #else validate()158 void validate() const {} 159 #endif 160 161 class AutoValidate : SkNoncopyable { 162 public: AutoValidate(const SkGlyphCache * cache)163 AutoValidate(const SkGlyphCache* cache) : fCache(cache) { 164 if (fCache) { 165 fCache->validate(); 166 } 167 } ~AutoValidate()168 ~AutoValidate() { 169 if (fCache) { 170 fCache->validate(); 171 } 172 } forget()173 void forget() { 174 fCache = NULL; 175 } 176 private: 177 const SkGlyphCache* fCache; 178 }; 179 180 private: 181 // we take ownership of the scalercontext 182 SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); 183 ~SkGlyphCache(); 184 185 enum MetricsType { 186 kJustAdvance_MetricsType, 187 kFull_MetricsType 188 }; 189 190 // Return the SkGlyph* associated with MakeID. The id parameter is the combined glyph/x/y 191 // id generated by MakeID. If it is just a glyph id then x and y are assuemd to be zero. 192 SkGlyph* lookupByCombinedID(uint32_t id, MetricsType type); 193 194 // Return a SkGlyph* associated with unicode id and position x and y. 195 SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed y = 0); 196 197 // Return the index of id in the fGlyphArray. If it does 198 // not exist, create a new one using MetricsType. 199 uint16_t lookupMetrics(uint32_t id, MetricsType type); DetachProc(const SkGlyphCache *,void *)200 static bool DetachProc(const SkGlyphCache*, void*) { return true; } 201 202 SkGlyphCache* fNext, *fPrev; 203 SkDescriptor* fDesc; 204 SkScalerContext* fScalerContext; 205 SkPaint::FontMetrics fFontMetrics; 206 207 enum { 208 kHashBits = 8, 209 kHashCount = 1 << kHashBits, 210 kHashMask = kHashCount - 1 211 }; 212 213 // A quick lookup to avoid the binary search looking for glyphs in fGlyphArray. 214 uint16_t fGlyphHash[kHashCount]; 215 // Contains the SkGlyphs that are used by fGlyphHash and fCharToGlyphHash. The zero element 216 // is reserved for a sentinel SkGlyph that reduces the logic to check for collisions in the 217 // hash arrays. The zero element has an fID of SkGlyph::kImpossibleID which never matches 218 // any combined id generated for a char or a glyph. 219 SkTDArray<SkGlyph> fGlyphArray; 220 SkChunkAlloc fGlyphAlloc; 221 222 struct CharGlyphRec { 223 uint32_t fID; // unichar + subpixel 224 uint16_t fGlyphIndex; 225 }; 226 227 // no reason to use the same kHashCount as fGlyphHash, but we do for now 228 // Dynamically allocated when chars are encountered. 229 SkAutoTArray<CharGlyphRec> fCharToGlyphHash; 230 231 // The id arg is a combined id generated by MakeID. 232 CharGlyphRec* getCharGlyphRec(uint32_t id); 233 void adjustCaches(int insertion_index); 234 ID2HashIndex(uint32_t h)235 static inline unsigned ID2HashIndex(uint32_t h) { 236 return SkChecksum::CheapMix(h) & kHashMask; 237 } 238 239 // used to track (approx) how much ram is tied-up in this cache 240 size_t fMemoryUsed; 241 242 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS 243 int fHashHitCount; 244 int fHashMissCount; 245 #endif 246 247 struct AuxProcRec { 248 AuxProcRec* fNext; 249 void (*fProc)(void*); 250 void* fData; 251 }; 252 AuxProcRec* fAuxProcList; 253 void invokeAndRemoveAuxProcs(); 254 255 inline static SkGlyphCache* FindTail(SkGlyphCache* head); 256 257 friend class SkGlyphCache_Globals; 258 }; 259 260 class SkAutoGlyphCacheBase { 261 public: getCache()262 SkGlyphCache* getCache() const { return fCache; } 263 release()264 void release() { 265 if (fCache) { 266 SkGlyphCache::AttachCache(fCache); 267 fCache = NULL; 268 } 269 } 270 271 protected: 272 // Hide the constructors so we can't create one of these directly. 273 // Create SkAutoGlyphCache or SkAutoGlyphCacheNoCache instead. SkAutoGlyphCacheBase(SkGlyphCache * cache)274 SkAutoGlyphCacheBase(SkGlyphCache* cache) : fCache(cache) {} SkAutoGlyphCacheBase(SkTypeface * typeface,const SkDescriptor * desc)275 SkAutoGlyphCacheBase(SkTypeface* typeface, const SkDescriptor* desc) { 276 fCache = SkGlyphCache::DetachCache(typeface, desc); 277 } SkAutoGlyphCacheBase(const SkPaint &,const SkDeviceProperties *,const SkMatrix *)278 SkAutoGlyphCacheBase(const SkPaint& /*paint*/, 279 const SkDeviceProperties* /*deviceProperties*/, 280 const SkMatrix* /*matrix*/) { 281 fCache = NULL; 282 } SkAutoGlyphCacheBase()283 SkAutoGlyphCacheBase() { 284 fCache = NULL; 285 } ~SkAutoGlyphCacheBase()286 ~SkAutoGlyphCacheBase() { 287 if (fCache) { 288 SkGlyphCache::AttachCache(fCache); 289 } 290 } 291 292 SkGlyphCache* fCache; 293 294 private: 295 static bool DetachProc(const SkGlyphCache*, void*); 296 }; 297 298 class SkAutoGlyphCache : public SkAutoGlyphCacheBase { 299 public: SkAutoGlyphCache(SkGlyphCache * cache)300 SkAutoGlyphCache(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {} SkAutoGlyphCache(SkTypeface * typeface,const SkDescriptor * desc)301 SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) : 302 SkAutoGlyphCacheBase(typeface, desc) {} SkAutoGlyphCache(const SkPaint & paint,const SkDeviceProperties * deviceProperties,const SkMatrix * matrix)303 SkAutoGlyphCache(const SkPaint& paint, 304 const SkDeviceProperties* deviceProperties, 305 const SkMatrix* matrix) { 306 fCache = paint.detachCache(deviceProperties, matrix, false); 307 } 308 309 private: SkAutoGlyphCache()310 SkAutoGlyphCache() : SkAutoGlyphCacheBase() {} 311 }; 312 #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) 313 314 class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCacheBase { 315 public: SkAutoGlyphCacheNoGamma(SkGlyphCache * cache)316 SkAutoGlyphCacheNoGamma(SkGlyphCache* cache) : SkAutoGlyphCacheBase(cache) {} SkAutoGlyphCacheNoGamma(SkTypeface * typeface,const SkDescriptor * desc)317 SkAutoGlyphCacheNoGamma(SkTypeface* typeface, const SkDescriptor* desc) : 318 SkAutoGlyphCacheBase(typeface, desc) {} SkAutoGlyphCacheNoGamma(const SkPaint & paint,const SkDeviceProperties * deviceProperties,const SkMatrix * matrix)319 SkAutoGlyphCacheNoGamma(const SkPaint& paint, 320 const SkDeviceProperties* deviceProperties, 321 const SkMatrix* matrix) { 322 fCache = paint.detachCache(deviceProperties, matrix, true); 323 } 324 325 private: SkAutoGlyphCacheNoGamma()326 SkAutoGlyphCacheNoGamma() : SkAutoGlyphCacheBase() {} 327 }; 328 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma) 329 330 #endif 331