• 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
5  * found in the LICENSE file.
6  */
7 
8 #include "src/core/SkScalerCache.h"
9 
10 #include "include/core/SkDrawable.h"
11 #include "include/core/SkGraphics.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkTypeface.h"
14 #include "src/core/SkEnumerate.h"
15 #include "src/core/SkScalerContext.h"
16 
use_or_generate_metrics(const SkFontMetrics * metrics,SkScalerContext * context)17 static SkFontMetrics use_or_generate_metrics(
18         const SkFontMetrics* metrics, SkScalerContext* context) {
19     SkFontMetrics answer;
20     if (metrics) {
21         answer = *metrics;
22     } else {
23         context->getFontMetrics(&answer);
24     }
25     return answer;
26 }
27 
SkScalerCache(std::unique_ptr<SkScalerContext> scaler,const SkFontMetrics * fontMetrics)28 SkScalerCache::SkScalerCache(
29     std::unique_ptr<SkScalerContext> scaler,
30     const SkFontMetrics* fontMetrics)
31         : fScalerContext{std::move(scaler)}
32         , fFontMetrics{use_or_generate_metrics(fontMetrics, fScalerContext.get())}
33         , fRoundingSpec{fScalerContext->isSubpixel(),
34                         fScalerContext->computeAxisAlignmentForHText()} {
35     SkASSERT(fScalerContext != nullptr);
36 }
37 
glyph(SkPackedGlyphID packedGlyphID)38 std::tuple<SkGlyph*, size_t> SkScalerCache::glyph(SkPackedGlyphID packedGlyphID) {
39     auto [digest, size] = this->digest(packedGlyphID);
40     return {fGlyphForIndex[digest.index()], size};
41 }
42 
digest(SkPackedGlyphID packedGlyphID)43 std::tuple<SkGlyphDigest, size_t> SkScalerCache::digest(SkPackedGlyphID packedGlyphID) {
44     SkGlyphDigest* digest = fDigestForPackedGlyphID.find(packedGlyphID.value());
45 
46     if (digest != nullptr) {
47         return {*digest, 0};
48     }
49 
50     SkGlyph* glyph = fAlloc.make<SkGlyph>(fScalerContext->makeGlyph(packedGlyphID, &fAlloc));
51     return {this->addGlyph(glyph), sizeof(SkGlyph)};
52 }
53 
addGlyph(SkGlyph * glyph)54 SkGlyphDigest SkScalerCache::addGlyph(SkGlyph* glyph) {
55     size_t index = fGlyphForIndex.size();
56     SkGlyphDigest digest = SkGlyphDigest{index, *glyph};
57     fDigestForPackedGlyphID.set(digest);
58     fGlyphForIndex.push_back(glyph);
59     return digest;
60 }
61 
preparePath(SkGlyph * glyph)62 std::tuple<const SkPath*, size_t> SkScalerCache::preparePath(SkGlyph* glyph) {
63     size_t delta = 0;
64     if (glyph->setPath(&fAlloc, fScalerContext.get())) {
65         delta = glyph->path()->approximateBytesUsed();
66     }
67     return {glyph->path(), delta};
68 }
69 
mergePath(SkGlyph * glyph,const SkPath * path,bool hairline)70 std::tuple<const SkPath*, size_t> SkScalerCache::mergePath(
71         SkGlyph* glyph, const SkPath* path, bool hairline) {
72     SkAutoMutexExclusive lock{fMu};
73     size_t pathDelta = 0;
74     if (glyph->setPathHasBeenCalled()) {
75         SkDEBUGFAIL("Re-adding path to existing glyph. This should not happen.");
76     }
77     if (glyph->setPath(&fAlloc, path, hairline)) {
78         pathDelta = glyph->path()->approximateBytesUsed();
79     }
80     return {glyph->path(), pathDelta};
81 }
82 
prepareDrawable(SkGlyph * glyph)83 std::tuple<SkDrawable*, size_t> SkScalerCache::prepareDrawable(SkGlyph* glyph) {
84     size_t delta = 0;
85     if (glyph->setDrawable(&fAlloc, fScalerContext.get())) {
86         delta = glyph->drawable()->approximateBytesUsed();
87         SkASSERT(delta > 0);
88     }
89     return {glyph->drawable(), delta};
90 }
91 
mergeDrawable(SkGlyph * glyph,sk_sp<SkDrawable> drawable)92 std::tuple<SkDrawable*, size_t> SkScalerCache::mergeDrawable(SkGlyph* glyph,
93                                                              sk_sp<SkDrawable> drawable) {
94     SkAutoMutexExclusive lock{fMu};
95     size_t delta = 0;
96     if (glyph->setDrawableHasBeenCalled()) {
97         SkDEBUGFAIL("Re-adding drawable to existing glyph. This should not happen.");
98     }
99     if (glyph->setDrawable(&fAlloc, std::move(drawable))) {
100         delta = glyph->drawable()->approximateBytesUsed();
101         SkASSERT(delta > 0);
102     }
103     return {glyph->drawable(), delta};
104 }
105 
countCachedGlyphs() const106 int SkScalerCache::countCachedGlyphs() const {
107     SkAutoMutexExclusive lock(fMu);
108     return fDigestForPackedGlyphID.count();
109 }
110 
internalPrepare(SkSpan<const SkGlyphID> glyphIDs,PathDetail pathDetail,const SkGlyph ** results)111 std::tuple<SkSpan<const SkGlyph*>, size_t> SkScalerCache::internalPrepare(
112         SkSpan<const SkGlyphID> glyphIDs, PathDetail pathDetail, const SkGlyph** results) {
113     const SkGlyph** cursor = results;
114     size_t delta = 0;
115     for (auto glyphID : glyphIDs) {
116         auto [glyph, size] = this->glyph(SkPackedGlyphID{glyphID});
117         delta += size;
118         if (pathDetail == kMetricsAndPath) {
119             auto [_, pathSize] = this->preparePath(glyph);
120             delta += pathSize;
121         }
122         *cursor++ = glyph;
123     }
124 
125     return {{results, glyphIDs.size()}, delta};
126 }
127 
prepareImage(SkGlyph * glyph)128 std::tuple<const void*, size_t> SkScalerCache::prepareImage(SkGlyph* glyph) {
129     size_t delta = 0;
130     if (glyph->setImage(&fAlloc, fScalerContext.get())) {
131         delta = glyph->imageSize();
132     }
133     return {glyph->image(), delta};
134 }
135 
mergeGlyphAndImage(SkPackedGlyphID toID,const SkGlyph & from)136 std::tuple<SkGlyph*, size_t> SkScalerCache::mergeGlyphAndImage(
137         SkPackedGlyphID toID, const SkGlyph& from) {
138     SkAutoMutexExclusive lock{fMu};
139     // TODO(herb): remove finding the glyph when setting the metrics and image are separated
140     SkGlyphDigest* digest = fDigestForPackedGlyphID.find(toID.value());
141     if (digest != nullptr) {
142         SkGlyph* to = fGlyphForIndex[digest->index()];
143         size_t delta = 0;
144         if (from.setImageHasBeenCalled()) {
145             if (to->setImageHasBeenCalled()) {
146                 // Should never set an image on a glyph which already has an image.
147                 SkDEBUGFAIL("Re-adding image to existing glyph. This should not happen.");
148             }
149             // TODO: assert that any metrics on `from` are the same.
150             delta = to->setMetricsAndImage(&fAlloc, from);
151         }
152         return {to, delta};
153     } else {
154         SkGlyph* glyph = fAlloc.make<SkGlyph>(toID);
155         size_t delta = glyph->setMetricsAndImage(&fAlloc, from);
156         (void)this->addGlyph(glyph);
157         return {glyph, sizeof(SkGlyph) + delta};
158     }
159 }
160 
metrics(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])161 std::tuple<SkSpan<const SkGlyph*>, size_t> SkScalerCache::metrics(
162         SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
163     SkAutoMutexExclusive lock{fMu};
164     auto [glyphs, delta] = this->internalPrepare(glyphIDs, kMetricsOnly, results);
165     return {glyphs, delta};
166 }
167 
preparePaths(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])168 std::tuple<SkSpan<const SkGlyph*>, size_t> SkScalerCache::preparePaths(
169         SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
170     SkAutoMutexExclusive lock{fMu};
171     auto [glyphs, delta] = this->internalPrepare(glyphIDs, kMetricsAndPath, results);
172     return {glyphs, delta};
173 }
174 
prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,const SkGlyph * results[])175 std::tuple<SkSpan<const SkGlyph*>, size_t> SkScalerCache::prepareImages(
176         SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) {
177     const SkGlyph** cursor = results;
178     SkAutoMutexExclusive lock{fMu};
179     size_t delta = 0;
180     for (auto glyphID : glyphIDs) {
181         auto[glyph, glyphSize] = this->glyph(glyphID);
182         auto[_, imageSize] = this->prepareImage(glyph);
183         delta += glyphSize + imageSize;
184         *cursor++ = glyph;
185     }
186 
187     return {{results, glyphIDs.size()}, delta};
188 }
189 
190 template <typename Fn>
commonFilterLoop(SkDrawableGlyphBuffer * accepted,Fn && fn)191 size_t SkScalerCache::commonFilterLoop(SkDrawableGlyphBuffer* accepted, Fn&& fn) {
192     size_t total = 0;
193     for (auto [i, packedID, pos] : SkMakeEnumerate(accepted->input())) {
194         if (SkScalarsAreFinite(pos.x(), pos.y())) {
195             auto [digest, size] = this->digest(packedID);
196             total += size;
197             if (!digest.isEmpty()) {
198                 fn(i, digest, pos);
199             }
200         }
201     }
202     return total;
203 }
204 
prepareForDrawingMasksCPU(SkDrawableGlyphBuffer * accepted)205 size_t SkScalerCache::prepareForDrawingMasksCPU(SkDrawableGlyphBuffer* accepted) {
206     SkAutoMutexExclusive lock{fMu};
207     size_t imageDelta = 0;
208     size_t delta = this->commonFilterLoop(accepted,
209         [&](size_t i, SkGlyphDigest digest, SkPoint pos) SK_REQUIRES(fMu) {
210             // If the glyph is too large, then no image is created.
211             SkGlyph* glyph = fGlyphForIndex[digest.index()];
212             auto [image, imageSize] = this->prepareImage(glyph);
213             if (image != nullptr) {
214                 accepted->accept(glyph, i);
215                 imageDelta += imageSize;
216             }
217         });
218 
219     return delta + imageDelta;
220 }
221 
222 // Note: this does not actually fill out the image. That happens at atlas building time.
prepareForMaskDrawing(SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)223 size_t SkScalerCache::prepareForMaskDrawing(
224         SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) {
225     SkAutoMutexExclusive lock{fMu};
226     size_t delta = this->commonFilterLoop(accepted,
227         [&](size_t i, SkGlyphDigest digest, SkPoint pos) SK_REQUIRES(fMu) {
228             // N.B. this must have the same behavior as RemoteStrike::prepareForMaskDrawing.
229             if (digest.canDrawAsMask()) {
230                 accepted->accept(fGlyphForIndex[digest.index()], i);
231             } else {
232                 rejected->reject(i, digest.maxDimension());
233             }
234         });
235 
236     return delta;
237 }
238 
prepareForSDFTDrawing(SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)239 size_t SkScalerCache::prepareForSDFTDrawing(
240         SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) {
241     SkAutoMutexExclusive lock{fMu};
242     size_t delta = this->commonFilterLoop(accepted,
243         [&](size_t i, SkGlyphDigest digest, SkPoint pos) SK_REQUIRES(fMu) {
244             if (digest.canDrawAsSDFT()) {
245                 accepted->accept(fGlyphForIndex[digest.index()], i);
246             } else {
247                 // Assume whatever follows SDF doesn't care about the maximum rejected size.
248                 rejected->reject(i);
249             }
250         });
251 
252     return delta;
253 }
254 
prepareForPathDrawing(SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)255 size_t SkScalerCache::prepareForPathDrawing(
256         SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) {
257     SkAutoMutexExclusive lock{fMu};
258     size_t pathDelta = 0;
259     size_t delta = this->commonFilterLoop(accepted,
260         [&](size_t i, SkGlyphDigest digest, SkPoint pos) SK_REQUIRES(fMu) {
261             SkGlyph* glyph = fGlyphForIndex[digest.index()];
262             auto [path, pathSize] = this->preparePath(glyph);
263             pathDelta += pathSize;
264             if (path != nullptr) {
265                 // Save off the path to draw later.
266                 accepted->accept(path, i);
267             } else {
268                 // Glyph does not have a path.
269                 rejected->reject(i, digest.maxDimension());
270             }
271         });
272 
273     return delta + pathDelta;
274 }
275 
prepareForDrawableDrawing(SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)276 size_t SkScalerCache::prepareForDrawableDrawing(
277         SkDrawableGlyphBuffer* accepted, SkSourceGlyphBuffer* rejected) {
278     SkAutoMutexExclusive lock{fMu};
279     size_t drawableDelta = 0;
280     size_t delta = this->commonFilterLoop(accepted,
281         [&](size_t i, SkGlyphDigest digest, SkPoint pos) SK_REQUIRES(fMu) {
282             SkGlyph* glyph = fGlyphForIndex[digest.index()];
283             auto [drawable, drawableSize] = this->prepareDrawable(glyph);
284             drawableDelta += drawableSize;
285             if (drawable != nullptr) {
286                 // Save off the drawable to draw later.
287                 accepted->accept(drawable, i);
288             } else {
289                 // Glyph does not have a drawable.
290                 rejected->reject(i, glyph->maxDimension());
291             }
292         });
293 
294     return delta + drawableDelta;
295 }
296 
findIntercepts(const SkScalar bounds[2],SkScalar scale,SkScalar xPos,SkGlyph * glyph,SkScalar * array,int * count)297 void SkScalerCache::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
298         SkGlyph* glyph, SkScalar* array, int* count) {
299     SkAutoMutexExclusive lock{fMu};
300     glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
301 }
302 
dump() const303 void SkScalerCache::dump() const {
304     SkAutoMutexExclusive lock{fMu};
305     const SkTypeface* face = fScalerContext->getTypeface();
306     const SkScalerContextRec& rec = fScalerContext->getRec();
307     SkMatrix matrix;
308     rec.getSingleMatrix(&matrix);
309     matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
310     SkString name;
311     face->getFamilyName(&name);
312 
313     SkString msg;
314     SkFontStyle style = face->fontStyle();
315     msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d",
316                face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(),
317                rec.dump().c_str(), fDigestForPackedGlyphID.count());
318     SkDebugf("%s\n", msg.c_str());
319 }
320 
321