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)) {}
380 accepted, isAntiAliased, strikeToSourceScale, std::move(strikePromise), alloc));
388 fPathDrawing.submitDraws(canvas, drawOrigin,
paint);
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)) {}
583 std::move(strikePromise),
596 fDrawingDrawing.submitDraws(canvas, drawOrigin,
paint);
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));
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:
806 const SkPMColor4f drawingColor = calculate_colors(sdc,
809 fVertexFiller.grMaskType(),
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());
856 auto [reuse, _] = fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
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; }
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; }
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(),
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 {
1045 fVertexFiller.flatten(
buffer);
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) {
1079 using MT = AtlasTextOp::MaskType;
1081 MT maskType = !isAntiAliased ? MT::kAliasedDistanceField
1082 :
isLCD ? MT::kLCDDistanceField
1083 : MT::kGrayscaleDistanceField;
1099 return {maskType, DFGPFlags, useGammaCorrectDistanceTable};
1106 SDFTSubRun(
bool useLCDText,
1111 : fUseLCDText{useLCDText}
1112 , fAntiAliased{antiAliased}
1113 , fMatrixRange{matrixRange}
1114 , fVertexFiller{std::move(vertexFiller)}
1115 , fGlyphs{std::move(
glyphs)} { }
1127 get_positions(accepted),
1132 std::move(strikePromise), get_packedIDs(accepted), alloc);
1136 has_some_antialiasing(runFont),
1138 std::move(vertexFiller),
1139 std::move(glyphVector));
1145 int useLCD =
buffer.readInt();
1146 int isAntiAliased =
buffer.readInt();
1149 if (!
buffer.validate(vertexFiller.has_value())) {
return nullptr; }
1150 if (!
buffer.validate(vertexFiller.value().grMaskType() == MaskFormat::kA8)) {
1154 if (!
buffer.validate(glyphVector.has_value())) {
return nullptr; }
1155 if (!
buffer.validate(
SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
1161 std::move(*vertexFiller),
1162 std::move(*glyphVector));
1165 int unflattenSize()
const override {
1166 return sizeof(SDFTSubRun) + fGlyphs.unflattenSize() + fVertexFiller.unflattenSize();
1170 return fMatrixRange.matrixInRange(positionMatrix);
1173 const AtlasSubRun* testingOnly_atlasSubRun()
const override {
return this; }
1176 fGlyphs.packedGlyphIDToGlyph(
cache);
1179 int glyphCount()
const override {
return fVertexFiller.count(); }
1181 SkASSERT(fVertexFiller.grMaskType() == MaskFormat::kA8);
1182 return MaskFormat::kA8;
1187 return fGlyphs.glyphs();
1190 unsigned short instanceFlags()
const override {
1191 return (
unsigned short)MaskFormat::kA8;
1200 {
true, fUseLCDText});
1203#if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
1204 size_t vertexStride(
const SkMatrix& drawMatrix)
const override {
1205 return fVertexFiller.vertexStride(drawMatrix);
1208 std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
1224 auto [maskType, DFGPFlags, useGammaCorrectDistanceTable] =
1225 calculate_sdf_parameters(*sdc, viewMatrix, fUseLCDText, fAntiAliased);
1231 std::move(subRunStorage),
1237 auto [_, deviceRect] = fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
1238 GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1244 useGammaCorrectDistanceTable,
1247 std::move(grPaint));
1249 return {
clip, std::move(op)};
1252 void fillVertexData(
1269 std::tuple<bool, int> regenerateAtlas(
int begin,
int end,
1271 return regenerateAtlas(&fGlyphs,
begin,
end, MaskFormat::kA8, this->glyphSrcPadding());
1274 const VertexFiller& vertexFiller()
const override {
return fVertexFiller; }
1279 buffer.writeInt(fUseLCDText);
1280 buffer.writeInt(fAntiAliased);
1281 fMatrixRange.flatten(
buffer);
1282 fVertexFiller.flatten(
buffer);
1287 const bool fUseLCDText;
1288 const bool fAntiAliased;
1302template<
typename AddSingleMaskFormat>
1303void add_multi_mask_format(
1304 AddSingleMaskFormat addSingleMaskFormat,
1306 if (accepted.
empty()) {
return; }
1308 auto maskSpan = accepted.
get<2>();
1310 size_t startIndex = 0;
1311 for (
size_t i = 1;
i < accepted.
size();
i++) {
1313 if (
format != nextFormat) {
1314 auto interval = accepted.
subspan(startIndex,
i - startIndex);
1316 auto glyphsWithSameFormat =
SkMakeZip(interval.get<0>(), interval.get<1>());
1318 addSingleMaskFormat(glyphsWithSameFormat,
format);
1323 auto interval = accepted.
last(accepted.
size() - startIndex);
1324 auto glyphsWithSameFormat =
SkMakeZip(interval.get<0>(), interval.get<1>());
1325 addSingleMaskFormat(glyphsWithSameFormat,
format);
1345 DirectMaskSubRun::MakeFromBuffer,
1346#if !defined(SK_DISABLE_SDF_TEXT)
1347 SDFTSubRun::MakeFromBuffer,
1349 TransformedMaskSubRun::MakeFromBuffer,
1350 PathSubRun::MakeFromBuffer,
1351 DrawableSubRun::MakeFromBuffer,
1353 int subRunTypeInt =
buffer.readInt();
1358 auto maker = makers[subRunTypeInt];
1359 if (!
buffer.validate(maker !=
nullptr)) {
return nullptr; }
1360 return maker(
buffer, alloc, client);
1365 : fInitialPositionMatrix{initialPositionMatrix} {}
1368 int unflattenSizeHint = 0;
1369 for (
auto& subrun : fSubRuns) {
1370 unflattenSizeHint += subrun.unflattenSize();
1372 buffer.writeInt(unflattenSizeHint);
1376 int subRunsSizeHint =
buffer.readInt();
1380 if (subRunsSizeHint < 0 || (1 << 16) < subRunsSizeHint) {
1381 subRunsSizeHint = 128;
1383 return subRunsSizeHint;
1387 buffer.writeMatrix(fInitialPositionMatrix);
1388 int subRunCount = 0;
1389 for ([[maybe_unused]]
auto& subRun : fSubRuns) {
1392 buffer.writeInt(subRunCount);
1393 for (
auto& subRun : fSubRuns) {
1402 buffer.readMatrix(&positionMatrix);
1403 if (!
buffer.isValid()) {
return nullptr; }
1406 int subRunCount =
buffer.readInt();
1408 if (!
buffer.validate(subRunCount > 0)) {
return nullptr; }
1409 for (
int i = 0;
i < subRunCount; ++
i) {
1411 if (!
buffer.validate(subRunOwner !=
nullptr)) {
return nullptr; }
1412 if (subRunOwner !=
nullptr) {
1413 container->fSubRuns.append(std::move(subRunOwner));
1421 constexpr size_t alignDiff =
alignof(DirectMaskSubRun) -
alignof(
SkPoint);
1422 constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0;
1425 return totalGlyphCount *
sizeof(
SkPoint)
1427 + glyphRunList.
runCount() * (
sizeof(DirectMaskSubRun) + vertexDataToSubRunPadding)
1439 return maxDimension;
1442#if !defined(SK_DISABLE_SDF_TEXT)
1449 int acceptedSize = 0,
1453 for (
const auto [glyphID,
pos] :
source) {
1461 case GlyphAction::kAccept: {
1470 acceptedBuffer[acceptedSize++] = std::make_tuple(packedID, glyphBounds.
leftTop());
1473 case GlyphAction::kReject:
1474 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1481 return {acceptedBuffer.
first(acceptedSize),
1482 rejectedBuffer.
first(rejectedSize),
1483 boundingRect.
rect()};
1487std::tuple<SkZip<const SkPackedGlyphID, const SkPoint, const SkMask::Format>,
1500 SkMatrix positionMatrixWithRounding = positionMatrix;
1501 positionMatrixWithRounding.
postTranslate(halfSampleFreq.
x(), halfSampleFreq.
y());
1503 int acceptedSize = 0,
1516 case GlyphAction::kAccept: {
1521 acceptedBuffer[acceptedSize++] =
1522 std::make_tuple(packedID, glyphBounds.
leftTop(), digest.maskFormat());
1525 case GlyphAction::kReject:
1526 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1533 return {acceptedBuffer.
first(acceptedSize),
1534 rejectedBuffer.
first(rejectedSize),
1535 boundingRect.
rect()};
1538std::tuple<SkZip<const SkPackedGlyphID, const SkPoint, const SkMask::Format>,
1546 int acceptedSize = 0,
1558 case GlyphAction::kAccept: {
1562 acceptedBuffer[acceptedSize++] =
1563 std::make_tuple(packedID, glyphBounds.
leftTop(), digest.maskFormat());
1566 case GlyphAction::kReject:
1567 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1574 return {acceptedBuffer.
first(acceptedSize),
1575 rejectedBuffer.
first(rejectedSize),
1576 boundingRect.
rect()};
1584 int acceptedSize = 0;
1585 int rejectedSize = 0;
1587 for (
const auto [glyphID,
pos] :
source) {
1594 case GlyphAction::kAccept:
1595 acceptedBuffer[acceptedSize++] = std::make_tuple(glyphID,
pos);
1597 case GlyphAction::kReject:
1598 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1604 return {acceptedBuffer.
first(acceptedSize), rejectedBuffer.
first(rejectedSize)};
1612 int acceptedSize = 0;
1613 int rejectedSize = 0;
1615 for (
const auto [glyphID,
pos] :
source) {
1622 case GlyphAction::kAccept:
1623 acceptedBuffer[acceptedSize++] = std::make_tuple(glyphID,
pos);
1625 case GlyphAction::kReject:
1626 rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID,
pos);
1632 return {acceptedBuffer.
first(acceptedSize), rejectedBuffer.
first(rejectedSize)};
1635#if !defined(SK_DISABLE_SDF_TEXT)
1636static std::tuple<SkStrikeSpec, SkScalar, sktext::gpu::SDFTMatrixRange>
1644 auto [dfFont, strikeToSourceScale, matrixRange] = control.
getSDFFont(
font, deviceMatrix,
1648 dfPaint.setStrokeWidth(
paint.getStrokeWidth() / strikeToSourceScale);
1654 if (dashInfo.
fCount > 0) {
1656 std::vector<SkScalar> scaledIntervals(dashInfo.
fCount);
1657 dashInfo.
fIntervals = scaledIntervals.data();
1659 (void)pathEffect->asADash(&dashInfo);
1660 for (
SkScalar& interval : scaledIntervals) {
1661 interval /= strikeToSourceScale;
1664 scaledIntervals.size(),
1665 dashInfo.
fPhase / strikeToSourceScale);
1666 dfPaint.setPathEffect(scaledDashes);
1677 return std::make_tuple(std::move(strikeSpec), strikeToSourceScale, matrixRange);
1701#if !defined(SK_DISABLE_SDF_TEXT)
1717 acceptedPackedGlyphIDs.
resize(maxGlyphRunSize);
1718 acceptedGlyphIDs.
resize(maxGlyphRunSize);
1719 acceptedPositions.
resize(maxGlyphRunSize);
1720 acceptedFormats.
resize(maxGlyphRunSize);
1725 rejectedGlyphIDs.
resize(maxGlyphRunSize);
1726 rejectedPositions.
resize(maxGlyphRunSize);
1727 const auto rejectedBuffer =
SkMakeZip(rejectedGlyphIDs, rejectedPositions);
1732 for (
auto& glyphRun : glyphRunList) {
1734 const SkFont& runFont = glyphRun.font();
1736 const SkScalar approximateDeviceTextSize =
1740 glyphRunListLocation);
1745 approximateDeviceTextSize < maxMaskSize) {
1747#if !defined(SK_DISABLE_SDF_TEXT)
1751 const auto& [strikeSpec, strikeToSourceScale, matrixRange] =
1753 runFont, runPaint, deviceProps, positionMatrix,
1770 auto acceptedBuffer =
SkMakeZip(acceptedPackedGlyphIDs, acceptedPositions);
1772 strike.
get(), creationMatrix,
source, acceptedBuffer, rejectedBuffer);
1775 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1779 strike->strikePromise(),
1797 runFont, runPaint, deviceProps, scalerContextFlags, positionMatrix);
1801 auto acceptedBuffer =
SkMakeZip(acceptedPackedGlyphIDs,
1805 strike.
get(), positionMatrix,
source, acceptedBuffer, rejectedBuffer);
1808 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1809 auto addGlyphsWithSameFormat =
1810 [&,
bounds = creationBounds](
1813 container->fSubRuns.append(
1816 container->initialPosition(),
1817 strike->strikePromise(),
1821 add_multi_mask_format(addGlyphsWithSameFormat, accepted);
1829 auto [strikeSpec, strikeToSourceScale] =
1835 auto acceptedBuffer =
SkMakeZip(acceptedGlyphIDs, acceptedPositions);
1836 auto [accepted, rejected] =
1840 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1841 container->fSubRuns.append(
1844 strikeToSourceScale,
1845 strike->strikePromise(),
1854 auto [strikeSpec, strikeToSourceScale] =
1860 auto acceptedBuffer =
SkMakeZip(acceptedGlyphIDs, acceptedPositions);
1861 auto [accepted, rejected] =
1865 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1866 container->fSubRuns.append(
1868 has_some_antialiasing(runFont),
1869 strikeToSourceScale,
1870 strike->strikePromise(),
1885 SkMatrix creationMatrix = positionMatrix;
1899 creationMatrix =
SkMatrix::Scale(perspectiveFactor, perspectiveFactor);
1903 static const constexpr SkScalar kMaxBilerpAtlasDimension =
1911 auto maxGlyphDimension = [&](
const SkMatrix&
m) {
1913 runFont, runPaint, deviceProps, scalerContextFlags,
m);
1924 return maxDimension;
1928 for (
SkScalar maxDimension = maxGlyphDimension(creationMatrix);
1929 kMaxBilerpAtlasDimension < maxDimension;
1930 maxDimension = maxGlyphDimension(creationMatrix))
1936 SkScalar reductionFactor = kMaxBilerpAtlasDimension / maxDimension;
1937 creationMatrix.
postScale(reductionFactor, reductionFactor);
1942 runFont, runPaint, deviceProps, scalerContextFlags, creationMatrix);
1946 auto acceptedBuffer =
1947 SkMakeZip(acceptedPackedGlyphIDs, acceptedPositions, acceptedFormats);
1948 auto [accepted, rejected, creationBounds] =
1950 strike.
get(), creationMatrix,
source, acceptedBuffer, rejectedBuffer);
1953 if (creationBehavior ==
kAddSubRuns && !accepted.empty()) {
1955 auto addGlyphsWithSameFormat =
1956 [&,
bounds = creationBounds](
1959 container->fSubRuns.append(
1961 container->initialPosition(),
1962 strike->strikePromise(),
1968 add_multi_mask_format(addGlyphsWithSameFormat, accepted);
1981 for (
auto& subRun : fSubRuns) {
1982 subRun.draw(canvas, drawOrigin,
paint,
sk_ref_sp(subRunStorage), atlasDelegate);
1987 for (
const SubRun& subRun : fSubRuns) {
1988 if (!subRun.canReuse(
paint, positionMatrix)) {
1997 uint32_t glyphCount =
buffer.getArrayCount();
2000 if (!
buffer.validate(glyphCount != 0)) {
return {}; }
2003 if (!
buffer.validate(glyphCount <= INT_MAX &&
2004 BagOfBytes::WillCountFit<SkPoint>(glyphCount))) {
return {}; }
2007 if (!
buffer.readPointArray(positionsData, glyphCount)) {
return {}; }
2008 return {positionsData, glyphCount};
@ kGammaCorrect_DistanceFieldEffectFlag
@ kUseLCD_DistanceFieldEffectFlag
@ kPerspective_DistanceFieldEffectFlag
@ kSimilarity_DistanceFieldEffectFlag
@ kBGR_DistanceFieldEffectFlag
@ kScaleOnly_DistanceFieldEffectFlag
@ kAliased_DistanceFieldEffectFlag
@ kPortrait_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)
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)
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
@ kUnknown_SkPixelGeometry
static bool SkPixelGeometryIsBGR(SkPixelGeometry geo)
static bool SkPixelGeometryIsV(SkPixelGeometry geo)
constexpr int SkCount(const Container &c)
constexpr int SkToInt(S x)
constexpr auto SkMakeZip(Ts &&... ts)
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
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
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)
static const char * begin(const StringSlice &s)
FlutterSemanticsFlag flags
uint32_t uint32_t * format
static float max(float r, float g, float b)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
unsigned useCenter Optional< SkMatrix > matrix
Optional< SkRect > bounds
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
drawAtlas(r.atlas.get(), r.xforms, r.texs, r.colors, r.count, r.mode, r.sampling, r.cull, r.paint)) DRAW(DrawAnnotation
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 Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
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
font
Font Metadata and Metrics.
const myers::Point & get< 1 >(const myers::Segment &s)
SkGlyphRect rect_union(SkGlyphRect, SkGlyphRect)
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::tuple< SkZip< const SkPackedGlyphID, const SkPoint >, SkZip< SkGlyphID, SkPoint >, SkRect > prepare_for_SDFT_drawing(StrikeForGPU *strike, const SkMatrix &creationMatrix, SkZip< const SkGlyphID, const SkPoint > source, SkZip< SkPackedGlyphID, SkPoint > acceptedBuffer, SkZip< SkGlyphID, SkPoint > rejectedBuffer)
SkSpan< SkPoint > MakePointsFromBuffer(SkReadBuffer &buffer, SubRunAllocator *alloc)
std::tuple< SkZip< const SkGlyphID, const SkPoint >, SkZip< SkGlyphID, SkPoint > > prepare_for_drawable_drawing(StrikeForGPU *strike, SkZip< const SkGlyphID, const SkPoint > source, SkZip< SkGlyphID, SkPoint > acceptedBuffer, SkZip< SkGlyphID, SkPoint > rejectedBuffer)
SkScalar find_maximum_glyph_dimension(StrikeForGPU *strike, SkSpan< const SkGlyphID > glyphs)
std::tuple< SkZip< const SkGlyphID, const SkPoint >, SkZip< SkGlyphID, SkPoint > > prepare_for_path_drawing(StrikeForGPU *strike, SkZip< const SkGlyphID, const SkPoint > source, SkZip< SkGlyphID, SkPoint > acceptedBuffer, SkZip< SkGlyphID, SkPoint > rejectedBuffer)
std::tuple< SkZip< const SkPackedGlyphID, const SkPoint, const SkMask::Format >, SkZip< SkGlyphID, SkPoint >, SkRect > prepare_for_direct_mask_drawing(StrikeForGPU *strike, const SkMatrix &positionMatrix, SkZip< const SkGlyphID, const SkPoint > source, SkZip< SkPackedGlyphID, SkPoint, SkMask::Format > acceptedBuffer, SkZip< SkGlyphID, SkPoint > rejectedBuffer)
std::tuple< SkZip< const SkPackedGlyphID, const SkPoint, const SkMask::Format >, SkZip< SkGlyphID, SkPoint >, SkRect > prepare_for_mask_drawing(StrikeForGPU *strike, const SkMatrix &creationMatrix, SkZip< const SkGlyphID, const SkPoint > source, SkZip< SkPackedGlyphID, SkPoint, SkMask::Format > acceptedBuffer, SkZip< SkGlyphID, SkPoint > rejectedBuffer)
std::function< void(const sktext::gpu::AtlasSubRun *subRun, SkPoint drawOrigin, const SkPaint &paint, sk_sp< SkRefCnt > subRunStorage, sktext::gpu::RendererData)> AtlasDrawDelegate
@ kTransformMaskStreamTag
static std::tuple< SkStrikeSpec, SkScalar, sktext::gpu::SDFTMatrixRange > make_sdft_strike_spec(const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, const SkMatrix &deviceMatrix, const SkPoint &textLocation, const sktext::gpu::SDFTControl &control)
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