62#include <initializer_list>
69#if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
100#if !defined(SK_DISABLE_SDF_TEXT)
117#if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
126 if (maskFormat == MaskFormat::kARGB) {
142 return accepted.
get<0>();
146 return accepted.
get<0>();
151 return accepted.template get<1>();
158class PathOpSubmitter {
160 PathOpSubmitter() =
delete;
161 PathOpSubmitter(
const PathOpSubmitter&) =
delete;
162 const PathOpSubmitter& operator=(
const PathOpSubmitter&) =
delete;
163 PathOpSubmitter(PathOpSubmitter&& that)
165 : fIDsOrPaths{std::exchange(
167 , fPositions{that.fPositions}
168 , fStrikeToSourceScale{that.fStrikeToSourceScale}
169 , fIsAntiAliased{that.fIsAntiAliased}
170 , fStrikePromise{std::move(that.fStrikePromise)} {}
171 PathOpSubmitter& operator=(PathOpSubmitter&& that) {
172 this->~PathOpSubmitter();
173 new (
this) PathOpSubmitter{std::move(that)};
176 PathOpSubmitter(
bool isAntiAliased,
190 int unflattenSize()
const;
207 const SkScalar fStrikeToSourceScale;
208 const bool fIsAntiAliased;
211 mutable SkOnce fConvertIDsToPaths;
212 mutable bool fPathsAreCreated{
false};
215int PathOpSubmitter::unflattenSize()
const {
216 return fPositions.size_bytes() + fIDsOrPaths.size_bytes();
220 fStrikePromise.flatten(
buffer);
222 buffer.writeInt(fIsAntiAliased);
223 buffer.writeScalar(fStrikeToSourceScale);
224 buffer.writePointArray(fPositions.data(),
SkCount(fPositions));
225 for (
IDOrPath& idOrPath : fIDsOrPaths) {
226 buffer.writeInt(idOrPath.fGlyphID);
233 std::optional<SkStrikePromise> strikePromise =
235 if (!
buffer.validate(strikePromise.has_value())) {
239 bool isAntiAlias =
buffer.readInt();
242 if (!
buffer.validate(0 < strikeToSourceScale)) {
return std::nullopt; }
245 if (positions.
empty()) {
return std::nullopt; }
246 const int glyphCount =
SkCount(positions);
249 if (!
buffer.validateCanReadN<
int>(glyphCount)) {
return std::nullopt; }
251 for (
auto& idOrPath : idsOrPaths) {
252 idOrPath.fGlyphID = SkTo<SkGlyphID>(
buffer.readInt());
255 if (!
buffer.isValid()) {
return std::nullopt; }
257 return PathOpSubmitter{isAntiAlias,
261 std::move(strikePromise.value())};
264PathOpSubmitter::PathOpSubmitter(
270 : fIDsOrPaths{idsOrPaths}
271 , fPositions{positions}
272 , fStrikeToSourceScale{strikeToSourceScale}
273 , fIsAntiAliased{isAntiAliased}
274 , fStrikePromise{std::move(strikePromise)} {
278PathOpSubmitter::~PathOpSubmitter() {
280 if (fPathsAreCreated) {
281 for (
auto& idOrPath : fIDsOrPaths) {
282 idOrPath.fPath.~SkPath();
297 return PathOpSubmitter{isAntiAliased,
301 std::move(strikePromise)};
307 fConvertIDsToPaths([&]() {
308 if (
SkStrike* strike = fStrikePromise.strike()) {
309 strike->glyphIDsToPaths(fIDsOrPaths);
312 fStrikePromise.resetStrike();
313 fPathsAreCreated = true;
318 runPaint.setAntiAlias(fIsAntiAliased);
330 bool needsExactCTM = runPaint.getShader()
331 || runPaint.getPathEffect()
333 || (maskFilter !=
nullptr && !maskFilter->
asABlur(
nullptr));
334 if (!needsExactCTM) {
339 if (maskFilter !=
nullptr && maskFilter->
asABlur(&blurRec)) {
340 runPaint.setMaskFilter(
343 for (
auto [idOrPath,
pos] :
SkMakeZip(fIDsOrPaths, fPositions)) {
345 SkMatrix pathMatrix = strikeToSource;
349 canvas->
concat(pathMatrix);
350 canvas->
drawPath(idOrPath.fPath, runPaint);
355 for (
auto [idOrPath,
pos] :
SkMakeZip(fIDsOrPaths, fPositions)) {
357 SkMatrix pathMatrix = strikeToSource;
361 idOrPath.fPath.
transform(pathMatrix, &deviceOutline);
363 canvas->
drawPath(deviceOutline, runPaint);
369class PathSubRun final :
public SubRun {
371 PathSubRun(PathOpSubmitter&& pathDrawing) : fPathDrawing(std::move(pathDrawing)) {}
379 PathOpSubmitter::Make(
380 accepted, isAntiAliased, strikeToSourceScale, std::move(strikePromise), alloc));
388 fPathDrawing.submitDraws(canvas, drawOrigin,
paint);
402 SubRunStreamTag
subRunStreamTag()
const override {
return SubRunStreamTag::kPathStreamTag; }
406 PathOpSubmitter fPathDrawing;
409int PathSubRun::unflattenSize()
const {
410 return sizeof(PathSubRun) + fPathDrawing.unflattenSize();
414 fPathDrawing.flatten(
buffer);
420 auto pathOpSubmitter = PathOpSubmitter::MakeFromBuffer(
buffer, alloc, client);
421 if (!
buffer.validate(pathOpSubmitter.has_value())) {
return nullptr; }
422 return alloc->
makeUnique<PathSubRun>(std::move(*pathOpSubmitter));
427class DrawableOpSubmitter {
429 DrawableOpSubmitter() =
delete;
430 DrawableOpSubmitter(
const DrawableOpSubmitter&) =
delete;
431 const DrawableOpSubmitter& operator=(
const DrawableOpSubmitter&) =
delete;
432 DrawableOpSubmitter(DrawableOpSubmitter&& that)
433 : fStrikeToSourceScale{that.fStrikeToSourceScale}
434 , fPositions{that.fPositions}
435 , fIDsOrDrawables{that.fIDsOrDrawables}
436 , fStrikePromise{std::move(that.fStrikePromise)} {}
437 DrawableOpSubmitter& operator=(DrawableOpSubmitter&& that) {
438 this->~DrawableOpSubmitter();
439 new (
this) DrawableOpSubmitter{std::move(that)};
442 DrawableOpSubmitter(
SkScalar strikeToSourceScale,
453 return DrawableOpSubmitter{
457 std::move(strikePromise)};
460 int unflattenSize()
const;
468 const SkScalar fStrikeToSourceScale;
474 mutable SkOnce fConvertIDsToDrawables;
477int DrawableOpSubmitter::unflattenSize()
const {
478 return fPositions.size_bytes() + fIDsOrDrawables.size_bytes();
482 fStrikePromise.flatten(
buffer);
484 buffer.writeScalar(fStrikeToSourceScale);
485 buffer.writePointArray(fPositions.data(),
SkCount(fPositions));
487 buffer.writeInt(idOrDrawable.fGlyphID);
491std::optional<DrawableOpSubmitter> DrawableOpSubmitter::MakeFromBuffer(
493 std::optional<SkStrikePromise> strikePromise =
495 if (!
buffer.validate(strikePromise.has_value())) {
500 if (!
buffer.validate(0 < strikeToSourceScale)) {
return std::nullopt; }
503 if (positions.
empty()) {
return std::nullopt; }
504 const int glyphCount =
SkCount(positions);
506 if (!
buffer.validateCanReadN<
int>(glyphCount)) {
return std::nullopt; }
508 for (
int i = 0; i <
SkToInt(glyphCount); ++i) {
514 return DrawableOpSubmitter{strikeToSourceScale,
516 SkSpan(idsOrDrawables, glyphCount),
517 std::move(strikePromise.value())};
520DrawableOpSubmitter::DrawableOpSubmitter(
525 : fStrikeToSourceScale{strikeToSourceScale}
526 , fPositions{positions}
527 , fIDsOrDrawables{idsOrDrawables}
528 , fStrikePromise(std::move(strikePromise)) {
535 fConvertIDsToDrawables([&]() {
536 fStrikePromise.strike()->glyphIDsToDrawables(fIDsOrDrawables);
544 strikeToSource.postTranslate(drawOrigin.
x(), drawOrigin.
y());
549 SkDrawable* drawable = fIDsOrDrawables[i].fDrawable;
551 if (drawable ==
nullptr) {
553 fStrikePromise.strike()->verifyPinnedStrike();
559 SkMatrix pathMatrix = strikeToSource;
564 pathMatrix.
mapRect(&drawableBounds);
566 drawable->
draw(canvas, &pathMatrix);
571class DrawableSubRun :
public SubRun {
573 DrawableSubRun(DrawableOpSubmitter&& drawingDrawing)
574 : fDrawingDrawing(std::move(drawingDrawing)) {}
581 DrawableOpSubmitter::Make(drawables,
583 std::move(strikePromise),
596 fDrawingDrawing.submitDraws(canvas, drawOrigin,
paint);
606 SubRunStreamTag
subRunStreamTag()
const override {
return SubRunStreamTag::kDrawableStreamTag; }
610 DrawableOpSubmitter fDrawingDrawing;
613int DrawableSubRun::unflattenSize()
const {
614 return sizeof(DrawableSubRun) + fDrawingDrawing.unflattenSize();
618 fDrawingDrawing.flatten(
buffer);
624 auto drawableOpSubmitter = DrawableOpSubmitter::MakeFromBuffer(
buffer, alloc, client);
625 if (!
buffer.validate(drawableOpSubmitter.has_value())) {
return nullptr; }
626 return alloc->
makeUnique<DrawableSubRun>(std::move(*drawableOpSubmitter));
633const AtlasSubRun* DrawableSubRun::testingOnly_atlasSubRun()
const {
637#if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
645std::tuple<ClipMethod, SkIRect>
649 }
else if (
clip !=
nullptr) {
662 if (clipRect.contains(glyphBounds)) {
667 return {kGeometryClipped, clipRect};
684 : fVertexFiller{std::move(vertexFiller)}
685 , fGlyphs{std::move(
glyphs)} {}
696 get_positions(accepted),
703 return alloc->
makeUnique<DirectMaskSubRun>(std::move(vertexFiller), std::move(glyphVector));
710 if (!
buffer.validate(vertexFiller.has_value())) {
return nullptr; }
713 if (!
buffer.validate(glyphVector.has_value())) {
return nullptr; }
714 if (!
buffer.validate(
SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
720 std::move(*vertexFiller), std::move(*glyphVector));
728 drawAtlas(
this, drawOrigin,
paint, std::move(subRunStorage),
729 {
false, fVertexFiller.isLCD()});
733 return sizeof(DirectMaskSubRun) +
734 fGlyphs.unflattenSize() +
735 fVertexFiller.unflattenSize();
739 return SkCount(fGlyphs.glyphs());
743 return fGlyphs.glyphs();
751 return (
unsigned short)fVertexFiller.grMaskType();
755 fGlyphs.packedGlyphIDToGlyph(cache);
758#if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
759 size_t vertexStride(
const SkMatrix& drawMatrix)
const override {
760 return fVertexFiller.vertexStride(drawMatrix);
763 std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
773 auto [integerTranslate, subRunDeviceBounds] =
774 fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
775 if (subRunDeviceBounds.isEmpty()) {
776 return {
nullptr,
nullptr};
780 if (integerTranslate) {
785 auto [clipMethod, clipRect] = calculate_clip(
clip, deviceBounds, subRunDeviceBounds);
787 switch (clipMethod) {
790 return {
nullptr,
nullptr};
792 case kGeometryClipped:
800 geometricClipRect = clipRect;
806 const SkPMColor4f drawingColor = calculate_colors(sdc,
809 fVertexFiller.grMaskType(),
812 auto geometry = AtlasTextOp::Geometry::Make(*
this,
816 std::move(subRunStorage),
823 fVertexFiller.opMaskType(),
830 return {
clip, std::move(op)};
833 void fillVertexData(
void* vertexDst,
int offset,
int count,
850 &fGlyphs,
begin,
end, fVertexFiller.grMaskType(), this->glyphSrcPadding());
866 return SubRunStreamTag::kDirectMaskStreamTag;
870 fVertexFiller.flatten(
buffer);
885 TransformedMaskSubRun(
bool isBigEnough,
888 : fIsBigEnough{isBigEnough}
889 , fVertexFiller{std::move(vertexFiller)}
890 , fGlyphs{std::move(
glyphs)} {}
893 const SkMatrix& initialPositionMatrix,
902 get_positions(accepted),
907 std::move(strikePromise), get_packedIDs(accepted), alloc);
909 return alloc->
makeUnique<TransformedMaskSubRun>(
911 std::move(vertexFiller),
912 std::move(glyphVector));
919 if (!
buffer.validate(vertexFiller.has_value())) {
return nullptr; }
922 if (!
buffer.validate(glyphVector.has_value())) {
return nullptr; }
923 if (!
buffer.validate(
SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
926 const bool isBigEnough =
buffer.readBool();
927 return alloc->
makeUnique<TransformedMaskSubRun>(
928 isBigEnough, std::move(*vertexFiller), std::move(*glyphVector));
931 int unflattenSize()
const override {
932 return sizeof(TransformedMaskSubRun) +
933 fGlyphs.unflattenSize() +
934 fVertexFiller.unflattenSize();
943 const AtlasSubRun* testingOnly_atlasSubRun()
const override {
return this; }
945 void testingOnly_packedGlyphIDToGlyph(
StrikeCache *cache)
const override {
946 fGlyphs.packedGlyphIDToGlyph(cache);
949 int glyphCount()
const override {
return SkCount(fGlyphs.glyphs()); }
952 return fGlyphs.glyphs();
955 unsigned short instanceFlags()
const override {
956 return (
unsigned short)fVertexFiller.grMaskType();
959 MaskFormat maskFormat()
const override {
return fVertexFiller.grMaskType(); }
961 int glyphSrcPadding()
const override {
return 1; }
968 drawAtlas(
this, drawOrigin,
paint, std::move(subRunStorage),
969 {
false, fVertexFiller.isLCD()});
972#if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
974 size_t vertexStride(
const SkMatrix& drawMatrix)
const override {
975 return fVertexFiller.vertexStride(drawMatrix);
978 std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
991 fVertexFiller.grMaskType(),
994 auto geometry = AtlasTextOp::Geometry::Make(*
this,
998 std::move(subRunStorage),
1004 auto [_, deviceRect] = fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
1005 GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1006 fVertexFiller.opMaskType(),
1012 std::move(grPaint));
1013 return {
clip, std::move(op)};
1016 void fillVertexData(
1031 std::tuple<bool, int> regenerateAtlas(
int begin,
int end,
1033 return regenerateAtlas(
1034 &fGlyphs,
begin,
end, fVertexFiller.grMaskType(), this->glyphSrcPadding());
1037 const VertexFiller& vertexFiller()
const override {
return fVertexFiller; }
1040 SubRunStreamTag subRunStreamTag()
const override {
1041 return SubRunStreamTag::kTransformMaskStreamTag;
1047 buffer.writeBool(fIsBigEnough);
1051 const bool fIsBigEnough;
1062bool has_some_antialiasing(
const SkFont& font ) {
1068#if !defined(SK_DISABLE_SDF_TEXT)
1070#if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
1072static std::tuple<AtlasTextOp::MaskType, uint32_t, bool> calculate_sdf_parameters(
1076 bool isAntiAliased) {
1081 using MT = AtlasTextOp::MaskType;
1082 MT maskType = !isAntiAliased ? MT::kAliasedDistanceField
1083 :
isLCD ? (isBGR ? MT::kLCDBGRDistanceField
1084 : MT::kLCDDistanceField)
1085 : MT::kGrayscaleDistanceField;
1098 return {maskType, DFGPFlags, useGammaCorrectDistanceTable};
1105 SDFTSubRun(
bool useLCDText,
1110 : fUseLCDText{useLCDText}
1111 , fAntiAliased{antiAliased}
1112 , fMatrixRange{matrixRange}
1113 , fVertexFiller{std::move(vertexFiller)}
1114 , fGlyphs{std::move(
glyphs)} { }
1126 get_positions(accepted),
1131 std::move(strikePromise), get_packedIDs(accepted), alloc);
1135 has_some_antialiasing(runFont),
1137 std::move(vertexFiller),
1138 std::move(glyphVector));
1144 int useLCD =
buffer.readInt();
1145 int isAntiAliased =
buffer.readInt();
1148 if (!
buffer.validate(vertexFiller.has_value())) {
return nullptr; }
1149 if (!
buffer.validate(vertexFiller.value().grMaskType() == MaskFormat::kA8)) {
1153 if (!
buffer.validate(glyphVector.has_value())) {
return nullptr; }
1154 if (!
buffer.validate(
SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
1160 std::move(*vertexFiller),
1161 std::move(*glyphVector));
1164 int unflattenSize()
const override {
1165 return sizeof(SDFTSubRun) + fGlyphs.unflattenSize() + fVertexFiller.unflattenSize();
1169 return fMatrixRange.matrixInRange(positionMatrix);
1172 const AtlasSubRun* testingOnly_atlasSubRun()
const override {
return this; }
1174 void testingOnly_packedGlyphIDToGlyph(
StrikeCache *cache)
const override {
1175 fGlyphs.packedGlyphIDToGlyph(cache);
1178 int glyphCount()
const override {
return fVertexFiller.count(); }
1180 SkASSERT(fVertexFiller.grMaskType() == MaskFormat::kA8);
1181 return MaskFormat::kA8;
1186 return fGlyphs.glyphs();
1189 unsigned short instanceFlags()
const override {
1190 return (
unsigned short)MaskFormat::kA8;
1198 drawAtlas(
this, drawOrigin,
paint, std::move(subRunStorage),
1199 {
true, fUseLCDText});
1202#if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
1203 size_t vertexStride(
const SkMatrix& drawMatrix)
const override {
1204 return fVertexFiller.vertexStride(drawMatrix);
1207 std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
1223 auto [maskType, DFGPFlags, useGammaCorrectDistanceTable] =
1224 calculate_sdf_parameters(*sdc, viewMatrix, fUseLCDText, fAntiAliased);
1226 auto geometry = AtlasTextOp::Geometry::Make(*
this,
1230 std::move(subRunStorage),
1236 auto [_, deviceRect] = fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
1237 GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1243 useGammaCorrectDistanceTable,
1246 std::move(grPaint));
1248 return {
clip, std::move(op)};
1251 void fillVertexData(
1268 std::tuple<bool, int> regenerateAtlas(
int begin,
int end,
1270 return regenerateAtlas(&fGlyphs,
begin,
end, MaskFormat::kA8, this->glyphSrcPadding());
1273 const VertexFiller& vertexFiller()
const override {
return fVertexFiller; }
1276 SubRunStreamTag subRunStreamTag()
const override {
return SubRunStreamTag::kSDFTStreamTag; }
1278 buffer.writeInt(fUseLCDText);
1279 buffer.writeInt(fAntiAliased);
1281 fVertexFiller.flatten(
buffer);
1286 const bool fUseLCDText;
1287 const bool fAntiAliased;
1301template<
typename AddSingleMaskFormat>
1302void add_multi_mask_format(
1303 AddSingleMaskFormat addSingleMaskFormat,
1305 if (accepted.
empty()) {
return; }
1307 auto maskSpan = accepted.
get<2>();
1309 size_t startIndex = 0;
1310 for (
size_t i = 1; i < accepted.
size(); i++) {
1312 if (
format != nextFormat) {
1313 auto interval = accepted.
subspan(startIndex, i - startIndex);
1315 auto glyphsWithSameFormat =
SkMakeZip(interval.get<0>(), interval.get<1>());
1317 addSingleMaskFormat(glyphsWithSameFormat,
format);
1322 auto interval = accepted.
last(accepted.
size() - startIndex);
1323 auto glyphsWithSameFormat =
SkMakeZip(interval.get<0>(), interval.get<1>());
1324 addSingleMaskFormat(glyphsWithSameFormat,
format);
1344 DirectMaskSubRun::MakeFromBuffer,
1345#if !defined(SK_DISABLE_SDF_TEXT)
1346 SDFTSubRun::MakeFromBuffer,
1348 TransformedMaskSubRun::MakeFromBuffer,
1349 PathSubRun::MakeFromBuffer,
1350 DrawableSubRun::MakeFromBuffer,
1352 int subRunTypeInt =
buffer.readInt();
1357 auto maker = makers[subRunTypeInt];
1358 if (!
buffer.validate(maker !=
nullptr)) {
return nullptr; }
1359 return maker(
buffer, alloc, client);
1364 : fInitialPositionMatrix{initialPositionMatrix} {}
1367 int unflattenSizeHint = 0;
1368 for (
auto& subrun : fSubRuns) {
1369 unflattenSizeHint += subrun.unflattenSize();
1371 buffer.writeInt(unflattenSizeHint);
1375 int subRunsSizeHint =
buffer.readInt();
1379 if (subRunsSizeHint < 0 || (1 << 16) < subRunsSizeHint) {
1380 subRunsSizeHint = 128;
1382 return subRunsSizeHint;
1386 buffer.writeMatrix(fInitialPositionMatrix);
1387 int subRunCount = 0;
1388 for ([[maybe_unused]]
auto& subRun : fSubRuns) {
1391 buffer.writeInt(subRunCount);
1392 for (
auto& subRun : fSubRuns) {
1401 buffer.readMatrix(&positionMatrix);
1402 if (!
buffer.isValid()) {
return nullptr; }
1405 int subRunCount =
buffer.readInt();
1407 if (!
buffer.validate(subRunCount > 0)) {
return nullptr; }
1408 for (
int i = 0; i < subRunCount; ++i) {
1410 if (!
buffer.validate(subRunOwner !=
nullptr)) {
return nullptr; }
1411 if (subRunOwner !=
nullptr) {
1412 container->fSubRuns.append(std::move(subRunOwner));
1420 constexpr size_t alignDiff =
alignof(DirectMaskSubRun) -
alignof(
SkPoint);
1421 constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0;
1424 return totalGlyphCount *
sizeof(
SkPoint)
1426 + glyphRunList.
runCount() * (
sizeof(DirectMaskSubRun) + vertexDataToSubRunPadding)
1438 return maxDimension;
1441#if !defined(SK_DISABLE_SDF_TEXT)
1448 int acceptedSize = 0,
1452 for (
const auto [glyphID,
pos] :
source) {
1460 case GlyphAction::kAccept: {
1468 boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
1469 acceptedBuffer[acceptedSize++] = std::make_tuple(packedID, glyphBounds.
leftTop());
1472 case GlyphAction::kReject:
1473 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1480 return {acceptedBuffer.
first(acceptedSize),
1481 rejectedBuffer.
first(rejectedSize),
1482 boundingRect.
rect()};
1486std::tuple<SkZip<const SkPackedGlyphID, const SkPoint, const SkMask::Format>,
1499 SkMatrix positionMatrixWithRounding = positionMatrix;
1500 positionMatrixWithRounding.
postTranslate(halfSampleFreq.
x(), halfSampleFreq.
y());
1502 int acceptedSize = 0,
1514 digest.
actionFor(skglyph::kDirectMask)) {
1515 case GlyphAction::kAccept: {
1519 boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
1520 acceptedBuffer[acceptedSize++] =
1524 case GlyphAction::kReject:
1525 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1532 return {acceptedBuffer.
first(acceptedSize),
1533 rejectedBuffer.
first(rejectedSize),
1534 boundingRect.
rect()};
1537std::tuple<SkZip<const SkPackedGlyphID, const SkPoint, const SkMask::Format>,
1545 int acceptedSize = 0,
1557 case GlyphAction::kAccept: {
1560 boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
1561 acceptedBuffer[acceptedSize++] =
1565 case GlyphAction::kReject:
1566 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1573 return {acceptedBuffer.
first(acceptedSize),
1574 rejectedBuffer.
first(rejectedSize),
1575 boundingRect.
rect()};
1583 int acceptedSize = 0;
1584 int rejectedSize = 0;
1586 for (
const auto [glyphID,
pos] :
source) {
1593 case GlyphAction::kAccept:
1594 acceptedBuffer[acceptedSize++] = std::make_tuple(glyphID,
pos);
1596 case GlyphAction::kReject:
1597 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1603 return {acceptedBuffer.
first(acceptedSize), rejectedBuffer.
first(rejectedSize)};
1611 int acceptedSize = 0;
1612 int rejectedSize = 0;
1614 for (
const auto [glyphID,
pos] :
source) {
1621 case GlyphAction::kAccept:
1622 acceptedBuffer[acceptedSize++] = std::make_tuple(glyphID,
pos);
1624 case GlyphAction::kReject:
1625 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1631 return {acceptedBuffer.
first(acceptedSize), rejectedBuffer.
first(rejectedSize)};
1634#if !defined(SK_DISABLE_SDF_TEXT)
1635static std::tuple<SkStrikeSpec, SkScalar, sktext::gpu::SDFTMatrixRange>
1643 auto [dfFont, strikeToSourceScale, matrixRange] = control.
getSDFFont(font, deviceMatrix,
1647 dfPaint.setStrokeWidth(
paint.getStrokeWidth() / strikeToSourceScale);
1653 if (dashInfo.
fCount > 0) {
1655 std::vector<SkScalar> scaledIntervals(dashInfo.
fCount);
1656 dashInfo.
fIntervals = scaledIntervals.data();
1658 (void)pathEffect->asADash(&dashInfo);
1659 for (
SkScalar& interval : scaledIntervals) {
1660 interval /= strikeToSourceScale;
1663 scaledIntervals.size(),
1664 dashInfo.
fPhase / strikeToSourceScale);
1665 dfPaint.setPathEffect(scaledDashes);
1676 return std::make_tuple(std::move(strikeSpec), strikeToSourceScale, matrixRange);
1700#if !defined(SK_DISABLE_SDF_TEXT)
1716 acceptedPackedGlyphIDs.
resize(maxGlyphRunSize);
1717 acceptedGlyphIDs.
resize(maxGlyphRunSize);
1718 acceptedPositions.
resize(maxGlyphRunSize);
1719 acceptedFormats.
resize(maxGlyphRunSize);
1724 rejectedGlyphIDs.
resize(maxGlyphRunSize);
1725 rejectedPositions.
resize(maxGlyphRunSize);
1726 const auto rejectedBuffer =
SkMakeZip(rejectedGlyphIDs, rejectedPositions);
1731 for (
auto& glyphRun : glyphRunList) {
1733 const SkFont& runFont = glyphRun.font();
1735 const SkScalar approximateDeviceTextSize =
1739 glyphRunListLocation);
1744 approximateDeviceTextSize < maxMaskSize) {
1746#if !defined(SK_DISABLE_SDF_TEXT)
1750 const auto& [strikeSpec, strikeToSourceScale, matrixRange] =
1751 make_sdft_strike_spec(
1752 runFont, runPaint, deviceProps, positionMatrix,
1769 auto acceptedBuffer =
SkMakeZip(acceptedPackedGlyphIDs, acceptedPositions);
1770 auto [accepted, rejected, creationBounds] = prepare_for_SDFT_drawing(
1771 strike.
get(), creationMatrix,
source, acceptedBuffer, rejectedBuffer);
1774 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1775 container->fSubRuns.append(SDFTSubRun::Make(
1778 strike->strikePromise(),
1796 runFont, runPaint, deviceProps, scalerContextFlags, positionMatrix);
1800 auto acceptedBuffer =
SkMakeZip(acceptedPackedGlyphIDs,
1803 auto [accepted, rejected, creationBounds] = prepare_for_direct_mask_drawing(
1804 strike.
get(), positionMatrix,
source, acceptedBuffer, rejectedBuffer);
1807 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1808 auto addGlyphsWithSameFormat =
1809 [&, bounds = creationBounds](
1812 container->fSubRuns.append(
1813 DirectMaskSubRun::Make(bounds,
1815 container->initialPosition(),
1816 strike->strikePromise(),
1820 add_multi_mask_format(addGlyphsWithSameFormat, accepted);
1828 auto [strikeSpec, strikeToSourceScale] =
1834 auto acceptedBuffer =
SkMakeZip(acceptedGlyphIDs, acceptedPositions);
1835 auto [accepted, rejected] =
1836 prepare_for_drawable_drawing(strike.
get(),
source, acceptedBuffer, rejectedBuffer);
1839 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1840 container->fSubRuns.append(
1841 DrawableSubRun::Make(
1843 strikeToSourceScale,
1844 strike->strikePromise(),
1853 auto [strikeSpec, strikeToSourceScale] =
1859 auto acceptedBuffer =
SkMakeZip(acceptedGlyphIDs, acceptedPositions);
1860 auto [accepted, rejected] =
1861 prepare_for_path_drawing(strike.
get(),
source, acceptedBuffer, rejectedBuffer);
1864 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1865 container->fSubRuns.append(
1866 PathSubRun::Make(accepted,
1867 has_some_antialiasing(runFont),
1868 strikeToSourceScale,
1869 strike->strikePromise(),
1884 SkMatrix creationMatrix = positionMatrix;
1898 creationMatrix =
SkMatrix::Scale(perspectiveFactor, perspectiveFactor);
1902 static const constexpr SkScalar kMaxBilerpAtlasDimension =
1910 auto maxGlyphDimension = [&](
const SkMatrix& m) {
1912 runFont, runPaint, deviceProps, scalerContextFlags, m);
1916 find_maximum_glyph_dimension(gaugingStrike.
get(),
glyphs);
1923 return maxDimension;
1927 for (
SkScalar maxDimension = maxGlyphDimension(creationMatrix);
1928 kMaxBilerpAtlasDimension < maxDimension;
1929 maxDimension = maxGlyphDimension(creationMatrix))
1935 SkScalar reductionFactor = kMaxBilerpAtlasDimension / maxDimension;
1936 creationMatrix.
postScale(reductionFactor, reductionFactor);
1941 runFont, runPaint, deviceProps, scalerContextFlags, creationMatrix);
1945 auto acceptedBuffer =
1946 SkMakeZip(acceptedPackedGlyphIDs, acceptedPositions, acceptedFormats);
1947 auto [accepted, rejected, creationBounds] =
1948 prepare_for_mask_drawing(
1949 strike.
get(), creationMatrix,
source, acceptedBuffer, rejectedBuffer);
1952 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1954 auto addGlyphsWithSameFormat =
1955 [&, bounds = creationBounds](
1958 container->fSubRuns.append(
1959 TransformedMaskSubRun::Make(subrun,
1960 container->initialPosition(),
1961 strike->strikePromise(),
1967 add_multi_mask_format(addGlyphsWithSameFormat, accepted);
1980 for (
auto& subRun : fSubRuns) {
1981 subRun.draw(canvas, drawOrigin,
paint,
sk_ref_sp(subRunStorage), atlasDelegate);
1986 for (
const SubRun& subRun : fSubRuns) {
1987 if (!subRun.canReuse(
paint, positionMatrix)) {
1996 uint32_t glyphCount =
buffer.getArrayCount();
1999 if (!
buffer.validate(glyphCount != 0)) {
return {}; }
2002 if (!
buffer.validate(glyphCount <= INT_MAX &&
2003 BagOfBytes::WillCountFit<SkPoint>(glyphCount))) {
return {}; }
2006 if (!
buffer.readPointArray(positionsData, glyphCount)) {
return {}; }
2007 return {positionsData, glyphCount};
@ kGammaCorrect_DistanceFieldEffectFlag
@ kUseLCD_DistanceFieldEffectFlag
@ kPerspective_DistanceFieldEffectFlag
@ kSimilarity_DistanceFieldEffectFlag
@ kBGR_DistanceFieldEffectFlag
@ kScaleOnly_DistanceFieldEffectFlag
@ kAliased_DistanceFieldEffectFlag
#define SkDEBUGFAIL(message)
#define SK_DistanceFieldInset
constexpr SkEnumerate< Iter > SkMakeEnumerate(C &c)
static bool SkIsFinite(T x, Pack... values)
static bool isLCD(const SkScalerContextRec &rec)
bool SkPaintToGrPaintReplaceShader(GrRecordingContext *context, const GrColorInfo &dstColorInfo, const SkPaint &skPaint, const SkMatrix &ctm, std::unique_ptr< GrFragmentProcessor > shaderFP, const SkSurfaceProps &surfaceProps, GrPaint *grPaint)
bool SkPaintToGrPaint(GrRecordingContext *context, const GrColorInfo &dstColorInfo, const SkPaint &skPaint, const SkMatrix &ctm, const SkSurfaceProps &surfaceProps, GrPaint *grPaint)
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
SkMaskFilterBase * as_MFB(SkMaskFilter *mf)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
sk_sp< T > sk_ref_sp(T *obj)
#define SkScalarFloorToScalar(x)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
static bool SkPixelGeometryIsH(SkPixelGeometry geo)
static bool SkPixelGeometryIsBGR(SkPixelGeometry geo)
constexpr int SkCount(const Container &c)
constexpr int SkToInt(S x)
constexpr auto SkMakeZip(Ts &&... ts)
static SkScalar center(float pos0, float pos1)
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
static bool IsPixelAligned(const SkRect &rect)
bool isLinearlyBlended() const
std::unique_ptr< GrOp > Owner
const SkPMColor4f & getColor4f() const
int saveLayer(const SkRect *bounds, const SkPaint *paint)
void drawPath(const SkPath &path, const SkPaint &paint)
void concat(const SkMatrix &matrix)
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
void draw(SkCanvas *, const SkMatrix *=nullptr)
static SkScalar ApproximateTransformedTextSize(const SkFont &font, const SkMatrix &matrix, const SkPoint &textLocation)
@ kAntiAlias
may have transparent pixels on glyph edges
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
SkGlyphRect bounds() const
SkMask::Format maskFormat() const
uint16_t maxDimension() const
static constexpr uint16_t kSkSideTooBigForAtlas
skglyph::GlyphAction actionFor(skglyph::ActionType actionType) const
SkGlyphRect offset(SkScalar x, SkScalar y) const
SkGlyphRect inset(SkScalar dx, SkScalar dy) const
virtual bool asABlur(BlurRec *) const
static sk_sp< SkMaskFilter > MakeBlur(SkBlurStyle style, SkScalar sigma, bool respectCTM=true)
static SkScalar DifferentialAreaScale(const SkMatrix &m, const SkPoint &p)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
SkMatrix & postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
SkPoint mapPoint(SkPoint pt) const
static const SkMatrix & I()
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
bool isScaleTranslate() const
SkScalar getMaxScale() const
bool hasPerspective() const
bool isSimilarity(SkScalar tol=SK_ScalarNearlyZero) const
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
static SkColor ComputeLuminanceColor(const SkPaint &)
@ kStroke_Style
set to stroke geometry
SkScalar getStrokeWidth() const
@ kDash_DashType
fills in all of the info parameter
SkPath & setIsVolatile(bool isVolatile)
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
constexpr bool empty() const
static SkStrikeCache * GlobalStrikeCache()
sk_sp< sktext::StrikeForGPU > findOrCreateScopedStrike(sktext::StrikeForGPUCacheInterface *cache) const
static SkStrikeSpec MakeTransformMask(const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix)
static SkStrikeSpec MakeMask(const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix)
static std::tuple< SkStrikeSpec, SkScalar > MakePath(const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, SkScalerContextFlags scalerContextFlags)
bool isHairlineStyle() const
SkPixelGeometry pixelGeometry() const
constexpr SkZip last(size_t n) const
constexpr size_t size() const
constexpr SkZip first(size_t n) const
constexpr SkZip subspan(size_t offset, size_t count) const
constexpr bool empty() const
constexpr auto get() const
GrRecordingContext * recordingContext() const
const GrColorInfo & colorInfo() const
const SkSurfaceProps & surfaceProps() const
SkArenaAlloc * arenaAlloc()
void resize(size_t count)
SkRect sourceBounds() const
size_t maxGlyphRunSize() const
size_t totalGlyphCount() const
static std::optional< SkStrikePromise > MakeFromBuffer(SkReadBuffer &buffer, const SkStrikeClient *client, SkStrikeCache *strikeCache)
virtual SkGlyphDigest digestFor(skglyph::ActionType, SkPackedGlyphID)=0
virtual const SkGlyphPositionRoundingSpec & roundingSpec() const =0
virtual skgpu::MaskFormat maskFormat() const =0
virtual const VertexFiller & vertexFiller() const =0
virtual unsigned short instanceFlags() const =0
virtual int glyphSrcPadding() const =0
virtual void testingOnly_packedGlyphIDToGlyph(StrikeCache *cache) const =0
virtual std::tuple< bool, int > regenerateAtlas(int begin, int end, RegenerateAtlasDelegate) const =0
virtual int glyphCount() const =0
static GlyphVector Make(SkStrikePromise &&promise, SkSpan< const SkPackedGlyphID > glyphs, SubRunAllocator *alloc)
static size_t GlyphVectorSize(size_t count)
static std::optional< GlyphVector > MakeFromBuffer(SkReadBuffer &buffer, const SkStrikeClient *strikeClient, SubRunAllocator *alloc)
static skgpu::MaskFormat FormatFromSkGlyph(SkMask::Format format)
static sk_sp< SkMaskFilter > Make()
std::tuple< SkFont, SkScalar, SDFTMatrixRange > getSDFFont(const SkFont &font, const SkMatrix &viewMatrix, const SkPoint &textLocation) const
bool isSDFT(SkScalar approximateDeviceTextSize, const SkPaint &paint, const SkMatrix &matrix) const
static SDFTMatrixRange MakeFromBuffer(SkReadBuffer &buffer)
std::unique_ptr< T[], ArrayDestroyer > makeUniqueArray(int n)
std::unique_ptr< T, Destroyer > makeUnique(Args &&... args)
SkSpan< T > makePODSpan(SkSpan< const T > s)
static SubRunContainerOwner MakeInAlloc(const GlyphRunList &glyphRunList, const SkMatrix &positionMatrix, const SkPaint &runPaint, SkStrikeDeviceInfo strikeDeviceInfo, StrikeForGPUCacheInterface *strikeCache, sktext::gpu::SubRunAllocator *alloc, SubRunCreationBehavior creationBehavior, const char *tag)
static size_t EstimateAllocSize(const GlyphRunList &glyphRunList)
void flattenAllocSizeHint(SkWriteBuffer &buffer) const
static SubRunContainerOwner MakeFromBufferInAlloc(SkReadBuffer &buffer, const SkStrikeClient *client, SubRunAllocator *alloc)
void draw(SkCanvas *, SkPoint drawOrigin, const SkPaint &, const SkRefCnt *subRunStorage, const AtlasDrawDelegate &) const
void flattenRuns(SkWriteBuffer &buffer) const
static int AllocSizeHintFromBuffer(SkReadBuffer &buffer)
bool canReuse(const SkPaint &paint, const SkMatrix &positionMatrix) const
virtual void doFlatten(SkWriteBuffer &buffer) const =0
virtual int unflattenSize() const =0
virtual void draw(SkCanvas *, SkPoint drawOrigin, const SkPaint &, sk_sp< SkRefCnt > subRunStorage, const AtlasDrawDelegate &) const =0
virtual bool canReuse(const SkPaint &paint, const SkMatrix &positionMatrix) const =0
void flatten(SkWriteBuffer &buffer) const
virtual SubRunStreamTag subRunStreamTag() const =0
virtual const AtlasSubRun * testingOnly_atlasSubRun() const =0
static SubRunOwner MakeFromBuffer(SkReadBuffer &buffer, sktext::gpu::SubRunAllocator *alloc, const SkStrikeClient *client)
static std::optional< VertexFiller > MakeFromBuffer(SkReadBuffer &buffer, SubRunAllocator *alloc)
static VertexFiller Make(skgpu::MaskFormat maskType, const SkMatrix &creationMatrix, SkRect creationBounds, SkSpan< const SkPoint > positions, SubRunAllocator *alloc, FillerType fillerType)
std::tuple< bool, SkRect > deviceRectAndCheckTransform(const SkMatrix &positionMatrix) const
void flatten(SkWriteBuffer &buffer) const
static const char * begin(const StringSlice &s)
FlutterSemanticsFlag flags
static const uint8_t buffer[]
uint32_t uint32_t * format
std::unique_ptr< SubRun, SubRunAllocator::Destroyer > SubRunOwner
std::function< std::tuple< bool, int >(GlyphVector *, int begin, int end, skgpu::MaskFormat, int padding)> RegenerateAtlasDelegate
std::unique_ptr< SubRunContainer, SubRunAllocator::Destroyer > SubRunContainerOwner
std::function< void(const sktext::gpu::AtlasSubRun *subRun, SkPoint drawOrigin, const SkPaint &paint, sk_sp< SkRefCnt > subRunStorage, sktext::gpu::RendererData)> AtlasDrawDelegate
@ kTransformMaskStreamTag
SkMatrix position_matrix(const SkMatrix &drawMatrix, SkPoint drawOrigin)
const SkVector halfAxisSampleFreq
const SkIPoint ignorePositionFieldMask
static constexpr SkIRect MakeEmpty()
SkScalar fPhase
Offset into the dashed interval pattern.
int32_t fCount
Number of intervals in the dash. Should be even number.
SkScalar * fIntervals
Length of on/off intervals for dashed lines.
constexpr float y() const
constexpr float x() const
bool intersects(const SkRect &r) const
void round(SkIRect *dst) const
constexpr SkPoint center() const
static constexpr SkRect MakeWH(float w, float h)
const SkSurfaceProps fSurfaceProps
const SkScalerContextFlags fScalerContextFlags
const sktext::gpu::SDFTControl *const fSDFTControl