1 /* libs/graphics/sgl/SkGlyphCache.h 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #ifndef SkGlyphCache_DEFINED 19 #define SkGlyphCache_DEFINED 20 21 #include "SkBitmap.h" 22 #include "SkChunkAlloc.h" 23 #include "SkDescriptor.h" 24 #include "SkScalerContext.h" 25 #include "SkTemplates.h" 26 27 class SkPaint; 28 29 class SkGlyphCache_Globals; 30 31 /** \class SkGlyphCache 32 33 This class represents a strike: a specific combination of typeface, size, 34 matrix, etc., and holds the glyphs for that strike. Calling any of the 35 getUnichar.../getGlyphID... methods will return the requested glyph, 36 either instantly if it is already cahced, or by first generating it and then 37 adding it to the strike. 38 39 The strikes are held in a global list, available to all threads. To interact 40 with one, call either VisitCache() or DetachCache(). 41 */ 42 class SkGlyphCache { 43 public: 44 /** Returns a glyph with valid fAdvance and fDevKern fields. 45 The remaining fields may be valid, but that is not guaranteed. If you 46 require those, call getUnicharMetrics or getGlyphIDMetrics instead. 47 */ 48 const SkGlyph& getUnicharAdvance(SkUnichar); 49 const SkGlyph& getGlyphIDAdvance(uint16_t); 50 51 /** Returns a glyph with all fields valid except fImage and fPath, which 52 may be null. If they are null, call findImage or findPath for those. 53 If they are not null, then they are valid. 54 55 This call is potentially slower than the matching ...Advance call. If 56 you only need the fAdvance/fDevKern fields, call those instead. 57 */ 58 const SkGlyph& getUnicharMetrics(SkUnichar); 59 const SkGlyph& getGlyphIDMetrics(uint16_t); 60 61 /** These are variants that take the device position of the glyph. Call 62 these only if you are drawing in subpixel mode. Passing 0, 0 is 63 effectively the same as calling the variants w/o the extra params, tho 64 a tiny bit slower. 65 */ 66 const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); 67 const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); 68 69 /** Return the glyphID for the specified Unichar. If the char has already 70 been seen, use the existing cache entry. If not, ask the scalercontext 71 to compute it for us. 72 */ 73 uint16_t unicharToGlyph(SkUnichar); 74 75 /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to 76 a character code of zero. 77 */ 78 SkUnichar glyphToUnichar(uint16_t); 79 80 /** Return the image associated with the glyph. If it has not been generated 81 this will trigger that. 82 */ 83 const void* findImage(const SkGlyph&); 84 /** Return the Path associated with the glyph. If it has not been generated 85 this will trigger that. 86 */ 87 const SkPath* findPath(const SkGlyph&); 88 89 /** Return the vertical metrics for this strike. 90 */ getFontMetricsY()91 const SkPaint::FontMetrics& getFontMetricsY() const { 92 return fFontMetricsY; 93 } 94 95 /* AuxProc/Data allow a client to associate data with this cache entry. 96 Multiple clients can use this, as their data is keyed with a function 97 pointer. In addition to serving as a key, the function pointer is called 98 with the data when the glyphcache object is deleted, so the client can 99 cleanup their data as well. NOTE: the auxProc must not try to access 100 this glyphcache in any way, since it may be in the process of being 101 deleted. 102 */ 103 104 //! If the proc is found, return true and set *dataPtr to its data 105 bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; 106 //! Add a proc/data pair to the glyphcache. proc should be non-null 107 void setAuxProc(void (*auxProc)(void*), void* auxData); 108 //! If found, remove the proc/data pair from the glyphcache (does not 109 // call the proc) 110 void removeAuxProc(void (*auxProc)(void*)); 111 112 /** Call proc on all cache entries, stopping early if proc returns true. 113 The proc should not create or delete caches, since it could produce 114 deadlock. 115 */ 116 static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx); 117 118 /** Find a matching cache entry, and call proc() with it. If none is found 119 create a new one. If the proc() returns true, detach the cache and 120 return it, otherwise leave it and return NULL. 121 */ 122 static SkGlyphCache* VisitCache(const SkDescriptor* desc, 123 bool (*proc)(const SkGlyphCache*, void*), 124 void* context); 125 126 /** Given a strike that was returned by either VisitCache() or DetachCache() 127 add it back into the global cache list (after which the caller should 128 not reference it anymore. 129 */ 130 static void AttachCache(SkGlyphCache*); 131 132 /** Detach a strike from the global cache matching the specified descriptor. 133 Once detached, it can be queried/modified by the current thread, and 134 when finished, be reattached to the global cache with AttachCache(). 135 While detached, if another request is made with the same descriptor, 136 a different strike will be generated. This is fine. It does mean we 137 can have more than 1 strike for the same descriptor, but that will 138 eventually get purged, and the win is that different thread will never 139 block each other while a strike is being used. 140 */ DetachCache(const SkDescriptor * desc)141 static SkGlyphCache* DetachCache(const SkDescriptor* desc) { 142 return VisitCache(desc, DetachProc, NULL); 143 } 144 145 /** Return the approximate number of bytes used by the font cache 146 */ 147 static size_t GetCacheUsed(); 148 149 /** This can be called to purge old font data, in an attempt to free 150 enough bytes such that the font cache is not using more than the 151 specified number of bytes. It is thread-safe, and may be called at 152 any time. 153 Return true if some amount of the cache was purged. 154 */ 155 static bool SetCacheUsed(size_t bytesUsed); 156 157 private: 158 SkGlyphCache(const SkDescriptor*); 159 ~SkGlyphCache(); 160 161 enum MetricsType { 162 kJustAdvance_MetricsType, 163 kFull_MetricsType 164 }; 165 166 SkGlyph* lookupMetrics(uint32_t id, MetricsType); DetachProc(const SkGlyphCache *,void *)167 static bool DetachProc(const SkGlyphCache*, void*) { return true; } 168 detach(SkGlyphCache ** head)169 void detach(SkGlyphCache** head) { 170 if (fPrev) { 171 fPrev->fNext = fNext; 172 } else { 173 *head = fNext; 174 } 175 if (fNext) { 176 fNext->fPrev = fPrev; 177 } 178 fPrev = fNext = NULL; 179 } 180 attachToHead(SkGlyphCache ** head)181 void attachToHead(SkGlyphCache** head) { 182 SkASSERT(NULL == fPrev && NULL == fNext); 183 if (*head) { 184 (*head)->fPrev = this; 185 fNext = *head; 186 } 187 *head = this; 188 } 189 190 SkGlyphCache* fNext, *fPrev; 191 SkDescriptor* fDesc; 192 SkScalerContext* fScalerContext; 193 SkPaint::FontMetrics fFontMetricsY; 194 195 enum { 196 kHashBits = 8, 197 kHashCount = 1 << kHashBits, 198 kHashMask = kHashCount - 1 199 }; 200 SkGlyph* fGlyphHash[kHashCount]; 201 SkTDArray<SkGlyph*> fGlyphArray; 202 SkChunkAlloc fGlyphAlloc; 203 SkChunkAlloc fImageAlloc; 204 205 int fMetricsCount, fAdvanceCount; 206 207 struct CharGlyphRec { 208 uint32_t fID; // unichar + subpixel 209 SkGlyph* fGlyph; 210 }; 211 // no reason to use the same kHashCount as fGlyphHash, but we do for now 212 CharGlyphRec fCharToGlyphHash[kHashCount]; 213 214 enum { 215 // shift so that the top bits fall into kHashBits region 216 kShiftForHashIndex = SkGlyph::kSubShift + 217 SkGlyph::kSubBits*2 - 218 kHashBits 219 }; 220 ID2HashIndex(uint32_t id)221 static inline unsigned ID2HashIndex(uint32_t id) { 222 return (id ^ (id >> kShiftForHashIndex)) & kHashMask; 223 } 224 225 // used to track (approx) how much ram is tied-up in this cache 226 size_t fMemoryUsed; 227 228 struct AuxProcRec { 229 AuxProcRec* fNext; 230 void (*fProc)(void*); 231 void* fData; 232 }; 233 AuxProcRec* fAuxProcList; 234 void invokeAndRemoveAuxProcs(); 235 236 // This relies on the caller to have already acquired the mutex to access the global cache 237 static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded); 238 239 inline static SkGlyphCache* FindTail(SkGlyphCache* head); 240 static size_t ComputeMemoryUsed(const SkGlyphCache* head); 241 242 friend class SkGlyphCache_Globals; 243 }; 244 245 class SkAutoGlyphCache { 246 public: SkAutoGlyphCache(SkGlyphCache * cache)247 SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} SkAutoGlyphCache(const SkDescriptor * desc)248 SkAutoGlyphCache(const SkDescriptor* desc) 249 { 250 fCache = SkGlyphCache::DetachCache(desc); 251 } SkAutoGlyphCache(const SkPaint & paint,const SkMatrix * matrix)252 SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix) 253 { 254 fCache = paint.detachCache(matrix); 255 } ~SkAutoGlyphCache()256 ~SkAutoGlyphCache() 257 { 258 if (fCache) 259 SkGlyphCache::AttachCache(fCache); 260 } 261 getCache()262 SkGlyphCache* getCache() const { return fCache; } 263 release()264 void release() 265 { 266 if (fCache) 267 { 268 SkGlyphCache::AttachCache(fCache); 269 fCache = NULL; 270 } 271 } 272 private: 273 SkGlyphCache* fCache; 274 275 static bool DetachProc(const SkGlyphCache*, void*); 276 }; 277 278 #endif 279 280