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 void Dump(); 142 143 /** Dump memory usage statistics of all the attaches caches in the process using the 144 SkTraceMemoryDump interface. 145 */ 146 static void DumpMemoryStatistics(SkTraceMemoryDump* dump); 147 148 typedef void (*Visitor)(const SkGlyphCache&, void* context); 149 static void VisitAll(Visitor, void* context); 150 151 #ifdef SK_DEBUG 152 void validate() const; 153 #else validate()154 void validate() const {} 155 #endif 156 157 class AutoValidate : SkNoncopyable { 158 public: AutoValidate(const SkGlyphCache * cache)159 AutoValidate(const SkGlyphCache* cache) : fCache(cache) { 160 if (fCache) { 161 fCache->validate(); 162 } 163 } ~AutoValidate()164 ~AutoValidate() { 165 if (fCache) { 166 fCache->validate(); 167 } 168 } forget()169 void forget() { 170 fCache = nullptr; 171 } 172 private: 173 const SkGlyphCache* fCache; 174 }; 175 176 private: 177 friend class SkGlyphCache_Globals; 178 179 enum MetricsType { 180 kJustAdvance_MetricsType, 181 kFull_MetricsType 182 }; 183 184 enum { 185 kHashBits = 8, 186 kHashCount = 1 << kHashBits, 187 kHashMask = kHashCount - 1 188 }; 189 190 struct CharGlyphRec { 191 SkPackedUnicharID fPackedUnicharID; 192 SkPackedGlyphID fPackedGlyphID; 193 }; 194 195 SkGlyphCache(const SkDescriptor*, std::unique_ptr<SkScalerContext>); 196 ~SkGlyphCache(); 197 198 // Return the SkGlyph* associated with MakeID. The id parameter is the 199 // combined glyph/x/y id generated by MakeID. If it is just a glyph id 200 // then x and y are assumed to be zero. 201 SkGlyph* lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, MetricsType type); 202 203 // Return a SkGlyph* associated with unicode id and position x and y. 204 SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed y = 0); 205 206 // Return a new SkGlyph for the glyph ID and subpixel position id. Limit the amount 207 // of work using type. 208 SkGlyph* allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsType type); 209 DetachProc(const SkGlyphCache *,void *)210 static bool DetachProc(const SkGlyphCache*, void*) { return true; } 211 212 // The id arg is a combined id generated by MakeID. 213 CharGlyphRec* getCharGlyphRec(SkPackedUnicharID id); 214 215 static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale, 216 SkScalar xPos, SkScalar* array, int* count); 217 static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept); 218 static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2], 219 bool yAxis, SkGlyph::Intercept* intercept); 220 static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis, 221 SkGlyph::Intercept* intercept); 222 static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis, 223 SkGlyph::Intercept* intercept); 224 static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis, 225 SkGlyph::Intercept* intercept); 226 static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph, 227 const SkScalar bounds[2]); 228 229 SkGlyphCache* fNext; 230 SkGlyphCache* fPrev; 231 const std::unique_ptr<SkDescriptor> fDesc; 232 const std::unique_ptr<SkScalerContext> fScalerContext; 233 SkPaint::FontMetrics fFontMetrics; 234 235 // Map from a combined GlyphID and sub-pixel position to a SkGlyph. 236 SkTHashTable<SkGlyph, SkPackedGlyphID, SkGlyph::HashTraits> fGlyphMap; 237 238 // so we don't grow our arrays a lot 239 static constexpr size_t kMinGlyphCount = 8; 240 static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */; 241 static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount; 242 243 SkArenaAlloc fAlloc {kMinAllocAmount}; 244 245 std::unique_ptr<CharGlyphRec[]> fPackedUnicharIDToPackedGlyphID; 246 247 // used to track (approx) how much ram is tied-up in this cache 248 size_t fMemoryUsed; 249 }; 250 251 class SkAutoGlyphCache : public std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor> { 252 public: 253 /** deprecated: use get() */ getCache()254 SkGlyphCache* getCache() const { return this->get(); } 255 SkAutoGlyphCache() = default; SkAutoGlyphCache(SkGlyphCache * cache)256 SkAutoGlyphCache(SkGlyphCache* cache) : INHERITED(cache) {} SkAutoGlyphCache(SkTypeface * typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)257 SkAutoGlyphCache(SkTypeface* typeface, const SkScalerContextEffects& effects, 258 const SkDescriptor* desc) 259 : INHERITED(SkGlyphCache::DetachCache(typeface, effects, desc)) 260 {} 261 /** deprecated: always enables fake gamma */ SkAutoGlyphCache(const SkPaint & paint,const SkSurfaceProps * surfaceProps,const SkMatrix * matrix)262 SkAutoGlyphCache(const SkPaint& paint, 263 const SkSurfaceProps* surfaceProps, 264 const SkMatrix* matrix) 265 : INHERITED(paint.detachCache(surfaceProps, 266 SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags, 267 matrix)) 268 {} SkAutoGlyphCache(const SkPaint & paint,const SkSurfaceProps * surfaceProps,uint32_t scalerContextFlags,const SkMatrix * matrix)269 SkAutoGlyphCache(const SkPaint& paint, 270 const SkSurfaceProps* surfaceProps, 271 uint32_t scalerContextFlags, 272 const SkMatrix* matrix) 273 : INHERITED(paint.detachCache(surfaceProps, scalerContextFlags, matrix)) 274 {} 275 private: 276 using INHERITED = std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor>; 277 }; 278 279 class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCache { 280 public: SkAutoGlyphCacheNoGamma(const SkPaint & paint,const SkSurfaceProps * surfaceProps,const SkMatrix * matrix)281 SkAutoGlyphCacheNoGamma(const SkPaint& paint, 282 const SkSurfaceProps* surfaceProps, 283 const SkMatrix* matrix) 284 : SkAutoGlyphCache(paint, surfaceProps, SkPaint::kNone_ScalerContextFlags, matrix) 285 {} 286 }; 287 #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) 288 #define SkAutoGlyphCacheNoGamma(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCacheNoGamma) 289 290 #endif 291