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 21struct SkDeviceProperties; 22class SkPaint; 23 24class 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*/ 37class SkGlyphCache { 38public: 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 187private: 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 SkGlyphCache* fNext, *fPrev; 201 SkDescriptor* fDesc; 202 SkScalerContext* fScalerContext; 203 SkPaint::FontMetrics fFontMetrics; 204 205 enum { 206 kHashBits = 8, 207 kHashCount = 1 << kHashBits, 208 kHashMask = kHashCount - 1 209 }; 210 SkGlyph* fGlyphHash[kHashCount]; 211 SkTDArray<SkGlyph*> fGlyphArray; 212 SkChunkAlloc fGlyphAlloc; 213 214 struct CharGlyphRec { 215 uint32_t fID; // unichar + subpixel 216 SkGlyph* fGlyph; 217 }; 218 // no reason to use the same kHashCount as fGlyphHash, but we do for now 219 CharGlyphRec fCharToGlyphHash[kHashCount]; 220 221 static inline unsigned ID2HashIndex(uint32_t id) { 222 id ^= id >> 16; 223 id ^= id >> 8; 224 return id & kHashMask; 225 } 226 227 // used to track (approx) how much ram is tied-up in this cache 228 size_t fMemoryUsed; 229 230 struct AuxProcRec { 231 AuxProcRec* fNext; 232 void (*fProc)(void*); 233 void* fData; 234 }; 235 AuxProcRec* fAuxProcList; 236 void invokeAndRemoveAuxProcs(); 237 238 inline static SkGlyphCache* FindTail(SkGlyphCache* head); 239 240 friend class SkGlyphCache_Globals; 241}; 242 243class SkAutoGlyphCache { 244public: 245 SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} 246 SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) { 247 fCache = SkGlyphCache::DetachCache(typeface, desc); 248 } 249 SkAutoGlyphCache(const SkPaint& paint, 250 const SkDeviceProperties* deviceProperties, 251 const SkMatrix* matrix) { 252 fCache = paint.detachCache(deviceProperties, matrix); 253 } 254 ~SkAutoGlyphCache() { 255 if (fCache) { 256 SkGlyphCache::AttachCache(fCache); 257 } 258 } 259 260 SkGlyphCache* getCache() const { return fCache; } 261 262 void release() { 263 if (fCache) { 264 SkGlyphCache::AttachCache(fCache); 265 fCache = NULL; 266 } 267 } 268 269private: 270 SkGlyphCache* fCache; 271 272 static bool DetachProc(const SkGlyphCache*, void*); 273}; 274#define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) 275 276#endif 277