xref: /aosp_15_r20/external/skia/src/core/SkGlyph.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2018 Google LLC
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/SkGlyph.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkData.h"
12 #include "include/core/SkDrawable.h"
13 #include "include/core/SkPicture.h"
14 #include "include/core/SkScalar.h"
15 #include "include/core/SkSerialProcs.h"
16 #include "include/core/SkSpan.h"
17 #include "include/private/base/SkFloatingPoint.h"
18 #include "include/private/base/SkTFitsIn.h"
19 #include "include/private/base/SkTo.h"
20 #include "src/base/SkArenaAlloc.h"
21 #include "src/base/SkBezierCurves.h"
22 #include "src/core/SkReadBuffer.h"
23 #include "src/core/SkScalerContext.h"
24 #include "src/core/SkWriteBuffer.h"
25 #include "src/text/StrikeForGPU.h"
26 
27 #include <cstring>
28 #include <optional>
29 #include <tuple>
30 #include <utility>
31 
32 using namespace skglyph;
33 using namespace sktext;
34 
35 // -- SkPictureBackedGlyphDrawable -----------------------------------------------------------------
36 sk_sp<SkPictureBackedGlyphDrawable>
MakeFromBuffer(SkReadBuffer & buffer)37 SkPictureBackedGlyphDrawable::MakeFromBuffer(SkReadBuffer& buffer) {
38     SkASSERT(buffer.isValid());
39 
40     sk_sp<SkData> pictureData = buffer.readByteArrayAsData();
41 
42     // Return nullptr if invalid or there an empty drawable, which is represented by nullptr.
43     if (!buffer.isValid() || pictureData->size() == 0) {
44         return nullptr;
45     }
46 
47     // Propagate the outer buffer's allow-SkSL setting to the picture decoder, using the flag on
48     // the deserial procs.
49     SkDeserialProcs procs;
50     procs.fAllowSkSL = buffer.allowSkSL();
51     sk_sp<SkPicture> picture = SkPicture::MakeFromData(pictureData.get(), &procs);
52     if (!buffer.validate(picture != nullptr)) {
53         return nullptr;
54     }
55 
56     return sk_make_sp<SkPictureBackedGlyphDrawable>(std::move(picture));
57 }
58 
FlattenDrawable(SkWriteBuffer & buffer,SkDrawable * drawable)59 void SkPictureBackedGlyphDrawable::FlattenDrawable(SkWriteBuffer& buffer, SkDrawable* drawable) {
60     if (drawable == nullptr) {
61         buffer.writeByteArray(nullptr, 0);
62         return;
63     }
64 
65     sk_sp<SkPicture> picture = drawable->makePictureSnapshot();
66     // These drawables should not have SkImages, SkTypefaces or SkPictures inside of them, so
67     // the default SkSerialProcs are sufficient.
68     sk_sp<SkData> data = picture->serialize();
69 
70     // If the picture is too big, or there is no picture, then drop by sending an empty byte array.
71     if (!SkTFitsIn<uint32_t>(data->size()) || data->size() == 0) {
72         buffer.writeByteArray(nullptr, 0);
73         return;
74     }
75 
76     buffer.writeByteArray(data->data(), data->size());
77 }
78 
SkPictureBackedGlyphDrawable(sk_sp<SkPicture> picture)79 SkPictureBackedGlyphDrawable::SkPictureBackedGlyphDrawable(sk_sp<SkPicture> picture)
80         : fPicture(std::move(picture)) {}
81 
onGetBounds()82 SkRect SkPictureBackedGlyphDrawable::onGetBounds() {
83     return fPicture->cullRect();
84 }
85 
onApproximateBytesUsed()86 size_t SkPictureBackedGlyphDrawable::onApproximateBytesUsed() {
87     return sizeof(SkPictureBackedGlyphDrawable) + fPicture->approximateBytesUsed();
88 }
89 
onDraw(SkCanvas * canvas)90 void SkPictureBackedGlyphDrawable::onDraw(SkCanvas* canvas) {
91     canvas->drawPicture(fPicture);
92 }
93 
94 //-- SkGlyph ---------------------------------------------------------------------------------------
MakeFromBuffer(SkReadBuffer & buffer)95 std::optional<SkGlyph> SkGlyph::MakeFromBuffer(SkReadBuffer& buffer) {
96     SkASSERT(buffer.isValid());
97     const SkPackedGlyphID packedID{buffer.readUInt()};
98     const SkVector advance = buffer.readPoint();
99     const uint32_t dimensions = buffer.readUInt();
100     const uint32_t leftTop = buffer.readUInt();
101     const SkMask::Format format = SkTo<SkMask::Format>(buffer.readUInt());
102 
103     if (!buffer.validate(SkMask::IsValidFormat(format))) {
104         return std::nullopt;
105     }
106 
107     SkGlyph glyph{packedID};
108     glyph.fAdvanceX = advance.x();
109     glyph.fAdvanceY = advance.y();
110     glyph.fWidth = dimensions >> 16;
111     glyph.fHeight = dimensions & 0xffffu;
112     glyph.fLeft = leftTop >> 16;
113     glyph.fTop = leftTop & 0xffffu;
114     glyph.fMaskFormat = format;
115     SkDEBUGCODE(glyph.fAdvancesBoundsFormatAndInitialPathDone = true;)
116     return glyph;
117 }
118 
mask() const119 SkMask SkGlyph::mask() const {
120     SkIRect bounds = SkIRect::MakeXYWH(fLeft, fTop, fWidth, fHeight);
121     return SkMask(static_cast<const uint8_t*>(fImage), bounds, this->rowBytes(), fMaskFormat);
122 }
123 
mask(SkPoint position) const124 SkMask SkGlyph::mask(SkPoint position) const {
125     SkASSERT(SkScalarIsInt(position.x()) && SkScalarIsInt(position.y()));
126     SkIRect bounds = SkIRect::MakeXYWH(fLeft, fTop, fWidth, fHeight);
127     bounds.offset(SkScalarFloorToInt(position.x()), SkScalarFloorToInt(position.y()));
128     return SkMask(static_cast<const uint8_t*>(fImage), bounds, this->rowBytes(), fMaskFormat);
129 }
130 
zeroMetrics()131 void SkGlyph::zeroMetrics() {
132     fAdvanceX = 0;
133     fAdvanceY = 0;
134     fWidth    = 0;
135     fHeight   = 0;
136     fTop      = 0;
137     fLeft     = 0;
138 }
139 
bits_to_bytes(size_t bits)140 static size_t bits_to_bytes(size_t bits) {
141     return (bits + 7) >> 3;
142 }
143 
format_alignment(SkMask::Format format)144 static size_t format_alignment(SkMask::Format format) {
145     switch (format) {
146         case SkMask::kBW_Format:
147         case SkMask::kA8_Format:
148         case SkMask::k3D_Format:
149         case SkMask::kSDF_Format:
150             return alignof(uint8_t);
151         case SkMask::kARGB32_Format:
152             return alignof(uint32_t);
153         case SkMask::kLCD16_Format:
154             return alignof(uint16_t);
155         default:
156             SK_ABORT("Unknown mask format.");
157             break;
158     }
159     return 0;
160 }
161 
format_rowbytes(int width,SkMask::Format format)162 static size_t format_rowbytes(int width, SkMask::Format format) {
163     return format == SkMask::kBW_Format ? bits_to_bytes(width)
164                                         : width * format_alignment(format);
165 }
166 
formatAlignment() const167 size_t SkGlyph::formatAlignment() const {
168     return format_alignment(this->maskFormat());
169 }
170 
allocImage(SkArenaAlloc * alloc)171 size_t SkGlyph::allocImage(SkArenaAlloc* alloc) {
172     SkASSERT(!this->isEmpty());
173     auto size = this->imageSize();
174     fImage = alloc->makeBytesAlignedTo(size, this->formatAlignment());
175 
176     return size;
177 }
178 
setImage(SkArenaAlloc * alloc,SkScalerContext * scalerContext)179 bool SkGlyph::setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
180     if (!this->setImageHasBeenCalled()) {
181         // It used to be that getImage() could change the fMaskFormat. Extra checking to make
182         // sure there are no regressions.
183         SkDEBUGCODE(SkMask::Format oldFormat = this->maskFormat());
184         this->allocImage(alloc);
185         scalerContext->getImage(*this);
186         SkASSERT(oldFormat == this->maskFormat());
187         return true;
188     }
189     return false;
190 }
191 
setImage(SkArenaAlloc * alloc,const void * image)192 bool SkGlyph::setImage(SkArenaAlloc* alloc, const void* image) {
193     if (!this->setImageHasBeenCalled()) {
194         this->allocImage(alloc);
195         memcpy(fImage, image, this->imageSize());
196         return true;
197     }
198     return false;
199 }
200 
setMetricsAndImage(SkArenaAlloc * alloc,const SkGlyph & from)201 size_t SkGlyph::setMetricsAndImage(SkArenaAlloc* alloc, const SkGlyph& from) {
202     // Since the code no longer tries to find replacement glyphs, the image should always be
203     // nullptr.
204     SkASSERT(fImage == nullptr || from.fImage == nullptr);
205 
206     // TODO(herb): remove "if" when we are sure there are no colliding glyphs.
207     if (fImage == nullptr) {
208         fAdvanceX = from.fAdvanceX;
209         fAdvanceY = from.fAdvanceY;
210         fWidth = from.fWidth;
211         fHeight = from.fHeight;
212         fTop = from.fTop;
213         fLeft = from.fLeft;
214         fScalerContextBits = from.fScalerContextBits;
215         fMaskFormat = from.fMaskFormat;
216 
217         // From glyph may not have an image because the glyph is too large.
218         if (from.fImage != nullptr && this->setImage(alloc, from.image())) {
219             return this->imageSize();
220         }
221 
222         SkDEBUGCODE(fAdvancesBoundsFormatAndInitialPathDone = from.fAdvancesBoundsFormatAndInitialPathDone;)
223     }
224     return 0;
225 }
226 
rowBytes() const227 size_t SkGlyph::rowBytes() const {
228     return format_rowbytes(fWidth, fMaskFormat);
229 }
230 
rowBytesUsingFormat(SkMask::Format format) const231 size_t SkGlyph::rowBytesUsingFormat(SkMask::Format format) const {
232     return format_rowbytes(fWidth, format);
233 }
234 
imageSize() const235 size_t SkGlyph::imageSize() const {
236     if (this->isEmpty() || this->imageTooLarge()) { return 0; }
237 
238     size_t size = this->rowBytes() * fHeight;
239 
240     if (fMaskFormat == SkMask::k3D_Format) {
241         size *= 3;
242     }
243 
244     return size;
245 }
246 
installPath(SkArenaAlloc * alloc,const SkPath * path,bool hairline,bool modified)247 void SkGlyph::installPath(SkArenaAlloc* alloc, const SkPath* path, bool hairline, bool modified) {
248     SkASSERT(fPathData == nullptr);
249     SkASSERT(!this->setPathHasBeenCalled());
250     fPathData = alloc->make<SkGlyph::PathData>();
251     if (path != nullptr) {
252         fPathData->fPath = *path;
253         fPathData->fPath.updateBoundsCache();
254         fPathData->fPath.getGenerationID();
255         fPathData->fHasPath = true;
256         fPathData->fHairline = hairline;
257         fPathData->fModified = modified;
258     }
259 }
260 
setPath(SkArenaAlloc * alloc,SkScalerContext * scalerContext)261 bool SkGlyph::setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
262     if (!this->setPathHasBeenCalled()) {
263         scalerContext->getPath(*this, alloc);
264         SkASSERT(this->setPathHasBeenCalled());
265         return this->path() != nullptr;
266     }
267 
268     return false;
269 }
270 
setPath(SkArenaAlloc * alloc,const SkPath * path,bool hairline,bool modified)271 bool SkGlyph::setPath(SkArenaAlloc* alloc, const SkPath* path, bool hairline, bool modified) {
272     if (!this->setPathHasBeenCalled()) {
273         this->installPath(alloc, path, hairline, modified);
274         return this->path() != nullptr;
275     }
276     return false;
277 }
278 
path() const279 const SkPath* SkGlyph::path() const {
280     // setPath must have been called previously.
281     SkASSERT(this->setPathHasBeenCalled());
282     if (fPathData->fHasPath) {
283         return &fPathData->fPath;
284     }
285     return nullptr;
286 }
287 
pathIsHairline() const288 bool SkGlyph::pathIsHairline() const {
289     // setPath must have been called previously.
290     SkASSERT(this->setPathHasBeenCalled());
291     return fPathData->fHairline;
292 }
293 
pathIsModified() const294 bool SkGlyph::pathIsModified() const {
295     // setPath must have been called previously.
296     SkASSERT(this->setPathHasBeenCalled());
297     return fPathData->fModified;
298 }
299 
installDrawable(SkArenaAlloc * alloc,sk_sp<SkDrawable> drawable)300 void SkGlyph::installDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable) {
301     SkASSERT(fDrawableData == nullptr);
302     SkASSERT(!this->setDrawableHasBeenCalled());
303     fDrawableData = alloc->make<SkGlyph::DrawableData>();
304     if (drawable != nullptr) {
305         fDrawableData->fDrawable = std::move(drawable);
306         fDrawableData->fDrawable->getGenerationID();
307         fDrawableData->fHasDrawable = true;
308     }
309 }
310 
setDrawable(SkArenaAlloc * alloc,SkScalerContext * scalerContext)311 bool SkGlyph::setDrawable(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
312     if (!this->setDrawableHasBeenCalled()) {
313         sk_sp<SkDrawable> drawable = scalerContext->getDrawable(*this);
314         this->installDrawable(alloc, std::move(drawable));
315         return this->drawable() != nullptr;
316     }
317     return false;
318 }
319 
setDrawable(SkArenaAlloc * alloc,sk_sp<SkDrawable> drawable)320 bool SkGlyph::setDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable) {
321     if (!this->setDrawableHasBeenCalled()) {
322         this->installDrawable(alloc, std::move(drawable));
323         return this->drawable() != nullptr;
324     }
325     return false;
326 }
327 
drawable() const328 SkDrawable* SkGlyph::drawable() const {
329     // setDrawable must have been called previously.
330     SkASSERT(this->setDrawableHasBeenCalled());
331     if (fDrawableData->fHasDrawable) {
332         return fDrawableData->fDrawable.get();
333     }
334     return nullptr;
335 }
336 
flattenMetrics(SkWriteBuffer & buffer) const337 void SkGlyph::flattenMetrics(SkWriteBuffer& buffer) const {
338     buffer.writeUInt(fID.value());
339     buffer.writePoint({fAdvanceX, fAdvanceY});
340     buffer.writeUInt(fWidth << 16 | fHeight);
341     // Note: << has undefined behavior for negative values, so convert everything to the bit
342     // values of uint16_t. Using the cast keeps the signed values fLeft and fTop from sign
343     // extending.
344     const uint32_t left = static_cast<uint16_t>(fLeft);
345     const uint32_t top = static_cast<uint16_t>(fTop);
346     buffer.writeUInt(left << 16 | top);
347     buffer.writeUInt(SkTo<uint32_t>(fMaskFormat));
348 }
349 
flattenImage(SkWriteBuffer & buffer) const350 void SkGlyph::flattenImage(SkWriteBuffer& buffer) const {
351     SkASSERT(this->setImageHasBeenCalled());
352 
353     // If the glyph is empty or too big, then no image data is sent.
354     if (!this->isEmpty() && SkGlyphDigest::FitsInAtlas(*this)) {
355         buffer.writeByteArray(this->image(), this->imageSize());
356     }
357 }
358 
addImageFromBuffer(SkReadBuffer & buffer,SkArenaAlloc * alloc)359 size_t SkGlyph::addImageFromBuffer(SkReadBuffer& buffer, SkArenaAlloc* alloc) {
360     SkASSERT(buffer.isValid());
361 
362     // If the glyph is empty or too big, then no image data is received.
363     if (this->isEmpty() || !SkGlyphDigest::FitsInAtlas(*this)) {
364         return 0;
365     }
366 
367     size_t memoryIncrease = 0;
368 
369     void* imageData = alloc->makeBytesAlignedTo(this->imageSize(), this->formatAlignment());
370     buffer.readByteArray(imageData, this->imageSize());
371     if (buffer.isValid()) {
372         this->installImage(imageData);
373         memoryIncrease += this->imageSize();
374     }
375 
376     return memoryIncrease;
377 }
378 
flattenPath(SkWriteBuffer & buffer) const379 void SkGlyph::flattenPath(SkWriteBuffer& buffer) const {
380     SkASSERT(this->setPathHasBeenCalled());
381 
382     const bool hasPath = this->path() != nullptr;
383     buffer.writeBool(hasPath);
384     if (hasPath) {
385         buffer.writeBool(this->pathIsHairline());
386         buffer.writeBool(this->pathIsModified());
387         buffer.writePath(*this->path());
388     }
389 }
390 
addPathFromBuffer(SkReadBuffer & buffer,SkArenaAlloc * alloc)391 size_t SkGlyph::addPathFromBuffer(SkReadBuffer& buffer, SkArenaAlloc* alloc) {
392     SkASSERT(buffer.isValid());
393 
394     size_t memoryIncrease = 0;
395     const bool hasPath = buffer.readBool();
396     // Check if the buffer is invalid, so as to not make a logical decision on invalid data.
397     if (!buffer.isValid()) {
398         return 0;
399     }
400     if (hasPath) {
401         const bool pathIsHairline = buffer.readBool();
402         const bool pathIsModified = buffer.readBool();
403         SkPath path;
404         buffer.readPath(&path);
405         if (buffer.isValid()) {
406             if (this->setPath(alloc, &path, pathIsHairline, pathIsModified)) {
407                 memoryIncrease += path.approximateBytesUsed();
408             }
409         }
410     } else {
411         this->setPath(alloc, nullptr, false, false);
412     }
413 
414     return memoryIncrease;
415 }
416 
flattenDrawable(SkWriteBuffer & buffer) const417 void SkGlyph::flattenDrawable(SkWriteBuffer& buffer) const {
418     SkASSERT(this->setDrawableHasBeenCalled());
419 
420     if (this->isEmpty() || this->drawable() == nullptr) {
421         SkPictureBackedGlyphDrawable::FlattenDrawable(buffer, nullptr);
422         return;
423     }
424 
425     SkPictureBackedGlyphDrawable::FlattenDrawable(buffer, this->drawable());
426 }
427 
addDrawableFromBuffer(SkReadBuffer & buffer,SkArenaAlloc * alloc)428 size_t SkGlyph::addDrawableFromBuffer(SkReadBuffer& buffer, SkArenaAlloc* alloc) {
429     SkASSERT(buffer.isValid());
430 
431     sk_sp<SkDrawable> drawable = SkPictureBackedGlyphDrawable::MakeFromBuffer(buffer);
432     if (!buffer.isValid()) {
433         return 0;
434     }
435 
436     if (this->setDrawable(alloc, std::move(drawable))) {
437         return this->drawable()->approximateBytesUsed();
438     }
439 
440     return 0;
441 }
442 
calculate_path_gap(SkScalar topOffset,SkScalar bottomOffset,const SkPath & path)443 static std::tuple<SkScalar, SkScalar> calculate_path_gap(
444         SkScalar topOffset, SkScalar bottomOffset, const SkPath& path) {
445 
446     // Left and Right of an ever expanding gap around the path.
447     SkScalar left  = SK_ScalarMax,
448              right = SK_ScalarMin;
449 
450     auto expandGap = [&left, &right](SkScalar v) {
451         left  = std::min(left, v);
452         right = std::max(right, v);
453     };
454 
455     // Handle all the different verbs for the path.
456     SkPoint pts[4];
457     auto addLine = [&](SkScalar offset) {
458         SkScalar t = sk_ieee_float_divide(offset - pts[0].fY, pts[1].fY - pts[0].fY);
459         if (0 <= t && t < 1) {   // this handles divide by zero above
460             expandGap(pts[0].fX + t * (pts[1].fX - pts[0].fX));
461         }
462     };
463 
464     auto addQuad = [&](SkScalar offset) {
465         SkScalar intersectionStorage[2];
466         auto intersections = SkBezierQuad::IntersectWithHorizontalLine(
467                 SkSpan(pts, 3), offset, intersectionStorage);
468         for (SkScalar x : intersections) {
469             expandGap(x);
470         }
471     };
472 
473     auto addCubic = [&](SkScalar offset) {
474         float intersectionStorage[3];
475         auto intersections = SkBezierCubic::IntersectWithHorizontalLine(
476                 SkSpan{pts, 4}, offset, intersectionStorage);
477 
478         for(double intersection : intersections) {
479             expandGap(intersection);
480         }
481     };
482 
483     // Handle when a verb's points are in the gap between top and bottom.
484     auto addPts = [&expandGap, &pts, topOffset, bottomOffset](int ptCount) {
485         for (int i = 0; i < ptCount; ++i) {
486             if (topOffset < pts[i].fY && pts[i].fY < bottomOffset) {
487                 expandGap(pts[i].fX);
488             }
489         }
490     };
491 
492     SkPath::Iter iter(path, false);
493     SkPath::Verb verb;
494     while (SkPath::kDone_Verb != (verb = iter.next(pts))) {
495         switch (verb) {
496             case SkPath::kMove_Verb: {
497                 break;
498             }
499             case SkPath::kLine_Verb: {
500                 auto [lineTop, lineBottom] = std::minmax({pts[0].fY, pts[1].fY});
501 
502                 // The y-coordinates of the points intersect the top and bottom offsets.
503                 if (topOffset <= lineBottom && lineTop <= bottomOffset) {
504                     addLine(topOffset);
505                     addLine(bottomOffset);
506                     addPts(2);
507                 }
508                 break;
509             }
510             case SkPath::kQuad_Verb: {
511                 auto [quadTop, quadBottom] = std::minmax({pts[0].fY, pts[1].fY, pts[2].fY});
512 
513                 // The y-coordinates of the points intersect the top and bottom offsets.
514                 if (topOffset <= quadBottom && quadTop <= bottomOffset) {
515                     addQuad(topOffset);
516                     addQuad(bottomOffset);
517                     addPts(3);
518                 }
519                 break;
520             }
521             case SkPath::kConic_Verb: {
522                 SkDEBUGFAIL("There should be no conic primitives in glyph outlines.");
523                 break;
524             }
525             case SkPath::kCubic_Verb: {
526                 auto [cubicTop, cubicBottom] =
527                         std::minmax({pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY});
528 
529                 // The y-coordinates of the points intersect the top and bottom offsets.
530                 if (topOffset <= cubicBottom && cubicTop <= bottomOffset) {
531                     addCubic(topOffset);
532                     addCubic(bottomOffset);
533                     addPts(4);
534                 }
535                 break;
536             }
537             case SkPath::kClose_Verb: {
538                 break;
539             }
540             default: {
541                 SkDEBUGFAIL("Unknown path verb generating glyph underline.");
542                 break;
543             }
544         }
545     }
546 
547     return std::tie(left, right);
548 }
549 
ensureIntercepts(const SkScalar * bounds,SkScalar scale,SkScalar xPos,SkScalar * array,int * count,SkArenaAlloc * alloc)550 void SkGlyph::ensureIntercepts(const SkScalar* bounds, SkScalar scale, SkScalar xPos,
551                                SkScalar* array, int* count, SkArenaAlloc* alloc) {
552 
553     auto offsetResults = [scale, xPos](
554             const SkGlyph::Intercept* intercept,SkScalar* array, int* count) {
555         if (array) {
556             array += *count;
557             for (int index = 0; index < 2; index++) {
558                 *array++ = intercept->fInterval[index] * scale + xPos;
559             }
560         }
561         *count += 2;
562     };
563 
564     const SkGlyph::Intercept* match =
565             [this](const SkScalar bounds[2]) -> const SkGlyph::Intercept* {
566                 if (fPathData == nullptr) {
567                     return nullptr;
568                 }
569                 const SkGlyph::Intercept* intercept = fPathData->fIntercept;
570                 while (intercept != nullptr) {
571                     if (bounds[0] == intercept->fBounds[0] && bounds[1] == intercept->fBounds[1]) {
572                         return intercept;
573                     }
574                     intercept = intercept->fNext;
575                 }
576                 return nullptr;
577             }(bounds);
578 
579     if (match != nullptr) {
580         if (match->fInterval[0] < match->fInterval[1]) {
581             offsetResults(match, array, count);
582         }
583         return;
584     }
585 
586     SkGlyph::Intercept* intercept = alloc->make<SkGlyph::Intercept>();
587     intercept->fNext = fPathData->fIntercept;
588     intercept->fBounds[0] = bounds[0];
589     intercept->fBounds[1] = bounds[1];
590     intercept->fInterval[0] = SK_ScalarMax;
591     intercept->fInterval[1] = SK_ScalarMin;
592     fPathData->fIntercept = intercept;
593     const SkPath* path = &(fPathData->fPath);
594     const SkRect& pathBounds = path->getBounds();
595     if (pathBounds.fBottom < bounds[0] || bounds[1] < pathBounds.fTop) {
596         return;
597     }
598 
599     std::tie(intercept->fInterval[0], intercept->fInterval[1])
600             = calculate_path_gap(bounds[0], bounds[1], *path);
601 
602     if (intercept->fInterval[0] >= intercept->fInterval[1]) {
603         intercept->fInterval[0] = SK_ScalarMax;
604         intercept->fInterval[1] = SK_ScalarMin;
605         return;
606     }
607     offsetResults(intercept, array, count);
608 }
609 
610 namespace {
init_actions(const SkGlyph & glyph)611 uint32_t init_actions(const SkGlyph& glyph) {
612     constexpr uint32_t kAllUnset = 0;
613     constexpr uint32_t kDrop = SkTo<uint32_t>(GlyphAction::kDrop);
614     constexpr uint32_t kAllDrop =
615             kDrop << kDirectMask |
616             kDrop << kDirectMaskCPU |
617             kDrop << kMask |
618             kDrop << kSDFT |
619             kDrop << kPath |
620             kDrop << kDrawable;
621     return glyph.isEmpty() ? kAllDrop : kAllUnset;
622 }
623 }  // namespace
624 
625 // -- SkGlyphDigest --------------------------------------------------------------------------------
SkGlyphDigest(size_t index,const SkGlyph & glyph)626 SkGlyphDigest::SkGlyphDigest(size_t index, const SkGlyph& glyph)
627         : fPackedID{SkTo<uint64_t>(glyph.getPackedID().value())}
628         , fIndex{SkTo<uint64_t>(index)}
629         , fIsEmpty(glyph.isEmpty())
630         , fFormat(glyph.maskFormat())
631         , fActions{init_actions(glyph)}
632         , fLeft{SkTo<int16_t>(glyph.left())}
633         , fTop{SkTo<int16_t>(glyph.top())}
634         , fWidth{SkTo<uint16_t>(glyph.width())}
635         , fHeight{SkTo<uint16_t>(glyph.height())} {}
636 
setActionFor(skglyph::ActionType actionType,SkGlyph * glyph,StrikeForGPU * strike)637 void SkGlyphDigest::setActionFor(skglyph::ActionType actionType,
638                                  SkGlyph* glyph,
639                                  StrikeForGPU* strike) {
640     // We don't have to do any more if the glyph is marked as kDrop because it was isEmpty().
641     if (this->actionFor(actionType) == GlyphAction::kUnset) {
642         GlyphAction action = GlyphAction::kReject;
643         switch (actionType) {
644             case kDirectMask: {
645                 if (this->fitsInAtlasDirect()) {
646                     action = GlyphAction::kAccept;
647                 }
648                 break;
649             }
650             case kDirectMaskCPU: {
651                 if (strike->prepareForImage(glyph)) {
652                     SkASSERT(!glyph->isEmpty());
653                     action = GlyphAction::kAccept;
654                 }
655                 break;
656             }
657             case kMask: {
658                 if (this->fitsInAtlasInterpolated()) {
659                     action = GlyphAction::kAccept;
660                 }
661                 break;
662             }
663             case kSDFT: {
664                 if (this->fitsInAtlasDirect() &&
665                     this->maskFormat() == SkMask::Format::kSDF_Format) {
666                     action = GlyphAction::kAccept;
667                 }
668                 break;
669             }
670             case kPath: {
671                 if (strike->prepareForPath(glyph)) {
672                     action = GlyphAction::kAccept;
673                 }
674                 break;
675             }
676             case kDrawable: {
677                 if (strike->prepareForDrawable(glyph)) {
678                     action = GlyphAction::kAccept;
679                 }
680                 break;
681             }
682         }
683         this->setAction(actionType, action);
684     }
685 }
686 
FitsInAtlas(const SkGlyph & glyph)687 bool SkGlyphDigest::FitsInAtlas(const SkGlyph& glyph) {
688     return glyph.maxDimension() <= kSkSideTooBigForAtlas;
689 }
690 
691 // -- SkGlyphPositionRoundingSpec ------------------------------------------------------------------
HalfAxisSampleFreq(bool isSubpixel,SkAxisAlignment axisAlignment)692 SkVector SkGlyphPositionRoundingSpec::HalfAxisSampleFreq(
693         bool isSubpixel, SkAxisAlignment axisAlignment) {
694     if (!isSubpixel) {
695         return {SK_ScalarHalf, SK_ScalarHalf};
696     } else {
697         switch (axisAlignment) {
698             case SkAxisAlignment::kX:
699                 return {SkPackedGlyphID::kSubpixelRound, SK_ScalarHalf};
700             case SkAxisAlignment::kY:
701                 return {SK_ScalarHalf, SkPackedGlyphID::kSubpixelRound};
702             case SkAxisAlignment::kNone:
703                 return {SkPackedGlyphID::kSubpixelRound, SkPackedGlyphID::kSubpixelRound};
704         }
705     }
706 
707     // Some compilers need this.
708     return {0, 0};
709 }
710 
IgnorePositionMask(bool isSubpixel,SkAxisAlignment axisAlignment)711 SkIPoint SkGlyphPositionRoundingSpec::IgnorePositionMask(
712         bool isSubpixel, SkAxisAlignment axisAlignment) {
713     return SkIPoint::Make((!isSubpixel || axisAlignment == SkAxisAlignment::kY) ? 0 : ~0,
714                           (!isSubpixel || axisAlignment == SkAxisAlignment::kX) ? 0 : ~0);
715 }
716 
IgnorePositionFieldMask(bool isSubpixel,SkAxisAlignment axisAlignment)717 SkIPoint SkGlyphPositionRoundingSpec::IgnorePositionFieldMask(bool isSubpixel,
718                                                               SkAxisAlignment axisAlignment) {
719     SkIPoint ignoreMask = IgnorePositionMask(isSubpixel, axisAlignment);
720     SkIPoint answer{ignoreMask.x() & SkPackedGlyphID::kXYFieldMask.x(),
721                     ignoreMask.y() & SkPackedGlyphID::kXYFieldMask.y()};
722     return answer;
723 }
724 
SkGlyphPositionRoundingSpec(bool isSubpixel,SkAxisAlignment axisAlignment)725 SkGlyphPositionRoundingSpec::SkGlyphPositionRoundingSpec(
726         bool isSubpixel, SkAxisAlignment axisAlignment)
727     : halfAxisSampleFreq{HalfAxisSampleFreq(isSubpixel, axisAlignment)}
728     , ignorePositionMask{IgnorePositionMask(isSubpixel, axisAlignment)}
729     , ignorePositionFieldMask {IgnorePositionFieldMask(isSubpixel, axisAlignment)} {}
730