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 */ getBaseGlyphCount(SkUnichar charCode)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 */ getFontMetricsY()98 const SkPaint::FontMetrics& getFontMetricsY() const { 99 return fFontMetricsY; 100 } 101 getDescriptor()102 const SkDescriptor& getDescriptor() const { return *fDesc; } 103 getMaskFormat()104 SkMask::Format getMaskFormat() const { 105 return fScalerContext->getMaskFormat(); 106 } 107 isSubpixel()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 getScalerContext()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 */ DetachCache(const SkDescriptor * desc)157 static SkGlyphCache* DetachCache(const SkDescriptor* desc) { 158 return VisitCache(desc, DetachProc, NULL); 159 } 160 161 #ifdef SK_DEBUG 162 void validate() const; 163 #else validate()164 void validate() const {} 165 #endif 166 167 class AutoValidate : SkNoncopyable { 168 public: AutoValidate(const SkGlyphCache * cache)169 AutoValidate(const SkGlyphCache* cache) : fCache(cache) { 170 if (fCache) { 171 fCache->validate(); 172 } 173 } ~AutoValidate()174 ~AutoValidate() { 175 if (fCache) { 176 fCache->validate(); 177 } 178 } forget()179 void forget() { 180 fCache = NULL; 181 } 182 private: 183 const SkGlyphCache* fCache; 184 }; 185 186 private: 187 SkGlyphCache(const SkDescriptor*); 188 ~SkGlyphCache(); 189 190 enum MetricsType { 191 kJustAdvance_MetricsType, 192 kFull_MetricsType 193 }; 194 195 SkGlyph* lookupMetrics(uint32_t id, MetricsType); DetachProc(const SkGlyphCache *,void *)196 static bool DetachProc(const SkGlyphCache*, void*) { return true; } 197 detach(SkGlyphCache ** head)198 void detach(SkGlyphCache** head) { 199 if (fPrev) { 200 fPrev->fNext = fNext; 201 } else { 202 *head = fNext; 203 } 204 if (fNext) { 205 fNext->fPrev = fPrev; 206 } 207 fPrev = fNext = NULL; 208 } 209 attachToHead(SkGlyphCache ** head)210 void attachToHead(SkGlyphCache** head) { 211 SkASSERT(NULL == fPrev && NULL == fNext); 212 if (*head) { 213 (*head)->fPrev = this; 214 fNext = *head; 215 } 216 *head = this; 217 } 218 219 SkGlyphCache* fNext, *fPrev; 220 SkDescriptor* fDesc; 221 SkScalerContext* fScalerContext; 222 SkPaint::FontMetrics fFontMetricsY; 223 224 enum { 225 kHashBits = 12, 226 kHashCount = 1 << kHashBits, 227 kHashMask = kHashCount - 1 228 }; 229 SkGlyph* fGlyphHash[kHashCount]; 230 SkTDArray<SkGlyph*> fGlyphArray; 231 SkChunkAlloc fGlyphAlloc; 232 SkChunkAlloc fImageAlloc; 233 234 int fMetricsCount, fAdvanceCount; 235 236 struct CharGlyphRec { 237 uint32_t fID; // unichar + subpixel 238 SkGlyph* fGlyph; 239 }; 240 // no reason to use the same kHashCount as fGlyphHash, but we do for now 241 CharGlyphRec fCharToGlyphHash[kHashCount]; 242 243 enum { 244 // shift so that the top bits fall into kHashBits region 245 kShiftForHashIndex = SkGlyph::kSubShift + 246 SkGlyph::kSubBits*2 - 247 kHashBits 248 }; 249 ID2HashIndex(uint32_t id)250 static inline unsigned ID2HashIndex(uint32_t id) { 251 return (id ^ (id >> kShiftForHashIndex)) & kHashMask; 252 } 253 254 // used to track (approx) how much ram is tied-up in this cache 255 size_t fMemoryUsed; 256 257 struct AuxProcRec { 258 AuxProcRec* fNext; 259 void (*fProc)(void*); 260 void* fData; 261 }; 262 AuxProcRec* fAuxProcList; 263 void invokeAndRemoveAuxProcs(); 264 265 // This relies on the caller to have already acquired the mutex to access the global cache 266 static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded); 267 268 inline static SkGlyphCache* FindTail(SkGlyphCache* head); 269 270 friend class SkGlyphCache_Globals; 271 }; 272 273 class SkAutoGlyphCache { 274 public: SkAutoGlyphCache(SkGlyphCache * cache)275 SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} SkAutoGlyphCache(const SkDescriptor * desc)276 SkAutoGlyphCache(const SkDescriptor* desc) { 277 fCache = SkGlyphCache::DetachCache(desc); 278 } SkAutoGlyphCache(const SkPaint & paint,const SkDeviceProperties * deviceProperties,const SkMatrix * matrix)279 SkAutoGlyphCache(const SkPaint& paint, 280 const SkDeviceProperties* deviceProperties, 281 const SkMatrix* matrix) { 282 fCache = paint.detachCache(deviceProperties, matrix); 283 } ~SkAutoGlyphCache()284 ~SkAutoGlyphCache() { 285 if (fCache) { 286 SkGlyphCache::AttachCache(fCache); 287 } 288 } 289 getCache()290 SkGlyphCache* getCache() const { return fCache; } 291 release()292 void release() { 293 if (fCache) { 294 SkGlyphCache::AttachCache(fCache); 295 fCache = NULL; 296 } 297 } 298 299 private: 300 SkGlyphCache* fCache; 301 302 static bool DetachProc(const SkGlyphCache*, void*); 303 }; 304 305 #endif 306