Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
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
81
85
89
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
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
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])
597 = calculate_path_gap(bounds[0], bounds[1], *path);
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 |
613 kDrop << kDirectMaskCPU |
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
634void SkGlyphDigest::setActionFor(skglyph::ActionType actionType,
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() &&
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)} {}
static bool match(const char *needle, const char *haystack)
Definition DM.cpp:1132
int count
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
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
constexpr D SkTo(S s)
Definition SkTo.h:16
void * makeBytesAlignedTo(size_t size, size_t align)
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
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 approximateBytesUsed()
sk_sp< SkPicture > makePictureSnapshot()
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:1837
size_t approximateBytesUsed() const
Definition SkPath.cpp:562
const SkRect & getBounds() const
Definition SkPath.cpp:420
@ kClose_Verb
Definition SkPath.h:1463
@ kMove_Verb
Definition SkPath.h:1458
@ kConic_Verb
Definition SkPath.h:1461
@ kDone_Verb
Definition SkPath.h:1464
@ kCubic_Verb
Definition SkPath.h:1462
@ kQuad_Verb
Definition SkPath.h:1460
@ kLine_Verb
Definition SkPath.h:1459
SkRect onGetBounds() override
Definition SkGlyph.cpp:82
SkPictureBackedGlyphDrawable(sk_sp< SkPicture > self)
Definition SkGlyph.cpp:79
void onDraw(SkCanvas *canvas) override
Definition SkGlyph.cpp:90
size_t onApproximateBytesUsed() override
Definition SkGlyph.cpp:86
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
virtual SkRect cullRect() const =0
static sk_sp< SkPicture > MakeFromData(const SkData *data, const SkDeserialProcs *procs=nullptr)
virtual size_t approximateBytesUsed() const =0
bool readByteArray(void *value, size_t size)
bool isValid() const
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
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
static const uint8_t buffer[]
uint8_t value
uint32_t uint32_t * format
double x
Definition ref_ptr.h:256
int32_t height
int32_t width
const Scalar scale
Point offset
SkGlyphPositionRoundingSpec(bool isSubpixel, SkAxisAlignment axisAlignment)
Definition SkGlyph.cpp:722
constexpr int32_t y() const
static constexpr SkIPoint Make(int32_t x, int32_t y)
constexpr int32_t x() const
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
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
constexpr float y() const
constexpr float x() const
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15