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