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/SkStrike.h"
9
10 #include "include/core/SkDrawable.h"
11 #include "include/core/SkFontStyle.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkPath.h"
14 #include "include/core/SkString.h"
15 #include "include/core/SkTraceMemoryDump.h"
16 #include "include/core/SkTypeface.h"
17 #include "include/private/base/SkDebug.h"
18 #include "include/private/base/SkTFitsIn.h"
19 #include "src/core/SkGlyph.h"
20 #include "src/core/SkMask.h"
21 #include "src/core/SkReadBuffer.h"
22 #include "src/core/SkScalerContext.h"
23 #include "src/core/SkStrikeCache.h"
24 #include "src/core/SkWriteBuffer.h"
25 #include "src/text/StrikeForGPU.h"
26
27 #include <cctype>
28 #include <new>
29 #include <optional>
30 #include <utility>
31
32 using namespace skglyph;
33
use_or_generate_metrics(const SkFontMetrics * metrics,SkScalerContext * context)34 static SkFontMetrics use_or_generate_metrics(
35 const SkFontMetrics* metrics, SkScalerContext* context) {
36 SkFontMetrics answer;
37 if (metrics) {
38 answer = *metrics;
39 } else {
40 context->getFontMetrics(&answer);
41 }
42 return answer;
43 }
44
SkStrike(SkStrikeCache * strikeCache,const SkStrikeSpec & strikeSpec,std::unique_ptr<SkScalerContext> scaler,const SkFontMetrics * metrics,std::unique_ptr<SkStrikePinner> pinner)45 SkStrike::SkStrike(SkStrikeCache* strikeCache,
46 const SkStrikeSpec& strikeSpec,
47 std::unique_ptr<SkScalerContext> scaler,
48 const SkFontMetrics* metrics,
49 std::unique_ptr<SkStrikePinner> pinner)
50 : fFontMetrics{use_or_generate_metrics(metrics, scaler.get())}
51 , fRoundingSpec{scaler->isSubpixel(),
52 scaler->computeAxisAlignmentForHText()}
53 , fStrikeSpec{strikeSpec}
54 , fStrikeCache{strikeCache}
55 , fScalerContext{std::move(scaler)}
56 , fPinner{std::move(pinner)} {
57 SkASSERT(fScalerContext != nullptr);
58 }
59
60 class SK_SCOPED_CAPABILITY SkStrike::Monitor {
61 public:
62 Monitor(SkStrike* strike) SK_ACQUIRE(strike->fStrikeLock)
63 : fStrike{strike} {
64 fStrike->lock();
65 }
66
SK_RELEASE_CAPABILITY()67 ~Monitor() SK_RELEASE_CAPABILITY() {
68 fStrike->unlock();
69 }
70
71 private:
72 SkStrike* const fStrike;
73 };
74
lock()75 void SkStrike::lock() {
76 fStrikeLock.acquire();
77 fMemoryIncrease = 0;
78 }
79
unlock()80 void SkStrike::unlock() {
81 const size_t memoryIncrease = fMemoryIncrease;
82 fStrikeLock.release();
83 this->updateMemoryUsage(memoryIncrease);
84 }
85
86 void
FlattenGlyphsByType(SkWriteBuffer & buffer,SkSpan<SkGlyph> images,SkSpan<SkGlyph> paths,SkSpan<SkGlyph> drawables)87 SkStrike::FlattenGlyphsByType(SkWriteBuffer& buffer,
88 SkSpan<SkGlyph> images,
89 SkSpan<SkGlyph> paths,
90 SkSpan<SkGlyph> drawables) {
91 SkASSERT_RELEASE(SkTFitsIn<int>(images.size()) &&
92 SkTFitsIn<int>(paths.size()) &&
93 SkTFitsIn<int>(drawables.size()));
94
95 buffer.writeInt(images.size());
96 for (SkGlyph& glyph : images) {
97 SkASSERT(SkMask::IsValidFormat(glyph.maskFormat()));
98 glyph.flattenMetrics(buffer);
99 glyph.flattenImage(buffer);
100 }
101
102 buffer.writeInt(paths.size());
103 for (SkGlyph& glyph : paths) {
104 SkASSERT(SkMask::IsValidFormat(glyph.maskFormat()));
105 glyph.flattenMetrics(buffer);
106 glyph.flattenPath(buffer);
107 }
108
109 buffer.writeInt(drawables.size());
110 for (SkGlyph& glyph : drawables) {
111 SkASSERT(SkMask::IsValidFormat(glyph.maskFormat()));
112 glyph.flattenMetrics(buffer);
113 glyph.flattenDrawable(buffer);
114 }
115 }
116
mergeFromBuffer(SkReadBuffer & buffer)117 bool SkStrike::mergeFromBuffer(SkReadBuffer& buffer) {
118 // Read glyphs with images for the current strike.
119 const int imagesCount = buffer.readInt();
120 if (imagesCount == 0 && !buffer.isValid()) {
121 return false;
122 }
123
124 {
125 Monitor m{this};
126 for (int curImage = 0; curImage < imagesCount; ++curImage) {
127 if (!this->mergeGlyphAndImageFromBuffer(buffer)) {
128 return false;
129 }
130 }
131 }
132
133 // Read glyphs with paths for the current strike.
134 const int pathsCount = buffer.readInt();
135 if (pathsCount == 0 && !buffer.isValid()) {
136 return false;
137 }
138 {
139 Monitor m{this};
140 for (int curPath = 0; curPath < pathsCount; ++curPath) {
141 if (!this->mergeGlyphAndPathFromBuffer(buffer)) {
142 return false;
143 }
144 }
145 }
146
147 // Read glyphs with drawables for the current strike.
148 const int drawablesCount = buffer.readInt();
149 if (drawablesCount == 0 && !buffer.isValid()) {
150 return false;
151 }
152 {
153 Monitor m{this};
154 for (int curDrawable = 0; curDrawable < drawablesCount; ++curDrawable) {
155 if (!this->mergeGlyphAndDrawableFromBuffer(buffer)) {
156 return false;
157 }
158 }
159 }
160
161 return true;
162 }
163
mergeGlyphAndImage(SkPackedGlyphID toID,const SkGlyph & fromGlyph)164 SkGlyph* SkStrike::mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& fromGlyph) {
165 Monitor m{this};
166 // TODO(herb): remove finding the glyph when setting the metrics and image are separated
167 SkGlyphDigest* digest = fDigestForPackedGlyphID.find(toID);
168 if (digest != nullptr) {
169 SkGlyph* glyph = fGlyphForIndex[digest->index()];
170 if (fromGlyph.setImageHasBeenCalled()) {
171 if (glyph->setImageHasBeenCalled()) {
172 // Should never set an image on a glyph which already has an image.
173 SkDEBUGFAIL("Re-adding image to existing glyph. This should not happen.");
174 }
175 // TODO: assert that any metrics on fromGlyph are the same.
176 fMemoryIncrease += glyph->setMetricsAndImage(&fAlloc, fromGlyph);
177 }
178 return glyph;
179 } else {
180 SkGlyph* glyph = fAlloc.make<SkGlyph>(toID);
181 fMemoryIncrease += glyph->setMetricsAndImage(&fAlloc, fromGlyph) + sizeof(SkGlyph);
182 (void)this->addGlyphAndDigest(glyph);
183 return glyph;
184 }
185 }
186
mergePath(SkGlyph * glyph,const SkPath * path,bool hairline,bool modified)187 const SkPath* SkStrike::mergePath(SkGlyph* glyph, const SkPath* path, bool hairline, bool modified) {
188 Monitor m{this};
189 if (glyph->setPathHasBeenCalled()) {
190 SkDEBUGFAIL("Re-adding path to existing glyph. This should not happen.");
191 }
192 if (glyph->setPath(&fAlloc, path, hairline, modified)) {
193 fMemoryIncrease += glyph->path()->approximateBytesUsed();
194 }
195
196 return glyph->path();
197 }
198
mergeDrawable(SkGlyph * glyph,sk_sp<SkDrawable> drawable)199 const SkDrawable* SkStrike::mergeDrawable(SkGlyph* glyph, sk_sp<SkDrawable> drawable) {
200 Monitor m{this};
201 if (glyph->setDrawableHasBeenCalled()) {
202 SkDEBUGFAIL("Re-adding drawable to existing glyph. This should not happen.");
203 }
204 if (glyph->setDrawable(&fAlloc, std::move(drawable))) {
205 fMemoryIncrease += glyph->drawable()->approximateBytesUsed();
206 SkASSERT(fMemoryIncrease > 0);
207 }
208
209 return glyph->drawable();
210 }
211
findIntercepts(const SkScalar bounds[2],SkScalar scale,SkScalar xPos,SkGlyph * glyph,SkScalar * array,int * count)212 void SkStrike::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
213 SkGlyph* glyph, SkScalar* array, int* count) {
214 SkAutoMutexExclusive lock{fStrikeLock};
215 glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
216 }
217
metrics(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])218 SkSpan<const SkGlyph*> SkStrike::metrics(
219 SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
220 Monitor m{this};
221 return this->internalPrepare(glyphIDs, kMetricsOnly, results);
222 }
223
preparePaths(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])224 SkSpan<const SkGlyph*> SkStrike::preparePaths(
225 SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
226 Monitor m{this};
227 return this->internalPrepare(glyphIDs, kMetricsAndPath, results);
228 }
229
prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,const SkGlyph * results[])230 SkSpan<const SkGlyph*> SkStrike::prepareImages(
231 SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) {
232 const SkGlyph** cursor = results;
233 Monitor m{this};
234 for (auto glyphID : glyphIDs) {
235 SkGlyph* glyph = this->glyph(glyphID);
236 this->prepareForImage(glyph);
237 *cursor++ = glyph;
238 }
239
240 return {results, glyphIDs.size()};
241 }
242
prepareDrawables(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])243 SkSpan<const SkGlyph*> SkStrike::prepareDrawables(
244 SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
245 const SkGlyph** cursor = results;
246 {
247 Monitor m{this};
248 for (auto glyphID : glyphIDs) {
249 SkGlyph* glyph = this->glyph(SkPackedGlyphID{glyphID});
250 this->prepareForDrawable(glyph);
251 *cursor++ = glyph;
252 }
253 }
254
255 return {results, glyphIDs.size()};
256 }
257
glyphIDsToPaths(SkSpan<sktext::IDOrPath> idsOrPaths)258 void SkStrike::glyphIDsToPaths(SkSpan<sktext::IDOrPath> idsOrPaths) {
259 Monitor m{this};
260 for (sktext::IDOrPath& idOrPath : idsOrPaths) {
261 SkGlyph* glyph = this->glyph(SkPackedGlyphID{idOrPath.fGlyphID});
262 this->prepareForPath(glyph);
263 new (&idOrPath.fPath) SkPath{*glyph->path()};
264 }
265 }
266
glyphIDsToDrawables(SkSpan<sktext::IDOrDrawable> idsOrDrawables)267 void SkStrike::glyphIDsToDrawables(SkSpan<sktext::IDOrDrawable> idsOrDrawables) {
268 Monitor m{this};
269 for (sktext::IDOrDrawable& idOrDrawable : idsOrDrawables) {
270 SkGlyph* glyph = this->glyph(SkPackedGlyphID{idOrDrawable.fGlyphID});
271 this->prepareForDrawable(glyph);
272 SkASSERT(glyph->drawable() != nullptr);
273 idOrDrawable.fDrawable = glyph->drawable();
274 }
275 }
276
dump() const277 void SkStrike::dump() const {
278 SkAutoMutexExclusive lock{fStrikeLock};
279 const SkTypeface* face = fScalerContext->getTypeface();
280 const SkScalerContextRec& rec = fScalerContext->getRec();
281 SkMatrix matrix;
282 rec.getSingleMatrix(&matrix);
283 matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
284 SkString name;
285 face->getFamilyName(&name);
286
287 SkString msg;
288 SkFontStyle style = face->fontStyle();
289 msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d",
290 face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(),
291 rec.dump().c_str(), fDigestForPackedGlyphID.count());
292 SkDebugf("%s\n", msg.c_str());
293 }
294
dumpMemoryStatistics(SkTraceMemoryDump * dump) const295 void SkStrike::dumpMemoryStatistics(SkTraceMemoryDump* dump) const {
296 SkAutoMutexExclusive lock{fStrikeLock};
297 const SkTypeface* face = fScalerContext->getTypeface();
298 const SkScalerContextRec& rec = fScalerContext->getRec();
299
300 SkString fontName;
301 face->getFamilyName(&fontName);
302 // Replace all special characters with '_'.
303 for (size_t index = 0; index < fontName.size(); ++index) {
304 if (!std::isalnum(fontName[index])) {
305 fontName[index] = '_';
306 }
307 }
308
309 SkString dumpName = SkStringPrintf("%s/%s_%u/%p",
310 SkStrikeCache::kGlyphCacheDumpName,
311 fontName.c_str(),
312 rec.fTypefaceID,
313 this);
314
315 dump->dumpNumericValue(dumpName.c_str(), "size", "bytes", fMemoryUsed);
316 dump->dumpNumericValue(dumpName.c_str(),
317 "glyph_count", "objects",
318 fDigestForPackedGlyphID.count());
319 dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
320 }
321
glyph(SkGlyphDigest digest)322 SkGlyph* SkStrike::glyph(SkGlyphDigest digest) {
323 return fGlyphForIndex[digest.index()];
324 }
325
glyph(SkPackedGlyphID packedGlyphID)326 SkGlyph* SkStrike::glyph(SkPackedGlyphID packedGlyphID) {
327 SkGlyphDigest digest = this->digestFor(kDirectMask, packedGlyphID);
328 return this->glyph(digest);
329 }
330
digestFor(ActionType actionType,SkPackedGlyphID packedGlyphID)331 SkGlyphDigest SkStrike::digestFor(ActionType actionType, SkPackedGlyphID packedGlyphID) {
332 SkGlyphDigest* digestPtr = fDigestForPackedGlyphID.find(packedGlyphID);
333 if (digestPtr != nullptr && digestPtr->actionFor(actionType) != GlyphAction::kUnset) {
334 return *digestPtr;
335 }
336
337 SkGlyph* glyph;
338 if (digestPtr != nullptr) {
339 glyph = fGlyphForIndex[digestPtr->index()];
340 } else {
341 glyph = fAlloc.make<SkGlyph>(fScalerContext->makeGlyph(packedGlyphID, &fAlloc));
342 fMemoryIncrease += sizeof(SkGlyph);
343 digestPtr = this->addGlyphAndDigest(glyph);
344 }
345
346 digestPtr->setActionFor(actionType, glyph, this);
347
348 return *digestPtr;
349 }
350
addGlyphAndDigest(SkGlyph * glyph)351 SkGlyphDigest* SkStrike::addGlyphAndDigest(SkGlyph* glyph) {
352 size_t index = fGlyphForIndex.size();
353 SkGlyphDigest digest = SkGlyphDigest{index, *glyph};
354 SkGlyphDigest* newDigest = fDigestForPackedGlyphID.set(digest);
355 fGlyphForIndex.push_back(glyph);
356 return newDigest;
357 }
358
prepareForImage(SkGlyph * glyph)359 bool SkStrike::prepareForImage(SkGlyph* glyph) {
360 if (glyph->setImage(&fAlloc, fScalerContext.get())) {
361 fMemoryIncrease += glyph->imageSize();
362 }
363 return glyph->image() != nullptr;
364 }
365
prepareForPath(SkGlyph * glyph)366 bool SkStrike::prepareForPath(SkGlyph* glyph) {
367 if (glyph->setPath(&fAlloc, fScalerContext.get())) {
368 fMemoryIncrease += glyph->path()->approximateBytesUsed();
369 }
370 return glyph->path() !=nullptr;
371 }
372
prepareForDrawable(SkGlyph * glyph)373 bool SkStrike::prepareForDrawable(SkGlyph* glyph) {
374 if (glyph->setDrawable(&fAlloc, fScalerContext.get())) {
375 size_t increase = glyph->drawable()->approximateBytesUsed();
376 SkASSERT(increase > 0);
377 fMemoryIncrease += increase;
378 }
379 return glyph->drawable() != nullptr;
380 }
381
mergeGlyphFromBuffer(SkReadBuffer & buffer)382 SkGlyph* SkStrike::mergeGlyphFromBuffer(SkReadBuffer& buffer) {
383 SkASSERT(buffer.isValid());
384 std::optional<SkGlyph> prototypeGlyph = SkGlyph::MakeFromBuffer(buffer);
385 if (!buffer.validate(prototypeGlyph.has_value())) {
386 return nullptr;
387 }
388
389 // Check if this glyph has already been seen.
390 SkGlyphDigest* digestPtr = fDigestForPackedGlyphID.find(prototypeGlyph->getPackedID());
391 if (digestPtr != nullptr) {
392 return fGlyphForIndex[digestPtr->index()];
393 }
394
395 // This is the first time. Allocate a new glyph.
396 SkGlyph* glyph = fAlloc.make<SkGlyph>(prototypeGlyph.value());
397 fMemoryIncrease += sizeof(SkGlyph);
398 this->addGlyphAndDigest(glyph);
399 return glyph;
400 }
401
mergeGlyphAndImageFromBuffer(SkReadBuffer & buffer)402 bool SkStrike::mergeGlyphAndImageFromBuffer(SkReadBuffer& buffer) {
403 SkASSERT(buffer.isValid());
404 SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
405 if (!buffer.validate(glyph != nullptr)) {
406 return false;
407 }
408 fMemoryIncrease += glyph->addImageFromBuffer(buffer, &fAlloc);
409 return buffer.isValid();
410 }
411
mergeGlyphAndPathFromBuffer(SkReadBuffer & buffer)412 bool SkStrike::mergeGlyphAndPathFromBuffer(SkReadBuffer& buffer) {
413 SkASSERT(buffer.isValid());
414 SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
415 if (!buffer.validate(glyph != nullptr)) {
416 return false;
417 }
418 fMemoryIncrease += glyph->addPathFromBuffer(buffer, &fAlloc);
419 return buffer.isValid();
420 }
421
mergeGlyphAndDrawableFromBuffer(SkReadBuffer & buffer)422 bool SkStrike::mergeGlyphAndDrawableFromBuffer(SkReadBuffer& buffer) {
423 SkASSERT(buffer.isValid());
424 SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
425 if (!buffer.validate(glyph != nullptr)) {
426 return false;
427 }
428 fMemoryIncrease += glyph->addDrawableFromBuffer(buffer, &fAlloc);
429 return buffer.isValid();
430 }
431
internalPrepare(SkSpan<const SkGlyphID> glyphIDs,PathDetail pathDetail,const SkGlyph ** results)432 SkSpan<const SkGlyph*> SkStrike::internalPrepare(
433 SkSpan<const SkGlyphID> glyphIDs, PathDetail pathDetail, const SkGlyph** results) {
434 const SkGlyph** cursor = results;
435 for (auto glyphID : glyphIDs) {
436 SkGlyph* glyph = this->glyph(SkPackedGlyphID{glyphID});
437 if (pathDetail == kMetricsAndPath) {
438 this->prepareForPath(glyph);
439 }
440 *cursor++ = glyph;
441 }
442
443 return {results, glyphIDs.size()};
444 }
445
updateMemoryUsage(size_t increase)446 void SkStrike::updateMemoryUsage(size_t increase) {
447 if (increase > 0) {
448 // fRemoved and the cache's total memory are managed under the cache's lock. This allows
449 // them to be accessed under LRU operation.
450 SkAutoMutexExclusive lock{fStrikeCache->fLock};
451 fMemoryUsed += increase;
452 if (!fRemoved) {
453 fStrikeCache->fTotalMemoryUsed += increase;
454 }
455 }
456 }
457