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 found in the LICENSE file. 5 */ 6 7 #ifndef SkGlyphCache_DEFINED 8 #define SkGlyphCache_DEFINED 9 10 #include "SkBitmap.h" 11 #include "SkChunkAlloc.h" 12 #include "SkDescriptor.h" 13 #include "SkGlyph.h" 14 #include "SkPaint.h" 15 #include "SkTHash.h" 16 #include "SkScalerContext.h" 17 #include "SkTemplates.h" 18 #include "SkTDArray.h" 19 20 class SkTraceMemoryDump; 21 22 class SkGlyphCache_Globals; 23 24 /** \class SkGlyphCache 25 26 This class represents a strike: a specific combination of typeface, size, matrix, etc., and 27 holds the glyphs for that strike. Calling any of the getUnichar.../getGlyphID... methods will 28 return the requested glyph, either instantly if it is already cached, or by first generating 29 it and then adding it to the strike. 30 31 The strikes are held in a global list, available to all threads. To interact with one, call 32 either VisitCache() or DetachCache(). 33 */ 34 class SkGlyphCache { 35 public: 36 /** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be 37 valid, but that is not guaranteed. If you require those, call getUnicharMetrics or 38 getGlyphIDMetrics instead. 39 */ 40 const SkGlyph& getUnicharAdvance(SkUnichar); 41 const SkGlyph& getGlyphIDAdvance(uint16_t); 42 43 /** Returns a glyph with all fields valid except fImage and fPath, which may be null. If they 44 are null, call findImage or findPath for those. If they are not null, then they are valid. 45 46 This call is potentially slower than the matching ...Advance call. If you only need the 47 fAdvance/fDevKern fields, call those instead. 48 */ 49 const SkGlyph& getUnicharMetrics(SkUnichar); 50 const SkGlyph& getGlyphIDMetrics(uint16_t); 51 52 /** These are variants that take the device position of the glyph. Call these only if you are 53 drawing in subpixel mode. Passing 0, 0 is effectively the same as calling the variants 54 w/o the extra params, though a tiny bit slower. 55 */ 56 const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); 57 const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); 58 59 /** Return the glyphID for the specified Unichar. If the char has already been seen, use the 60 existing cache entry. If not, ask the scalercontext to compute it for us. 61 */ 62 uint16_t unicharToGlyph(SkUnichar); 63 64 /** Map the glyph to its Unicode equivalent. Unmappable glyphs map to a character code of zero. 65 */ 66 SkUnichar glyphToUnichar(uint16_t); 67 68 /** Returns the number of glyphs for this strike. 69 */ 70 unsigned getGlyphCount() const; 71 72 /** Return the number of glyphs currently cached. */ 73 int countCachedGlyphs() const; 74 75 /** Return the image associated with the glyph. If it has not been generated this will 76 trigger that. 77 */ 78 const void* findImage(const SkGlyph&); 79 80 /** If the advance axis intersects the glyph's path, append the positions scaled and offset 81 to the array (if non-null), and set the count to the updated array length. 82 */ 83 void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, 84 bool yAxis, SkGlyph* , SkScalar* array, int* count); 85 86 /** Return the Path associated with the glyph. If it has not been generated this will trigger 87 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 /** Return the approx RAM usage for this cache. */ getMemoryUsed()108 size_t getMemoryUsed() const { return fMemoryUsed; } 109 110 void dump() const; 111 112 /** AuxProc/Data allow a client to associate data with this cache entry. Multiple clients can 113 use this, as their data is keyed with a function pointer. In addition to serving as a 114 key, the function pointer is called with the data when the glyphcache object is deleted, 115 so the client can cleanup their data as well. 116 NOTE: the auxProc must not try to access this glyphcache in any way, since it may be in 117 the process of being deleted. 118 */ 119 120 //! If the proc is found, return true and set *dataPtr to its data 121 bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const; 122 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 /** Find a matching cache entry, and call proc() with it. If none is found create a new one. 129 If the proc() returns true, detach the cache and return it, otherwise leave it and return 130 nullptr. 131 */ 132 static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, 133 bool (*proc)(const SkGlyphCache*, void*), 134 void* context); 135 136 /** Given a strike that was returned by either VisitCache() or DetachCache() add it back into 137 the global cache list (after which the caller should not reference it anymore. 138 */ 139 static void AttachCache(SkGlyphCache*); 140 using AttachCacheFunctor = SkFunctionWrapper<void, SkGlyphCache, AttachCache>; 141 142 /** Detach a strike from the global cache matching the specified descriptor. Once detached, 143 it can be queried/modified by the current thread, and when finished, be reattached to the 144 global cache with AttachCache(). While detached, if another request is made with the same 145 descriptor, a different strike will be generated. This is fine. It does mean we can have 146 more than 1 strike for the same descriptor, but that will eventually get purged, and the 147 win is that different thread will never block each other while a strike is being used. 148 */ DetachCache(SkTypeface * typeface,const SkDescriptor * desc)149 static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkDescriptor* desc) { 150 return VisitCache(typeface, desc, DetachProc, nullptr); 151 } 152 153 static void Dump(); 154 155 /** Dump memory usage statistics of all the attaches caches in the process using the 156 SkTraceMemoryDump interface. 157 */ 158 static void DumpMemoryStatistics(SkTraceMemoryDump* dump); 159 160 typedef void (*Visitor)(const SkGlyphCache&, void* context); 161 static void VisitAll(Visitor, void* context); 162 163 #ifdef SK_DEBUG 164 void validate() const; 165 #else validate()166 void validate() const {} 167 #endif 168 169 class AutoValidate : SkNoncopyable { 170 public: AutoValidate(const SkGlyphCache * cache)171 AutoValidate(const SkGlyphCache* cache) : fCache(cache) { 172 if (fCache) { 173 fCache->validate(); 174 } 175 } ~AutoValidate()176 ~AutoValidate() { 177 if (fCache) { 178 fCache->validate(); 179 } 180 } forget()181 void forget() { 182 fCache = nullptr; 183 } 184 private: 185 const SkGlyphCache* fCache; 186 }; 187 188 private: 189 friend class SkGlyphCache_Globals; 190 191 enum MetricsType { 192 kJustAdvance_MetricsType, 193 kFull_MetricsType 194 }; 195 196 enum { 197 kHashBits = 8, 198 kHashCount = 1 << kHashBits, 199 kHashMask = kHashCount - 1 200 }; 201 202 typedef uint32_t PackedGlyphID; // glyph-index + subpixel-pos 203 typedef uint32_t PackedUnicharID; // unichar + subpixel-pos 204 205 struct CharGlyphRec { 206 PackedUnicharID fPackedUnicharID; 207 PackedGlyphID fPackedGlyphID; 208 }; 209 210 struct AuxProcRec { 211 AuxProcRec* fNext; 212 void (*fProc)(void*); 213 void* fData; 214 }; 215 216 // SkGlyphCache takes ownership of the scalercontext. 217 SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); 218 ~SkGlyphCache(); 219 220 // Return the SkGlyph* associated with MakeID. The id parameter is the 221 // combined glyph/x/y id generated by MakeID. If it is just a glyph id 222 // then x and y are assumed to be zero. 223 SkGlyph* lookupByPackedGlyphID(PackedGlyphID packedGlyphID, MetricsType type); 224 225 // Return a SkGlyph* associated with unicode id and position x and y. 226 SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed y = 0); 227 228 // Return a new SkGlyph for the glyph ID and subpixel position id. Limit the amount 229 // of work 230 // using type. 231 SkGlyph* allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType type); 232 DetachProc(const SkGlyphCache *,void *)233 static bool DetachProc(const SkGlyphCache*, void*) { return true; } 234 235 // The id arg is a combined id generated by MakeID. 236 CharGlyphRec* getCharGlyphRec(PackedUnicharID id); 237 238 void invokeAndRemoveAuxProcs(); 239 240 inline static SkGlyphCache* FindTail(SkGlyphCache* head); 241 242 static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale, 243 SkScalar xPos, SkScalar* array, int* count); 244 static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept); 245 static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2], 246 bool yAxis, SkGlyph::Intercept* intercept); 247 static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis, 248 SkGlyph::Intercept* intercept); 249 static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis, 250 SkGlyph::Intercept* intercept); 251 static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis, 252 SkGlyph::Intercept* intercept); 253 static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph, 254 const SkScalar bounds[2]); 255 256 SkGlyphCache* fNext; 257 SkGlyphCache* fPrev; 258 SkDescriptor* const fDesc; 259 SkScalerContext* const fScalerContext; 260 SkPaint::FontMetrics fFontMetrics; 261 262 // Map from a combined GlyphID and sub-pixel position to a SkGlyph. 263 SkTHashTable<SkGlyph, PackedGlyphID, SkGlyph::HashTraits> fGlyphMap; 264 265 SkChunkAlloc fGlyphAlloc; 266 267 SkAutoTArray<CharGlyphRec> fPackedUnicharIDToPackedGlyphID; 268 269 // used to track (approx) how much ram is tied-up in this cache 270 size_t fMemoryUsed; 271 272 AuxProcRec* fAuxProcList; 273 }; 274 275 class SkAutoGlyphCache : public skstd::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor> { 276 public: 277 /** deprecated: use get() */ getCache()278 SkGlyphCache* getCache() const { return this->get(); } 279 SkAutoGlyphCache(SkGlyphCache * cache)280 SkAutoGlyphCache(SkGlyphCache* cache) : INHERITED(cache) {} SkAutoGlyphCache(SkTypeface * typeface,const SkDescriptor * desc)281 SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) 282 : INHERITED(SkGlyphCache::DetachCache(typeface, desc)) 283 {} 284 /** deprecated: always enables fake gamma */ SkAutoGlyphCache(const SkPaint & paint,const SkSurfaceProps * surfaceProps,const SkMatrix * matrix)285 SkAutoGlyphCache(const SkPaint& paint, 286 const SkSurfaceProps* surfaceProps, 287 const SkMatrix* matrix) 288 : INHERITED(paint.detachCache(surfaceProps, SkPaint::FakeGamma::On, matrix)) 289 {} SkAutoGlyphCache(const SkPaint & paint,const SkSurfaceProps * surfaceProps,SkPaint::FakeGamma fakeGamma,const SkMatrix * matrix)290 SkAutoGlyphCache(const SkPaint& paint, 291 const SkSurfaceProps* surfaceProps, 292 SkPaint::FakeGamma fakeGamma, 293 const SkMatrix* matrix) 294 : INHERITED(paint.detachCache(surfaceProps, fakeGamma, matrix)) 295 {} 296 private: 297 using INHERITED = skstd::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor>; 298 }; 299 300 class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCache { 301 public: SkAutoGlyphCacheNoGamma(const SkPaint & paint,const SkSurfaceProps * surfaceProps,const SkMatrix * matrix)302 SkAutoGlyphCacheNoGamma(const SkPaint& paint, 303 const SkSurfaceProps* surfaceProps, 304 const SkMatrix* matrix) 305 : SkAutoGlyphCache(paint, surfaceProps, SkPaint::FakeGamma::Off, matrix) 306 {} 307 }; 308 #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) 309 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma) 310 311 #endif 312