43 if (!
buffer.isValid() || pictureData->size() == 0) {
52 if (!
buffer.validate(picture !=
nullptr)) {
56 return sk_make_sp<SkPictureBackedGlyphDrawable>(std::move(picture));
60 if (drawable ==
nullptr) {
61 buffer.writeByteArray(
nullptr, 0);
71 if (!SkTFitsIn<uint32_t>(data->size()) || data->size() == 0) {
72 buffer.writeByteArray(
nullptr, 0);
76 buffer.writeByteArray(data->data(), data->size());
80 : fPicture(
std::move(picture)) {}
99 const uint32_t dimensions =
buffer.readUInt();
100 const uint32_t leftTop =
buffer.readUInt();
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;)
127 return SkMask(
static_cast<const uint8_t*
>(fImage), bounds, this->
rowBytes(), fMaskFormat);
134 return SkMask(
static_cast<const uint8_t*
>(fImage), bounds, this->
rowBytes(), fMaskFormat);
147 return (bits + 7) >> 3;
156 return alignof(uint8_t);
158 return alignof(uint32_t);
160 return alignof(uint16_t);
190 this->allocImage(alloc);
200 this->allocImage(alloc);
210 SkASSERT(fImage ==
nullptr || from.fImage ==
nullptr);
213 if (fImage ==
nullptr) {
214 fAdvanceX = from.fAdvanceX;
215 fAdvanceY = from.fAdvanceY;
216 fWidth = from.fWidth;
217 fHeight = from.fHeight;
220 fScalerContextBits = from.fScalerContextBits;
221 fMaskFormat = from.fMaskFormat;
224 if (from.fImage !=
nullptr && this->setImage(alloc, from.
image())) {
228 SkDEBUGCODE(fAdvancesBoundsFormatAndInitialPathDone = from.fAdvancesBoundsFormatAndInitialPathDone;)
244 size_t size = this->
rowBytes() * fHeight;
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;
268 scalerContext->
getPath(*
this, alloc);
270 return this->
path() !=
nullptr;
278 this->installPath(alloc,
path, hairline);
279 return this->
path() !=
nullptr;
287 if (fPathData->fHasPath) {
288 return &fPathData->fPath;
296 return fPathData->fHairline;
302 fDrawableData = alloc->
make<SkGlyph::DrawableData>();
304 fDrawableData->fDrawable = std::move(
drawable);
305 fDrawableData->fDrawable->getGenerationID();
306 fDrawableData->fHasDrawable =
true;
313 this->installDrawable(alloc, std::move(
drawable));
321 this->installDrawable(alloc, std::move(
drawable));
330 if (fDrawableData->fHasDrawable) {
331 return fDrawableData->fDrawable.get();
337 buffer.writeUInt(fID.value());
338 buffer.writePoint({fAdvanceX, fAdvanceY});
339 buffer.writeUInt(fWidth << 16 | fHeight);
343 const uint32_t
left =
static_cast<uint16_t
>(fLeft);
344 const uint32_t
top =
static_cast<uint16_t
>(fTop);
346 buffer.writeUInt(SkTo<uint32_t>(fMaskFormat));
366 size_t memoryIncrease = 0;
371 this->installImage(imageData);
375 return memoryIncrease;
381 const bool hasPath = this->
path() !=
nullptr;
392 size_t memoryIncrease = 0;
393 const bool hasPath =
buffer.readBool();
408 this->
setPath(alloc,
nullptr,
false);
411 return memoryIncrease;
456 if (0 <= t && t < 1) {
457 expandGap(pts[0].fX + t * (pts[1].fX - pts[0].fX));
471 float intersectionStorage[3];
475 for(
double intersection : intersections) {
476 expandGap(intersection);
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);
497 auto [lineTop, lineBottom] = std::minmax({pts[0].
fY, pts[1].
fY});
500 if (topOffset <= lineBottom && lineTop <= bottomOffset) {
502 addLine(bottomOffset);
508 auto [quadTop, quadBottom] = std::minmax({pts[0].
fY, pts[1].
fY, pts[2].
fY});
511 if (topOffset <= quadBottom && quadTop <= bottomOffset) {
513 addQuad(bottomOffset);
519 SkDEBUGFAIL(
"There should be no conic primitives in glyph outlines.");
523 auto [cubicTop, cubicBottom] =
524 std::minmax({pts[0].
fY, pts[1].
fY, pts[2].
fY, pts[3].
fY});
527 if (topOffset <= cubicBottom && cubicTop <= bottomOffset) {
529 addCubic(bottomOffset);
538 SkDEBUGFAIL(
"Unknown path verb generating glyph underline.");
550 auto offsetResults = [
scale, xPos](
551 const SkGlyph::Intercept* intercept,
SkScalar* array,
int*
count) {
554 for (
int index = 0; index < 2; index++) {
555 *array++ = intercept->fInterval[index] *
scale + xPos;
561 const SkGlyph::Intercept*
match =
562 [
this](
const SkScalar bounds[2]) ->
const SkGlyph::Intercept* {
563 if (fPathData ==
nullptr) {
566 const SkGlyph::Intercept* intercept = fPathData->fIntercept;
567 while (intercept !=
nullptr) {
568 if (bounds[0] == intercept->fBounds[0] && bounds[1] == intercept->fBounds[1]) {
571 intercept = intercept->fNext;
576 if (
match !=
nullptr) {
577 if (
match->fInterval[0] <
match->fInterval[1]) {
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];
589 fPathData->fIntercept = intercept;
592 if (pathBounds.
fBottom < bounds[0] || bounds[1] < pathBounds.
fTop) {
596 std::tie(intercept->fInterval[0], intercept->fInterval[1])
599 if (intercept->fInterval[0] >= intercept->fInterval[1]) {
604 offsetResults(intercept, array,
count);
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 |
618 return glyph.
isEmpty() ? kAllDrop : kAllUnset;
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())}
638 if (this->
actionFor(actionType) == GlyphAction::kUnset) {
639 GlyphAction
action = GlyphAction::kReject;
640 switch (actionType) {
643 action = GlyphAction::kAccept;
647 case kDirectMaskCPU: {
650 action = GlyphAction::kAccept;
656 action = GlyphAction::kAccept;
663 action = GlyphAction::kAccept;
669 action = GlyphAction::kAccept;
675 action = GlyphAction::kAccept;
680 this->setAction(actionType,
action);
689SkVector SkGlyphPositionRoundingSpec::HalfAxisSampleFreq(
694 switch (axisAlignment) {
708SkIPoint SkGlyphPositionRoundingSpec::IgnorePositionMask(
714SkIPoint SkGlyphPositionRoundingSpec::IgnorePositionFieldMask(
bool isSubpixel,
716 SkIPoint ignoreMask = IgnorePositionMask(isSubpixel, 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)
#define SkDEBUGFAIL(message)
#define SK_ABORT(message,...)
static constexpr float sk_ieee_float_divide(float numer, float denom)
static size_t format_alignment(SkMask::Format format)
static size_t format_rowbytes(int width, SkMask::Format format)
static size_t bits_to_bytes(size_t bits)
static std::tuple< SkScalar, SkScalar > calculate_path_gap(SkScalar topOffset, SkScalar bottomOffset, const SkPath &path)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
static bool SkScalarIsInt(SkScalar x)
#define SkScalarFloorToInt(x)
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)
size_t approximateBytesUsed()
sk_sp< SkPicture > makePictureSnapshot()
SkMask::Format maskFormat() const
static bool FitsInAtlas(const SkGlyph &glyph)
static constexpr uint16_t kSkSideTooBigForAtlas
bool fitsInAtlasInterpolated() const
void setActionFor(skglyph::ActionType, SkGlyph *, sktext::StrikeForGPU *)
bool fitsInAtlasDirect() const
skglyph::GlyphAction actionFor(skglyph::ActionType actionType) const
bool setPathHasBeenCalled() const
size_t addPathFromBuffer(SkReadBuffer &, SkArenaAlloc *)
bool imageTooLarge() const
size_t formatAlignment() const
void ensureIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, SkScalar *array, int *count, SkArenaAlloc *alloc)
void flattenMetrics(SkWriteBuffer &) const
bool setDrawableHasBeenCalled() const
bool setImageHasBeenCalled() const
size_t setMetricsAndImage(SkArenaAlloc *alloc, const SkGlyph &from)
const SkPath * path() const
SkMask::Format maskFormat() const
SkGlyph & operator=(const SkGlyph &)
bool setDrawable(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
bool setPath(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
bool pathIsHairline() const
void flattenPath(SkWriteBuffer &) const
size_t rowBytesUsingFormat(SkMask::Format format) const
bool setImage(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
void flattenDrawable(SkWriteBuffer &) const
size_t addImageFromBuffer(SkReadBuffer &, SkArenaAlloc *)
size_t addDrawableFromBuffer(SkReadBuffer &, SkArenaAlloc *)
void flattenImage(SkWriteBuffer &) const
SkDrawable * drawable() const
const void * image() const
static std::optional< SkGlyph > MakeFromBuffer(SkReadBuffer &)
Verb next(SkPoint pts[4])
size_t approximateBytesUsed() const
const SkRect & getBounds() const
SkRect onGetBounds() override
SkPictureBackedGlyphDrawable(sk_sp< SkPicture > self)
void onDraw(SkCanvas *canvas) override
size_t onApproximateBytesUsed() override
static sk_sp< SkPictureBackedGlyphDrawable > MakeFromBuffer(SkReadBuffer &buffer)
static void FlattenDrawable(SkWriteBuffer &buffer, SkDrawable *drawable)
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)
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
virtual bool prepareForPath(SkGlyph *)=0
virtual bool prepareForDrawable(SkGlyph *)=0
virtual bool prepareForImage(SkGlyph *)=0
static const uint8_t buffer[]
uint32_t uint32_t * format
SkGlyphPositionRoundingSpec(bool isSubpixel, SkAxisAlignment axisAlignment)
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)
@ k3D_Format
3 8bit per pixl planes: alpha, mul, add
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
@ kLCD16_Format
565 alpha for r/g/b
@ kARGB32_Format
SkPMColor.
@ kSDF_Format
8bits representing signed distance field
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
static bool IsValidFormat(uint8_t format)
static const constexpr SkScalar kSubpixelRound
static const constexpr SkIPoint kXYFieldMask
constexpr float y() const
constexpr float x() const
SkScalar fBottom
larger y-axis bounds
SkScalar fTop
smaller y-axis bounds