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 /** Return the image associated with the glyph. If it has not been generated 76 this will trigger that. 77 */ 78 const void* findImage(const SkGlyph&); 79 /** Return the Path associated with the glyph. If it has not been generated 80 this will trigger that. 81 */ 82 const SkPath* findPath(const SkGlyph&); 83 84 /** Return the vertical metrics for this strike. 85 */ getFontMetricsY()86 const SkPaint::FontMetrics& getFontMetricsY() const { 87 return fFontMetricsY; 88 } 89 90 /* AuxProc/Data allow a client to associate data with this cache entry. 91 Multiple clients can use this, as their data is keyed with a function 92 pointer. In addition to serving as a key, the function pointer is called 93 with the data when the glyphcache object is deleted, so the client can 94 cleanup their data as well. NOTE: the auxProc must not try to access 95 this glyphcache in any way, since it may be in the process of being 96 deleted. 97 */ 98 99 //! If the proc is found, return true and set *dataPtr to its data 100 bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; 101 //! Add a proc/data pair to the glyphcache. proc should be non-null 102 void setAuxProc(void (*auxProc)(void*), void* auxData); 103 //! If found, remove the proc/data pair from the glyphcache (does not 104 // call the proc) 105 void removeAuxProc(void (*auxProc)(void*)); 106 107 /** Call proc on all cache entries, stopping early if proc returns true. 108 The proc should not create or delete caches, since it could produce 109 deadlock. 110 */ 111 static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx); 112 113 /** Find a matching cache entry, and call proc() with it. If none is found 114 create a new one. If the proc() returns true, detach the cache and 115 return it, otherwise leave it and return NULL. 116 */ 117 static SkGlyphCache* VisitCache(const SkDescriptor* desc, 118 bool (*proc)(const SkGlyphCache*, void*), 119 void* context); 120 121 /** Given a strike that was returned by either VisitCache() or DetachCache() 122 add it back into the global cache list (after which the caller should 123 not reference it anymore. 124 */ 125 static void AttachCache(SkGlyphCache*); 126 127 /** Detach a strike from the global cache matching the specified descriptor. 128 Once detached, it can be queried/modified by the current thread, and 129 when finished, be reattached to the global cache with AttachCache(). 130 While detached, if another request is made with the same descriptor, 131 a different strike will be generated. This is fine. It does mean we 132 can have more than 1 strike for the same descriptor, but that will 133 eventually get purged, and the win is that different thread will never 134 block each other while a strike is being used. 135 */ DetachCache(const SkDescriptor * desc)136 static SkGlyphCache* DetachCache(const SkDescriptor* desc) { 137 return VisitCache(desc, DetachProc, NULL); 138 } 139 140 /** Return the approximate number of bytes used by the font cache 141 */ 142 static size_t GetCacheUsed(); 143 144 /** This can be called to purge old font data, in an attempt to free 145 enough bytes such that the font cache is not using more than the 146 specified number of bytes. It is thread-safe, and may be called at 147 any time. 148 Return true if some amount of the cache was purged. 149 */ 150 static bool SetCacheUsed(size_t bytesUsed); 151 152 private: 153 SkGlyphCache(const SkDescriptor*); 154 ~SkGlyphCache(); 155 156 enum MetricsType { 157 kJustAdvance_MetricsType, 158 kFull_MetricsType 159 }; 160 161 SkGlyph* lookupMetrics(uint32_t id, MetricsType); DetachProc(const SkGlyphCache *,void *)162 static bool DetachProc(const SkGlyphCache*, void*) { return true; } 163 detach(SkGlyphCache ** head)164 void detach(SkGlyphCache** head) { 165 if (fPrev) { 166 fPrev->fNext = fNext; 167 } else { 168 *head = fNext; 169 } 170 if (fNext) { 171 fNext->fPrev = fPrev; 172 } 173 fPrev = fNext = NULL; 174 } 175 attachToHead(SkGlyphCache ** head)176 void attachToHead(SkGlyphCache** head) { 177 SkASSERT(NULL == fPrev && NULL == fNext); 178 if (*head) { 179 (*head)->fPrev = this; 180 fNext = *head; 181 } 182 *head = this; 183 } 184 185 SkGlyphCache* fNext, *fPrev; 186 SkDescriptor* fDesc; 187 SkScalerContext* fScalerContext; 188 SkPaint::FontMetrics fFontMetricsY; 189 190 enum { 191 kHashBits = 8, 192 kHashCount = 1 << kHashBits, 193 kHashMask = kHashCount - 1 194 }; 195 SkGlyph* fGlyphHash[kHashCount]; 196 SkTDArray<SkGlyph*> fGlyphArray; 197 SkChunkAlloc fGlyphAlloc; 198 SkChunkAlloc fImageAlloc; 199 200 int fMetricsCount, fAdvanceCount; 201 202 struct CharGlyphRec { 203 uint32_t fID; // unichar + subpixel 204 SkGlyph* fGlyph; 205 }; 206 // no reason to use the same kHashCount as fGlyphHash, but we do for now 207 CharGlyphRec fCharToGlyphHash[kHashCount]; 208 209 enum { 210 // shift so that the top bits fall into kHashBits region 211 kShiftForHashIndex = SkGlyph::kSubShift + 212 SkGlyph::kSubBits*2 - 213 kHashBits 214 }; 215 ID2HashIndex(uint32_t id)216 static inline unsigned ID2HashIndex(uint32_t id) { 217 return (id ^ (id >> kShiftForHashIndex)) & kHashMask; 218 } 219 220 // used to track (approx) how much ram is tied-up in this cache 221 size_t fMemoryUsed; 222 223 struct AuxProcRec { 224 AuxProcRec* fNext; 225 void (*fProc)(void*); 226 void* fData; 227 }; 228 AuxProcRec* fAuxProcList; 229 void invokeAndRemoveAuxProcs(); 230 231 // This relies on the caller to have already acquired the mutex to access the global cache 232 static size_t InternalFreeCache(SkGlyphCache_Globals*, size_t bytesNeeded); 233 234 inline static SkGlyphCache* FindTail(SkGlyphCache* head); 235 static size_t ComputeMemoryUsed(const SkGlyphCache* head); 236 237 friend class SkGlyphCache_Globals; 238 }; 239 240 class SkAutoGlyphCache { 241 public: SkAutoGlyphCache(SkGlyphCache * cache)242 SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {} SkAutoGlyphCache(const SkDescriptor * desc)243 SkAutoGlyphCache(const SkDescriptor* desc) 244 { 245 fCache = SkGlyphCache::DetachCache(desc); 246 } SkAutoGlyphCache(const SkPaint & paint,const SkMatrix * matrix)247 SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix) 248 { 249 fCache = paint.detachCache(matrix); 250 } ~SkAutoGlyphCache()251 ~SkAutoGlyphCache() 252 { 253 if (fCache) 254 SkGlyphCache::AttachCache(fCache); 255 } 256 getCache()257 SkGlyphCache* getCache() const { return fCache; } 258 release()259 void release() 260 { 261 if (fCache) 262 { 263 SkGlyphCache::AttachCache(fCache); 264 fCache = NULL; 265 } 266 } 267 private: 268 SkGlyphCache* fCache; 269 270 static bool DetachProc(const SkGlyphCache*, void*); 271 }; 272 273 #endif 274 275