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