Line data Source code
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 : */
94 0 : const SkPaint::FontMetrics& getFontMetrics() const {
95 0 : return fFontMetrics;
96 : }
97 :
98 0 : const SkDescriptor& getDescriptor() const { return *fDesc; }
99 :
100 : SkMask::Format getMaskFormat() const {
101 : return fScalerContext->getMaskFormat();
102 : }
103 :
104 21 : bool isSubpixel() const {
105 21 : return fScalerContext->isSubpixel();
106 : }
107 :
108 : /** Return the approx RAM usage for this cache. */
109 0 : size_t getMemoryUsed() const { return fMemoryUsed; }
110 :
111 : void dump() const;
112 :
113 21 : 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 : */
136 21 : static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkScalerContextEffects& effects,
137 : const SkDescriptor* desc) {
138 21 : 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
154 : void validate() const {}
155 : #endif
156 :
157 : class AutoValidate : SkNoncopyable {
158 : public:
159 450 : AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
160 450 : if (fCache) {
161 450 : fCache->validate();
162 : }
163 450 : }
164 900 : ~AutoValidate() {
165 450 : if (fCache) {
166 450 : fCache->validate();
167 : }
168 450 : }
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 0 : 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 :
210 21 : 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 21 : class SkAutoGlyphCache : public std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor> {
252 : public:
253 : /** deprecated: use get() */
254 0 : SkGlyphCache* getCache() const { return this->get(); }
255 : SkAutoGlyphCache() = default;
256 : SkAutoGlyphCache(SkGlyphCache* cache) : INHERITED(cache) {}
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 */
262 0 : SkAutoGlyphCache(const SkPaint& paint,
263 : const SkSurfaceProps* surfaceProps,
264 : const SkMatrix* matrix)
265 0 : : INHERITED(paint.detachCache(surfaceProps,
266 : SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags,
267 0 : matrix))
268 0 : {}
269 21 : SkAutoGlyphCache(const SkPaint& paint,
270 : const SkSurfaceProps* surfaceProps,
271 : uint32_t scalerContextFlags,
272 : const SkMatrix* matrix)
273 21 : : INHERITED(paint.detachCache(surfaceProps, scalerContextFlags, matrix))
274 21 : {}
275 : private:
276 : using INHERITED = std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor>;
277 : };
278 :
279 : class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCache {
280 : public:
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
|