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 SkStrike_DEFINED 8 #define SkStrike_DEFINED 9 10 #include "SkArenaAlloc.h" 11 #include "SkDescriptor.h" 12 #include "SkFontMetrics.h" 13 #include "SkFontTypes.h" 14 #include "SkGlyph.h" 15 #include "SkGlyphRunPainter.h" 16 #include "SkPaint.h" 17 #include "SkTHash.h" 18 #include "SkScalerContext.h" 19 #include "SkTemplates.h" 20 #include <memory> 21 22 /** \class SkGlyphCache 23 24 This class represents a strike: a specific combination of typeface, size, matrix, etc., and 25 holds the glyphs for that strike. Calling any of the getGlyphID... methods will 26 return the requested glyph, either instantly if it is already cached, or by first generating 27 it and then adding it to the strike. 28 29 The strikes are held in a global list, available to all threads. To interact with one, call 30 either Find{OrCreate}Exclusive(). 31 32 The Find*Exclusive() method returns SkExclusiveStrikePtr, which releases exclusive ownership 33 when they go out of scope. 34 */ 35 class SkStrike : public SkStrikeInterface { 36 public: 37 SkStrike(const SkDescriptor& desc, 38 std::unique_ptr<SkScalerContext> scaler, 39 const SkFontMetrics&); 40 41 const SkDescriptor& getDescriptor() const; 42 43 /** Return true if glyph is cached. */ 44 bool isGlyphCached(SkGlyphID glyphID, SkFixed x, SkFixed y) const; 45 46 /** Return a glyph that has no information if it is not already filled out. */ 47 SkGlyph* getRawGlyphByID(SkPackedGlyphID); 48 49 /** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be 50 valid, but that is not guaranteed. If you require those, call getGlyphIDMetrics instead. 51 */ 52 const SkGlyph& getGlyphIDAdvance(SkGlyphID); 53 54 /** Returns a glyph with all fields valid except fImage and fPath, which may be null. If they 55 are null, call findImage or findPath for those. If they are not null, then they are valid. 56 57 This call is potentially slower than the matching ...Advance call. If you only need the 58 fAdvance/fDevKern fields, call those instead. 59 */ 60 const SkGlyph& getGlyphIDMetrics(SkGlyphID); 61 62 /** These are variants that take the device position of the glyph. Call these only if you are 63 drawing in subpixel mode. Passing 0, 0 is effectively the same as calling the variants 64 w/o the extra params, though a tiny bit slower. 65 */ 66 const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); 67 68 void getAdvances(SkSpan<const SkGlyphID>, SkPoint[]); 69 70 /** Returns the number of glyphs for this strike. 71 */ 72 unsigned getGlyphCount() const; 73 74 /** Return the number of glyphs currently cached. */ 75 int countCachedGlyphs() const; 76 77 /** Return the image associated with the glyph. If it has not been generated this will 78 trigger that. 79 */ 80 const void* findImage(const SkGlyph&); 81 82 /** Initializes the image associated with the glyph with |data|. 83 */ 84 void initializeImage(const volatile void* data, size_t size, SkGlyph*); 85 86 /** If the advance axis intersects the glyph's path, append the positions scaled and offset 87 to the array (if non-null), and set the count to the updated array length. 88 */ 89 void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, 90 bool yAxis, SkGlyph* , SkScalar* array, int* count); 91 92 /** Return the Path associated with the glyph. If it has not been generated this will trigger 93 that. 94 */ 95 const SkPath* findPath(const SkGlyph&); 96 97 /** Initializes the path associated with the glyph with |data|. Returns false if 98 * data is invalid. 99 */ 100 bool initializePath(SkGlyph*, const volatile void* data, size_t size); 101 102 /** Fallback glyphs used during font remoting if the original glyph can't be found. 103 */ 104 bool belongsToCache(const SkGlyph* glyph) const; 105 /** Find any glyph in this cache with the given ID, regardless of subpixel positioning. 106 * If set and present, skip over the glyph with vetoID. 107 */ 108 const SkGlyph* getCachedGlyphAnySubPix(SkGlyphID, 109 SkPackedGlyphID vetoID = SkPackedGlyphID()) const; 110 void initializeGlyphFromFallback(SkGlyph* glyph, const SkGlyph&); 111 112 /** Return the vertical metrics for this strike. 113 */ getFontMetrics()114 const SkFontMetrics& getFontMetrics() const { 115 return fFontMetrics; 116 } 117 getMaskFormat()118 SkMask::Format getMaskFormat() const { 119 return fScalerContext->getMaskFormat(); 120 } 121 isSubpixel()122 bool isSubpixel() const { 123 return fIsSubpixel; 124 } 125 126 SkVector rounding() const override; 127 128 const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) override; 129 130 bool hasImage(const SkGlyph& glyph) override; 131 132 bool hasPath(const SkGlyph& glyph) override; 133 134 /** Return the approx RAM usage for this cache. */ getMemoryUsed()135 size_t getMemoryUsed() const { return fMemoryUsed; } 136 137 void dump() const; 138 getScalerContext()139 SkScalerContext* getScalerContext() const { return fScalerContext.get(); } 140 141 #ifdef SK_DEBUG 142 void forceValidate() const; 143 void validate() const; 144 #else validate()145 void validate() const {} 146 #endif 147 148 class AutoValidate : SkNoncopyable { 149 public: AutoValidate(const SkStrike * cache)150 AutoValidate(const SkStrike* cache) : fCache(cache) { 151 if (fCache) { 152 fCache->validate(); 153 } 154 } ~AutoValidate()155 ~AutoValidate() { 156 if (fCache) { 157 fCache->validate(); 158 } 159 } forget()160 void forget() { 161 fCache = nullptr; 162 } 163 private: 164 const SkStrike* fCache; 165 }; 166 167 private: 168 enum MetricsType { 169 kNothing_MetricsType, 170 kJustAdvance_MetricsType, 171 kFull_MetricsType 172 }; 173 174 enum { 175 kHashBits = 8, 176 kHashCount = 1 << kHashBits, 177 kHashMask = kHashCount - 1 178 }; 179 180 // Return the SkGlyph* associated with MakeID. The id parameter is the 181 // combined glyph/x/y id generated by MakeID. If it is just a glyph id 182 // then x and y are assumed to be zero. 183 SkGlyph* lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, MetricsType type); 184 185 // Return a new SkGlyph for the glyph ID and subpixel position id. Limit the amount 186 // of work using type. 187 SkGlyph* allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsType type); 188 189 static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale, 190 SkScalar xPos, SkScalar* array, int* count); 191 static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept); 192 static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2], 193 bool yAxis, SkGlyph::Intercept* intercept); 194 static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis, 195 SkGlyph::Intercept* intercept); 196 static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis, 197 SkGlyph::Intercept* intercept); 198 static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis, 199 SkGlyph::Intercept* intercept); 200 static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph, 201 const SkScalar bounds[2]); 202 203 const SkAutoDescriptor fDesc; 204 const std::unique_ptr<SkScalerContext> fScalerContext; 205 SkFontMetrics fFontMetrics; 206 207 class GlyphMapHashTraits { 208 public: GetKey(const SkGlyph * glyph)209 static SkPackedGlyphID GetKey(const SkGlyph* glyph) { 210 return glyph->getPackedID(); 211 } Hash(SkPackedGlyphID glyphId)212 static uint32_t Hash(SkPackedGlyphID glyphId) { 213 return glyphId.hash(); 214 } 215 }; 216 217 // Map from a combined GlyphID and sub-pixel position to a SkGlyph*. 218 // The actual glyph is stored in the fAlloc. This structure provides an 219 // unchanging pointer as long as the cache is alive. 220 SkTHashTable<SkGlyph*, SkPackedGlyphID, GlyphMapHashTraits> fGlyphMap; 221 222 // so we don't grow our arrays a lot 223 static constexpr size_t kMinGlyphCount = 8; 224 static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */; 225 static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount; 226 227 SkArenaAlloc fAlloc {kMinAllocAmount}; 228 229 // used to track (approx) how much ram is tied-up in this cache 230 size_t fMemoryUsed; 231 232 const bool fIsSubpixel; 233 const SkAxisAlignment fAxisAlignment; 234 }; 235 236 #endif // SkStrike_DEFINED 237