Flutter Engine
The Flutter Engine
SkGlyph.cpp
Go to the documentation of this file.
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
11#include "include/core/SkData.h"
16#include "include/core/SkSpan.h"
26
27#include <cstring>
28#include <optional>
29#include <tuple>
30#include <utility>
31
32using namespace skglyph;
33using namespace sktext;
34
35// -- SkPictureBackedGlyphDrawable -----------------------------------------------------------------
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
60 if (drawable == nullptr) {
61 buffer.writeByteArray(nullptr, 0);
62 return;
63 }
64
66 // These drawables should not have SkImages, SkTypefaces or SkPictures inside of them, so
67 // the default SkSerialProcs are sufficient.
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
80 : fPicture(std::move(picture)) {}
81
82SkRect SkPictureBackedGlyphDrawable::onGetBounds() {
83 return fPicture->cullRect();
84}
85
86size_t SkPictureBackedGlyphDrawable::onApproximateBytesUsed() {
87 return sizeof(SkPictureBackedGlyphDrawable) + fPicture->approximateBytesUsed();
88}
89
90void SkPictureBackedGlyphDrawable::onDraw(SkCanvas* canvas) {
91 canvas->drawPicture(fPicture);
92}
93
94//-- SkGlyph ---------------------------------------------------------------------------------------
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
119SkGlyph::SkGlyph(const SkGlyph&) = default;
120SkGlyph& SkGlyph::operator=(const SkGlyph&) = default;
121SkGlyph::SkGlyph(SkGlyph&&) = default;
123SkGlyph::~SkGlyph() = default;
124
126 SkIRect bounds = SkIRect::MakeXYWH(fLeft, fTop, fWidth, fHeight);
127 return SkMask(static_cast<const uint8_t*>(fImage), bounds, this->rowBytes(), fMaskFormat);
128}
129
130SkMask SkGlyph::mask(SkPoint position) const {
131 SkASSERT(SkScalarIsInt(position.x()) && SkScalarIsInt(position.y()));
132 SkIRect bounds = SkIRect::MakeXYWH(fLeft, fTop, fWidth, fHeight);
133 bounds.offset(SkScalarFloorToInt(position.x()), SkScalarFloorToInt(position.y()));
134 return SkMask(static_cast<const uint8_t*>(fImage), bounds, this->rowBytes(), fMaskFormat);
135}
136
138 fAdvanceX = 0;
139 fAdvanceY = 0;
140 fWidth = 0;
141 fHeight = 0;
142 fTop = 0;
143 fLeft = 0;
144}
145
146static size_t bits_to_bytes(size_t bits) {
147 return (bits + 7) >> 3;
148}
149
151 switch (format) {
156 return alignof(uint8_t);
158 return alignof(uint32_t);
160 return alignof(uint16_t);
161 default:
162 SK_ABORT("Unknown mask format.");
163 break;
164 }
165 return 0;
166}
167
171}
172
174 return format_alignment(this->maskFormat());
175}
176
177size_t SkGlyph::allocImage(SkArenaAlloc* alloc) {
178 SkASSERT(!this->isEmpty());
179 auto size = this->imageSize();
180 fImage = alloc->makeBytesAlignedTo(size, this->formatAlignment());
181
182 return size;
183}
184
185bool SkGlyph::setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
186 if (!this->setImageHasBeenCalled()) {
187 // It used to be that getImage() could change the fMaskFormat. Extra checking to make
188 // sure there are no regressions.
189 SkDEBUGCODE(SkMask::Format oldFormat = this->maskFormat());
190 this->allocImage(alloc);
191 scalerContext->getImage(*this);
192 SkASSERT(oldFormat == this->maskFormat());
193 return true;
194 }
195 return false;
196}
197
198bool SkGlyph::setImage(SkArenaAlloc* alloc, const void* image) {
199 if (!this->setImageHasBeenCalled()) {
200 this->allocImage(alloc);
201 memcpy(fImage, image, this->imageSize());
202 return true;
203 }
204 return false;
205}
206
208 // Since the code no longer tries to find replacement glyphs, the image should always be
209 // nullptr.
210 SkASSERT(fImage == nullptr || from.fImage == nullptr);
211
212 // TODO(herb): remove "if" when we are sure there are no colliding glyphs.
213 if (fImage == nullptr) {
214 fAdvanceX = from.fAdvanceX;
215 fAdvanceY = from.fAdvanceY;
216 fWidth = from.fWidth;
217 fHeight = from.fHeight;
218 fTop = from.fTop;
219 fLeft = from.fLeft;
220 fScalerContextBits = from.fScalerContextBits;
221 fMaskFormat = from.fMaskFormat;
222
223 // From glyph may not have an image because the glyph is too large.
224 if (from.fImage != nullptr && this->setImage(alloc, from.image())) {
225 return this->imageSize();
226 }
227
228 SkDEBUGCODE(fAdvancesBoundsFormatAndInitialPathDone = from.fAdvancesBoundsFormatAndInitialPathDone;)
229 }
230 return 0;
231}
232
233size_t SkGlyph::rowBytes() const {
234 return format_rowbytes(fWidth, fMaskFormat);
235}
236
238 return format_rowbytes(fWidth, format);
239}
240
241size_t SkGlyph::imageSize() const {
242 if (this->isEmpty() || this->imageTooLarge()) { return 0; }
243
244 size_t size = this->rowBytes() * fHeight;
245
246 if (fMaskFormat == SkMask::k3D_Format) {
247 size *= 3;
248 }
249
250 return size;
251}
252
253void SkGlyph::installPath(SkArenaAlloc* alloc, const SkPath* path, bool hairline) {
254 SkASSERT(fPathData == nullptr);
256 fPathData = alloc->make<SkGlyph::PathData>();
257 if (path != nullptr) {
258 fPathData->fPath = *path;
259 fPathData->fPath.updateBoundsCache();
260 fPathData->fPath.getGenerationID();
261 fPathData->fHasPath = true;
262 fPathData->fHairline = hairline;
263 }
264}
265
266bool SkGlyph::setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
267 if (!this->setPathHasBeenCalled()) {
268 scalerContext->getPath(*this, alloc);
270 return this->path() != nullptr;
271 }
272
273 return false;
274}
275
276bool SkGlyph::setPath(SkArenaAlloc* alloc, const SkPath* path, bool hairline) {
277 if (!this->setPathHasBeenCalled()) {
278 this->installPath(alloc, path, hairline);
279 return this->path() != nullptr;
280 }
281 return false;
282}
283
284const SkPath* SkGlyph::path() const {
285 // setPath must have been called previously.
287 if (fPathData->fHasPath) {
288 return &fPathData->fPath;
289 }
290 return nullptr;
291}
292
294 // setPath must have been called previously.
296 return fPathData->fHairline;
297}
298
299void SkGlyph::installDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable) {
300 SkASSERT(fDrawableData == nullptr);
302 fDrawableData = alloc->make<SkGlyph::DrawableData>();
303 if (drawable != nullptr) {
304 fDrawableData->fDrawable = std::move(drawable);
305 fDrawableData->fDrawable->getGenerationID();
306 fDrawableData->fHasDrawable = true;
307 }
308}
309
311 if (!this->setDrawableHasBeenCalled()) {
312 sk_sp<SkDrawable> drawable = scalerContext->getDrawable(*this);
313 this->installDrawable(alloc, std::move(drawable));
314 return this->drawable() != nullptr;
315 }
316 return false;
317}
318
320 if (!this->setDrawableHasBeenCalled()) {
321 this->installDrawable(alloc, std::move(drawable));
322 return this->drawable() != nullptr;
323 }
324 return false;
325}
326
328 // setDrawable must have been called previously.
330 if (fDrawableData->fHasDrawable) {
331 return fDrawableData->fDrawable.get();
332 }
333 return nullptr;
334}
335
337 buffer.writeUInt(fID.value());
338 buffer.writePoint({fAdvanceX, fAdvanceY});
339 buffer.writeUInt(fWidth << 16 | fHeight);
340 // Note: << has undefined behavior for negative values, so convert everything to the bit
341 // values of uint16_t. Using the cast keeps the signed values fLeft and fTop from sign
342 // extending.
343 const uint32_t left = static_cast<uint16_t>(fLeft);
344 const uint32_t top = static_cast<uint16_t>(fTop);
345 buffer.writeUInt(left << 16 | top);
346 buffer.writeUInt(SkTo<uint32_t>(fMaskFormat));
347}
348
351
352 // If the glyph is empty or too big, then no image data is sent.
353 if (!this->isEmpty() && SkGlyphDigest::FitsInAtlas(*this)) {
354 buffer.writeByteArray(this->image(), this->imageSize());
355 }
356}
357
359 SkASSERT(buffer.isValid());
360
361 // If the glyph is empty or too big, then no image data is received.
362 if (this->isEmpty() || !SkGlyphDigest::FitsInAtlas(*this)) {
363 return 0;
364 }
365
366 size_t memoryIncrease = 0;
367
368 void* imageData = alloc->makeBytesAlignedTo(this->imageSize(), this->formatAlignment());
369 buffer.readByteArray(imageData, this->imageSize());
370 if (buffer.isValid()) {
371 this->installImage(imageData);
372 memoryIncrease += this->imageSize();
373 }
374
375 return memoryIncrease;
376}
377
380
381 const bool hasPath = this->path() != nullptr;
382 buffer.writeBool(hasPath);
383 if (hasPath) {
384 buffer.writeBool(this->pathIsHairline());
385 buffer.writePath(*this->path());
386 }
387}
388
390 SkASSERT(buffer.isValid());
391
392 size_t memoryIncrease = 0;
393 const bool hasPath = buffer.readBool();
394 // Check if the buffer is invalid, so as to not make a logical decision on invalid data.
395 if (!buffer.isValid()) {
396 return 0;
397 }
398 if (hasPath) {
399 const bool pathIsHairline = buffer.readBool();
400 SkPath path;
401 buffer.readPath(&path);
402 if (buffer.isValid()) {
403 if (this->setPath(alloc, &path, pathIsHairline)) {
404 memoryIncrease += path.approximateBytesUsed();
405 }
406 }
407 } else {
408 this->setPath(alloc, nullptr, false);
409 }
410
411 return memoryIncrease;
412}
413
416
417 if (this->isEmpty() || this->drawable() == nullptr) {
419 return;
420 }
421
423}
424
426 SkASSERT(buffer.isValid());
427
429 if (!buffer.isValid()) {
430 return 0;
431 }
432
433 if (this->setDrawable(alloc, std::move(drawable))) {
434 return this->drawable()->approximateBytesUsed();
435 }
436
437 return 0;
438}
439
440static std::tuple<SkScalar, SkScalar> calculate_path_gap(
441 SkScalar topOffset, SkScalar bottomOffset, const SkPath& path) {
442
443 // Left and Right of an ever expanding gap around the path.
446
447 auto expandGap = [&left, &right](SkScalar v) {
448 left = std::min(left, v);
449 right = std::max(right, v);
450 };
451
452 // Handle all the different verbs for the path.
453 SkPoint pts[4];
454 auto addLine = [&](SkScalar offset) {
455 SkScalar t = sk_ieee_float_divide(offset - pts[0].fY, pts[1].fY - pts[0].fY);
456 if (0 <= t && t < 1) { // this handles divide by zero above
457 expandGap(pts[0].fX + t * (pts[1].fX - pts[0].fX));
458 }
459 };
460
461 auto addQuad = [&](SkScalar offset) {
462 SkScalar intersectionStorage[2];
464 SkSpan(pts, 3), offset, intersectionStorage);
465 for (SkScalar x : intersections) {
466 expandGap(x);
467 }
468 };
469
470 auto addCubic = [&](SkScalar offset) {
471 float intersectionStorage[3];
473 SkSpan{pts, 4}, offset, intersectionStorage);
474
475 for(double intersection : intersections) {
476 expandGap(intersection);
477 }
478 };
479
480 // Handle when a verb's points are in the gap between top and bottom.
481 auto addPts = [&expandGap, &pts, topOffset, bottomOffset](int ptCount) {
482 for (int i = 0; i < ptCount; ++i) {
483 if (topOffset < pts[i].fY && pts[i].fY < bottomOffset) {
484 expandGap(pts[i].fX);
485 }
486 }
487 };
488
489 SkPath::Iter iter(path, false);
490 SkPath::Verb verb;
491 while (SkPath::kDone_Verb != (verb = iter.next(pts))) {
492 switch (verb) {
493 case SkPath::kMove_Verb: {
494 break;
495 }
496 case SkPath::kLine_Verb: {
497 auto [lineTop, lineBottom] = std::minmax({pts[0].fY, pts[1].fY});
498
499 // The y-coordinates of the points intersect the top and bottom offsets.
500 if (topOffset <= lineBottom && lineTop <= bottomOffset) {
501 addLine(topOffset);
502 addLine(bottomOffset);
503 addPts(2);
504 }
505 break;
506 }
507 case SkPath::kQuad_Verb: {
508 auto [quadTop, quadBottom] = std::minmax({pts[0].fY, pts[1].fY, pts[2].fY});
509
510 // The y-coordinates of the points intersect the top and bottom offsets.
511 if (topOffset <= quadBottom && quadTop <= bottomOffset) {
512 addQuad(topOffset);
513 addQuad(bottomOffset);
514 addPts(3);
515 }
516 break;
517 }
518 case SkPath::kConic_Verb: {
519 SkDEBUGFAIL("There should be no conic primitives in glyph outlines.");
520 break;
521 }
522 case SkPath::kCubic_Verb: {
523 auto [cubicTop, cubicBottom] =
524 std::minmax({pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY});
525
526 // The y-coordinates of the points intersect the top and bottom offsets.
527 if (topOffset <= cubicBottom && cubicTop <= bottomOffset) {
528 addCubic(topOffset);
529 addCubic(bottomOffset);
530 addPts(4);
531 }
532 break;
533 }
534 case SkPath::kClose_Verb: {
535 break;
536 }
537 default: {
538 SkDEBUGFAIL("Unknown path verb generating glyph underline.");
539 break;
540 }
541 }
542 }
543
544 return std::tie(left, right);
545}
546
548 SkScalar* array, int* count, SkArenaAlloc* alloc) {
549
550 auto offsetResults = [scale, xPos](
551 const SkGlyph::Intercept* intercept,SkScalar* array, int* count) {
552 if (array) {
553 array += *count;
554 for (int index = 0; index < 2; index++) {
555 *array++ = intercept->fInterval[index] * scale + xPos;
556 }
557 }
558 *count += 2;
559 };
560
561 const SkGlyph::Intercept* match =
562 [this](const SkScalar bounds[2]) -> const SkGlyph::Intercept* {
563 if (fPathData == nullptr) {
564 return nullptr;
565 }
566 const SkGlyph::Intercept* intercept = fPathData->fIntercept;
567 while (intercept != nullptr) {
568 if (bounds[0] == intercept->fBounds[0] && bounds[1] == intercept->fBounds[1]) {
569 return intercept;
570 }
571 intercept = intercept->fNext;
572 }
573 return nullptr;
574 }(bounds);
575
576 if (match != nullptr) {
577 if (match->fInterval[0] < match->fInterval[1]) {
578 offsetResults(match, array, count);
579 }
580 return;
581 }
582
583 SkGlyph::Intercept* intercept = alloc->make<SkGlyph::Intercept>();
584 intercept->fNext = fPathData->fIntercept;
585 intercept->fBounds[0] = bounds[0];
586 intercept->fBounds[1] = bounds[1];
587 intercept->fInterval[0] = SK_ScalarMax;
588 intercept->fInterval[1] = SK_ScalarMin;
589 fPathData->fIntercept = intercept;
590 const SkPath* path = &(fPathData->fPath);
591 const SkRect& pathBounds = path->getBounds();
592 if (pathBounds.fBottom < bounds[0] || bounds[1] < pathBounds.fTop) {
593 return;
594 }
595
596 std::tie(intercept->fInterval[0], intercept->fInterval[1])
598
599 if (intercept->fInterval[0] >= intercept->fInterval[1]) {
600 intercept->fInterval[0] = SK_ScalarMax;
601 intercept->fInterval[1] = SK_ScalarMin;
602 return;
603 }
604 offsetResults(intercept, array, count);
605}
606
607namespace {
608uint32_t init_actions(const SkGlyph& glyph) {
609 constexpr uint32_t kAllUnset = 0;
610 constexpr uint32_t kDrop = SkTo<uint32_t>(GlyphAction::kDrop);
611 constexpr uint32_t kAllDrop =
612 kDrop << kDirectMask |
614 kDrop << kMask |
615 kDrop << kSDFT |
616 kDrop << kPath |
617 kDrop << kDrawable;
618 return glyph.isEmpty() ? kAllDrop : kAllUnset;
619}
620} // namespace
621
622// -- SkGlyphDigest --------------------------------------------------------------------------------
623SkGlyphDigest::SkGlyphDigest(size_t index, const SkGlyph& glyph)
624 : fPackedID{SkTo<uint64_t>(glyph.getPackedID().value())}
625 , fIndex{SkTo<uint64_t>(index)}
626 , fIsEmpty(glyph.isEmpty())
627 , fFormat(glyph.maskFormat())
628 , fActions{init_actions(glyph)}
629 , fLeft{SkTo<int16_t>(glyph.left())}
630 , fTop{SkTo<int16_t>(glyph.top())}
631 , fWidth{SkTo<uint16_t>(glyph.width())}
632 , fHeight{SkTo<uint16_t>(glyph.height())} {}
633
635 SkGlyph* glyph,
636 StrikeForGPU* strike) {
637 // We don't have to do any more if the glyph is marked as kDrop because it was isEmpty().
638 if (this->actionFor(actionType) == GlyphAction::kUnset) {
639 GlyphAction action = GlyphAction::kReject;
640 switch (actionType) {
641 case kDirectMask: {
642 if (this->fitsInAtlasDirect()) {
643 action = GlyphAction::kAccept;
644 }
645 break;
646 }
647 case kDirectMaskCPU: {
648 if (strike->prepareForImage(glyph)) {
649 SkASSERT(!glyph->isEmpty());
650 action = GlyphAction::kAccept;
651 }
652 break;
653 }
654 case kMask: {
655 if (this->fitsInAtlasInterpolated()) {
656 action = GlyphAction::kAccept;
657 }
658 break;
659 }
660 case kSDFT: {
661 if (this->fitsInAtlasDirect() &&
662 this->maskFormat() == SkMask::Format::kSDF_Format) {
663 action = GlyphAction::kAccept;
664 }
665 break;
666 }
667 case kPath: {
668 if (strike->prepareForPath(glyph)) {
669 action = GlyphAction::kAccept;
670 }
671 break;
672 }
673 case kDrawable: {
674 if (strike->prepareForDrawable(glyph)) {
675 action = GlyphAction::kAccept;
676 }
677 break;
678 }
679 }
680 this->setAction(actionType, action);
681 }
682}
683
685 return glyph.maxDimension() <= kSkSideTooBigForAtlas;
686}
687
688// -- SkGlyphPositionRoundingSpec ------------------------------------------------------------------
689SkVector SkGlyphPositionRoundingSpec::HalfAxisSampleFreq(
690 bool isSubpixel, SkAxisAlignment axisAlignment) {
691 if (!isSubpixel) {
693 } else {
694 switch (axisAlignment) {
701 }
702 }
703
704 // Some compilers need this.
705 return {0, 0};
706}
707
708SkIPoint SkGlyphPositionRoundingSpec::IgnorePositionMask(
709 bool isSubpixel, SkAxisAlignment axisAlignment) {
710 return SkIPoint::Make((!isSubpixel || axisAlignment == SkAxisAlignment::kY) ? 0 : ~0,
711 (!isSubpixel || axisAlignment == SkAxisAlignment::kX) ? 0 : ~0);
712}
713
714SkIPoint SkGlyphPositionRoundingSpec::IgnorePositionFieldMask(bool isSubpixel,
715 SkAxisAlignment axisAlignment) {
716 SkIPoint ignoreMask = IgnorePositionMask(isSubpixel, axisAlignment);
717 SkIPoint answer{ignoreMask.x() & SkPackedGlyphID::kXYFieldMask.x(),
718 ignoreMask.y() & SkPackedGlyphID::kXYFieldMask.y()};
719 return answer;
720}
721
723 bool isSubpixel, SkAxisAlignment axisAlignment)
724 : halfAxisSampleFreq{HalfAxisSampleFreq(isSubpixel, axisAlignment)}
725 , ignorePositionMask{IgnorePositionMask(isSubpixel, axisAlignment)}
726 , ignorePositionFieldMask {IgnorePositionFieldMask(isSubpixel, axisAlignment)} {}
int count
Definition: FontMgrTest.cpp:50
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kDrawable
static constexpr float sk_ieee_float_divide(float numer, float denom)
static size_t format_alignment(SkMask::Format format)
Definition: SkGlyph.cpp:150
static size_t format_rowbytes(int width, SkMask::Format format)
Definition: SkGlyph.cpp:168
static size_t bits_to_bytes(size_t bits)
Definition: SkGlyph.cpp:146
static std::tuple< SkScalar, SkScalar > calculate_path_gap(SkScalar topOffset, SkScalar bottomOffset, const SkPath &path)
Definition: SkGlyph.cpp:440
SkAxisAlignment
Definition: SkGlyph.h:218
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
#define SK_ScalarMin
Definition: SkScalar.h:25
#define SK_ScalarMax
Definition: SkScalar.h:24
#define SK_ScalarHalf
Definition: SkScalar.h:19
static bool SkScalarIsInt(SkScalar x)
Definition: SkScalar.h:80
#define SkScalarFloorToInt(x)
Definition: SkScalar.h:35
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
constexpr D SkTo(S s)
Definition: SkTo.h:16
void * makeBytesAlignedTo(size_t size, size_t align)
Definition: SkArenaAlloc.h:200
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
static SkSpan< const float > IntersectWithHorizontalLine(SkSpan< const SkPoint > controlPoints, float yIntercept, float intersectionStorage[3])
static SkSpan< const float > IntersectWithHorizontalLine(SkSpan< const SkPoint > controlPoints, float yIntercept, float intersectionStorage[2])
void drawPicture(const SkPicture *picture)
Definition: SkCanvas.h:1961
size_t size() const
Definition: SkData.h:30
size_t approximateBytesUsed()
Definition: SkDrawable.cpp:75
sk_sp< SkPicture > makePictureSnapshot()
Definition: SkDrawable.cpp:60
SkMask::Format maskFormat() const
Definition: SkGlyph.h:341
SkGlyphDigest()=default
static bool FitsInAtlas(const SkGlyph &glyph)
Definition: SkGlyph.cpp:684
static constexpr uint16_t kSkSideTooBigForAtlas
Definition: SkGlyph.h:333
bool fitsInAtlasInterpolated() const
Definition: SkGlyph.h:357
void setActionFor(skglyph::ActionType, SkGlyph *, sktext::StrikeForGPU *)
Definition: SkGlyph.cpp:634
bool fitsInAtlasDirect() const
Definition: SkGlyph.h:353
skglyph::GlyphAction actionFor(skglyph::ActionType actionType) const
Definition: SkGlyph.h:343
int top() const
Definition: SkGlyph.h:511
bool setPathHasBeenCalled() const
Definition: SkGlyph.h:486
void zeroMetrics()
Definition: SkGlyph.cpp:137
size_t rowBytes() const
Definition: SkGlyph.cpp:233
bool isEmpty() const
Definition: SkGlyph.h:514
size_t addPathFromBuffer(SkReadBuffer &, SkArenaAlloc *)
Definition: SkGlyph.cpp:389
bool imageTooLarge() const
Definition: SkGlyph.h:517
size_t formatAlignment() const
Definition: SkGlyph.cpp:173
void ensureIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, SkScalar *array, int *count, SkArenaAlloc *alloc)
Definition: SkGlyph.cpp:547
void flattenMetrics(SkWriteBuffer &) const
Definition: SkGlyph.cpp:336
bool setDrawableHasBeenCalled() const
Definition: SkGlyph.h:495
size_t imageSize() const
Definition: SkGlyph.cpp:241
SkMask mask() const
Definition: SkGlyph.cpp:125
bool setImageHasBeenCalled() const
Definition: SkGlyph.h:459
size_t setMetricsAndImage(SkArenaAlloc *alloc, const SkGlyph &from)
Definition: SkGlyph.cpp:207
const SkPath * path() const
Definition: SkGlyph.cpp:284
SkMask::Format maskFormat() const
Definition: SkGlyph.h:500
SkGlyph & operator=(const SkGlyph &)
bool setDrawable(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:310
bool setPath(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:266
bool pathIsHairline() const
Definition: SkGlyph.cpp:293
void flattenPath(SkWriteBuffer &) const
Definition: SkGlyph.cpp:378
size_t rowBytesUsingFormat(SkMask::Format format) const
Definition: SkGlyph.cpp:237
bool setImage(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:185
void flattenDrawable(SkWriteBuffer &) const
Definition: SkGlyph.cpp:414
constexpr SkGlyph()
Definition: SkGlyph.h:417
size_t addImageFromBuffer(SkReadBuffer &, SkArenaAlloc *)
Definition: SkGlyph.cpp:358
size_t addDrawableFromBuffer(SkReadBuffer &, SkArenaAlloc *)
Definition: SkGlyph.cpp:425
void flattenImage(SkWriteBuffer &) const
Definition: SkGlyph.cpp:349
SkDrawable * drawable() const
Definition: SkGlyph.cpp:327
int left() const
Definition: SkGlyph.h:510
int maxDimension() const
Definition: SkGlyph.h:504
const void * image() const
Definition: SkGlyph.h:465
static std::optional< SkGlyph > MakeFromBuffer(SkReadBuffer &)
Definition: SkGlyph.cpp:95
Verb next(SkPoint pts[4])
Definition: SkPath.cpp:1901
Definition: SkPath.h:59
size_t approximateBytesUsed() const
Definition: SkPath.cpp:572
const SkRect & getBounds() const
Definition: SkPath.cpp:430
@ kClose_Verb
Definition: SkPath.h:1471
@ kMove_Verb
Definition: SkPath.h:1466
@ kConic_Verb
Definition: SkPath.h:1469
@ kDone_Verb
Definition: SkPath.h:1472
@ kCubic_Verb
Definition: SkPath.h:1470
@ kQuad_Verb
Definition: SkPath.h:1468
@ kLine_Verb
Definition: SkPath.h:1467
SkPictureBackedGlyphDrawable(sk_sp< SkPicture > self)
Definition: SkGlyph.cpp:79
static sk_sp< SkPictureBackedGlyphDrawable > MakeFromBuffer(SkReadBuffer &buffer)
Definition: SkGlyph.cpp:37
static void FlattenDrawable(SkWriteBuffer &buffer, SkDrawable *drawable)
Definition: SkGlyph.cpp:59
sk_sp< SkData > serialize(const SkSerialProcs *procs=nullptr) const
Definition: SkPicture.cpp:249
virtual SkRect cullRect() const =0
static sk_sp< SkPicture > MakeFromData(const SkData *data, const SkDeserialProcs *procs=nullptr)
Definition: SkPicture.cpp:160
virtual size_t approximateBytesUsed() const =0
bool readByteArray(void *value, size_t size)
bool isValid() const
Definition: SkReadBuffer.h:208
void getPath(SkGlyph &, SkArenaAlloc *)
sk_sp< SkDrawable > getDrawable(SkGlyph &)
void getImage(const SkGlyph &)
virtual void writeBool(bool value)=0
virtual void writeByteArray(const void *data, size_t size)=0
virtual void writePath(const SkPath &path)=0
T * get() const
Definition: SkRefCnt.h:303
virtual bool prepareForPath(SkGlyph *)=0
virtual bool prepareForDrawable(SkGlyph *)=0
virtual bool prepareForImage(SkGlyph *)=0
float SkScalar
Definition: extension.cpp:12
uint8_t value
uint32_t uint32_t * format
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double x
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
def match(bench, filt)
Definition: benchmark.py:23
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
GlyphAction
Definition: SkGlyph.h:304
ActionType
Definition: SkGlyph.h:312
@ kSDFT
Definition: SkGlyph.h:316
@ kPath
Definition: SkGlyph.h:317
@ kMask
Definition: SkGlyph.h:315
@ kDirectMask
Definition: SkGlyph.h:313
@ kDirectMaskCPU
Definition: SkGlyph.h:314
Definition: ref_ptr.h:256
int32_t height
int32_t width
const Scalar scale
SeparatedVector2 offset
SkGlyphPositionRoundingSpec(bool isSubpixel, SkAxisAlignment axisAlignment)
Definition: SkGlyph.cpp:722
constexpr int32_t y() const
Definition: SkPoint_impl.h:52
static constexpr SkIPoint Make(int32_t x, int32_t y)
Definition: SkPoint_impl.h:38
constexpr int32_t x() const
Definition: SkPoint_impl.h:46
Definition: SkRect.h:32
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition: SkRect.h:104
Definition: SkMask.h:25
Format
Definition: SkMask.h:26
@ k3D_Format
3 8bit per pixl planes: alpha, mul, add
Definition: SkMask.h:29
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
Definition: SkMask.h:28
@ kLCD16_Format
565 alpha for r/g/b
Definition: SkMask.h:31
@ kARGB32_Format
SkPMColor.
Definition: SkMask.h:30
@ kSDF_Format
8bits representing signed distance field
Definition: SkMask.h:32
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition: SkMask.h:27
static bool IsValidFormat(uint8_t format)
Definition: SkMask.h:46
static const constexpr SkScalar kSubpixelRound
Definition: SkGlyph.h:69
static const constexpr SkIPoint kXYFieldMask
Definition: SkGlyph.h:72
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
SkScalar fBottom
larger y-axis bounds
Definition: extension.cpp:17
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63