• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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