40 auto val = std::fabs(
a);
43 }
else if (val < 100000) {
52 if (
a.start ==
b.start &&
a.end ==
b.end)
return a;
60 , fParagraphStyle(
std::move(style))
61 , fAlphabeticBaseline(0)
62 , fIdeographicBaseline(0)
65 , fMaxIntrinsicWidth(0)
66 , fMinIntrinsicWidth(0)
68 , fExceededMaxLines(0)
80 , fTextStyles(
std::move(blocks))
81 , fPlaceholders(
std::move(placeholders))
84 , fUnresolvedGlyphs(0)
86 , fStrutMetrics(
false)
90 , fHasLineBreaks(
false)
91 , fHasWhitespacesInside(
false)
106 std::move(placeholders),
121 return fUnresolvedGlyphs;
125 return fUnresolvedCodepoints;
132 fUnresolvedCodepoints.emplace(unichar);
139 auto floorWidth = rawWidth;
146 fLines.size() == 1 && fLines.front().ellipsis() ==
nullptr) {
151 }
else if (fState >=
kLineBroken && fOldWidth != floorWidth) {
169 this->fClusters.clear();
170 this->fClustersIndexFromCodeUnit.
clear();
176 this->computeEmptyMetrics();
177 this->fLines.clear();
191 this->fOldWidth = floorWidth;
192 this->fOldHeight = this->
fHeight;
206 this->computeEmptyMetrics();
207 this->fLines.clear();
219 this->fOldWidth = floorWidth;
220 this->fOldHeight = this->
fHeight;
249 for (
auto&
line : fLines) {
250 line.paint(painter,
x,
y);
262 fMaxWidthWithTrailingSpaces = 0;
269 if (
nullptr == fUnicode) {
285 this->paragraphStyle().getReplaceTabCharacters(),
286 &fCodeUnitProperties)) {
291 fTrailingSpaces = fText.
size();
293 for (
int i = 0;
i < fCodeUnitProperties.
size(); ++
i) {
294 auto flags = fCodeUnitProperties[
i];
296 if (fTrailingSpaces == fText.
size()) {
303 fTrailingSpaces = fText.
size();
306 fHasLineBreaks =
true;
310 if (firstWhitespace < fTrailingSpaces) {
311 fHasWhitespacesInside =
true;
330#define M(shift) (1 << (shift))
331 constexpr uint32_t kSpaceMask =
M(kHT) |
M(kLF) |
M(kVT) |
M(kFF) |
M(kCR);
333 return (c == kSP) || (c <= 31 && (kSpaceMask &
M(c)));
345 , fRunIndex(runIndex)
352 , fHalfLetterSpacing(0.0)
353 , fIsIdeographic(
false) {
354 size_t whiteSpacesBreakLen = 0;
355 size_t intraWordBreakLen = 0;
357 const char* ch =
text.begin();
358 if (
text.end() - ch == 1 && *(
const unsigned char*)ch <= 0x7F) {
361 ++whiteSpacesBreakLen;
364 for (
auto i = fTextRange.
start;
i < fTextRange.
end; ++
i) {
366 ++whiteSpacesBreakLen;
372 fIsIdeographic =
true;
377 fIsWhiteSpaceBreak = whiteSpacesBreakLen == fTextRange.
width();
378 fIsIntraWordBreak = intraWordBreakLen == fTextRange.
width();
380 SkUnicode::CodeUnitFlags::kHardLineBreakBefore);
386 auto correction = 0.0f;
389 correction = fJustificationShifts[
end - 1].fX -
390 fJustificationShifts[
start].fY;
400 size_t letterSpacingStyles = 0;
401 bool hasWordSpacing =
false;
402 for (
auto&
block : fTextStyles) {
405 ++letterSpacingStyles;
408 hasWordSpacing =
true;
413 if (letterSpacingStyles == 0 && !hasWordSpacing) {
419 if (letterSpacingStyles == 1 && !hasWordSpacing && fTextStyles.size() == 1 &&
420 fTextStyles[0].fRange.width() == fText.
size() && fRuns.size() == 1) {
422 auto&
run = fRuns[0];
423 auto& style = fTextStyles[0].fStyle;
424 run.addSpacesEvenly(style.getLetterSpacing());
427 for (
auto&
cluster : fClusters) {
440 bool soFarWhitespacesOnly =
true;
441 bool wordSpacingPending =
false;
442 Cluster* lastSpaceCluster =
nullptr;
443 for (
auto&
run : fRuns) {
446 if (
run.isPlaceholder()) {
450 run.iterateThroughClusters([
this, &
run, &shift, &soFarWhitespacesOnly, &wordSpacingPending, &lastSpaceCluster](
Cluster*
cluster) {
455 Block* currentStyle = fTextStyles.begin();
458 SkASSERT(currentStyle != fTextStyles.end());
465 if (cluster->isWhitespaceBreak() && cluster->isSoftBreak()) {
466 if (!soFarWhitespacesOnly) {
467 lastSpaceCluster = cluster;
468 wordSpacingPending = true;
470 }
else if (wordSpacingPending) {
472 if (
cluster->fRunIndex != lastSpaceCluster->fRunIndex) {
475 lastSpaceCluster->run().addSpacesAtTheEnd(spacing, lastSpaceCluster);
476 lastSpaceCluster->run().extend(lastSpaceCluster, spacing);
478 run.addSpacesAtTheEnd(spacing, lastSpaceCluster);
483 wordSpacingPending =
false;
487 if (currentStyle->fStyle.getLetterSpacing() != 0) {
488 shift += run.addSpacesEvenly(currentStyle->fStyle.getLetterSpacing(), cluster);
492 soFarWhitespacesOnly = false;
499void ParagraphImpl::buildClusterTable() {
503 int cluster_count = 1;
504 for (
auto&
run : fRuns) {
505 cluster_count +=
run.isPlaceholder() ? 1 :
run.size();
506 fCodeUnitProperties[
run.fTextRange.start] |= SkUnicode::CodeUnitFlags::kGraphemeStart;
507 fCodeUnitProperties[
run.fTextRange.start] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
509 if (!fRuns.empty()) {
510 fCodeUnitProperties[fRuns.back().textRange().end] |= SkUnicode::CodeUnitFlags::kGraphemeStart;
511 fCodeUnitProperties[fRuns.back().textRange().end] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
513 fClusters.reserve_exact(fClusters.size() + cluster_count);
516 for (
auto&
run : fRuns) {
517 auto runIndex =
run.index();
518 auto runStart = fClusters.size();
519 if (
run.isPlaceholder()) {
521 for (
auto i =
run.textRange().start;
i <
run.textRange().end; ++
i) {
522 fClustersIndexFromCodeUnit[
i] = fClusters.size();
525 fClusters.emplace_back(
this, runIndex, 0ul, 1ul, this->
text(
run.textRange()),
run.advance().fX,
run.advance().fY);
526 fCodeUnitProperties[
run.textRange().start] |= SkUnicode::CodeUnitFlags::kSoftLineBreakBefore;
527 fCodeUnitProperties[
run.textRange().end] |= SkUnicode::CodeUnitFlags::kSoftLineBreakBefore;
530 run.iterateThroughClustersInTextOrder([runIndex,
this](
size_t glyphStart,
538 for (
auto i = charStart;
i < charEnd; ++
i) {
539 fClustersIndexFromCodeUnit[
i] = fClusters.size();
542 fClusters.emplace_back(
this, runIndex, glyphStart, glyphEnd,
text,
width,
height);
543 fCodeUnitProperties[charStart] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
546 fCodeUnitProperties[
run.textRange().start] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
548 run.setClusterRange(runStart, fClusters.size());
549 fMaxIntrinsicWidth +=
run.advance().fX;
551 fClustersIndexFromCodeUnit[fText.size()] = fClusters.size();
552 fClusters.emplace_back(
this,
EMPTY_RUN, 0, 0, this->
text({fText.size(), fText.size()}), 0, 0);
555bool ParagraphImpl::shapeTextIntoEndlessLine() {
557 if (fText.size() == 0) {
561 fUnresolvedCodepoints.clear();
562 fFontSwitches.clear();
568 this->applySpacingAndBuildClusterTable();
573void ParagraphImpl::breakShapedTextIntoLines(
SkScalar maxWidth) {
575 if (!fHasLineBreaks &&
576 !fHasWhitespacesInside &&
577 fPlaceholders.size() == 1 &&
578 fRuns.size() == 1 && fRuns[0].fAdvance.fX <= maxWidth) {
588 auto&
run = this->fRuns[0];
589 auto advance =
run.advance();
591 auto textExcludingSpaces =
TextRange(0, fTrailingSpaces);
594 auto disableFirstAscent = this->paragraphStyle().getTextHeightBehavior() &
596 auto disableLastDescent = this->paragraphStyle().getTextHeightBehavior() &
598 if (disableFirstAscent) {
599 metrics.fAscent = metrics.fRawAscent;
601 if (disableLastDescent) {
602 metrics.fDescent = metrics.fRawDescent;
604 if (this->strutEnabled()) {
605 this->strutMetrics().updateLineMetrics(metrics);
610 auto& cluster = fClusters[trailingSpaces];
611 if (!cluster.isWhitespaceBreak()) {
615 advance.fX -= cluster.width();
616 }
while (trailingSpaces != 0);
618 advance.fY = metrics.
height();
622 textExcludingSpaces, textRange, textRange,
623 clusterRange, clusterRangeWithGhosts,
run.advance().x(),
626 fLongestLine =
nearlyZero(advance.fX) ?
run.advance().fX : advance.fX;
627 fHeight = advance.fY;
629 fMaxIntrinsicWidth =
run.advance().fX;
630 fMinIntrinsicWidth = advance.fX;
631 fAlphabeticBaseline = fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline();
632 fIdeographicBaseline = fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline();
633 fExceededMaxLines =
false;
654 auto&
line = this->addLine(
offset, advance, textExcludingSpaces,
text, textWithNewlines, clusters, clustersWithGhosts, widthWithSpaces, metrics);
656 line.createEllipsis(maxWidth, this->getEllipsis(),
true);
661 fHeight = textWrapper.
height();
665 fAlphabeticBaseline = fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline();
666 fIdeographicBaseline = fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline();
670void ParagraphImpl::formatLines(
SkScalar maxWidth) {
671 auto effectiveAlign = fParagraphStyle.effective_align();
672 const bool isLeftAligned = effectiveAlign == TextAlign::kLeft
673 || (effectiveAlign == TextAlign::kJustify && fParagraphStyle.getTextDirection() == TextDirection::kLtr);
675 if (!
SkIsFinite(maxWidth) && !isLeftAligned) {
682 for (
auto&
line : fLines) {
683 line.format(effectiveAlign, maxWidth);
687void ParagraphImpl::resolveStrut() {
688 auto strutStyle = this->paragraphStyle().getStrutStyle();
689 if (!strutStyle.getStrutEnabled() || strutStyle.getFontSize() < 0) {
693 std::vector<sk_sp<SkTypeface>> typefaces = fFontCollection->findTypefaces(strutStyle.getFontFamilies(), strutStyle.getFontStyle(), std::nullopt);
694 if (typefaces.empty()) {
695 SkDEBUGF(
"Could not resolve strut font\n");
699 SkFont font(typefaces.front(), strutStyle.getFontSize());
701 font.getMetrics(&metrics);
702 const SkScalar strutLeading = strutStyle.getLeading() < 0 ? 0 : strutStyle.getLeading() * strutStyle.getFontSize();
704 if (strutStyle.getHeightOverride()) {
708 if (strutStyle.getHalfLeading()) {
710 auto flexibleHeight = strutStyle.getHeight() * strutStyle.getFontSize() - occupiedHeight;
713 strutAscent = metrics.
fAscent - flexibleHeight;
714 strutDescent = metrics.
fDescent + flexibleHeight;
717 const auto strutHeightMultiplier = strutMetricsHeight == 0
718 ? strutStyle.getHeight()
719 : strutStyle.getHeight() * strutStyle.getFontSize() / strutMetricsHeight;
720 strutAscent = metrics.
fAscent * strutHeightMultiplier;
721 strutDescent = metrics.
fDescent * strutHeightMultiplier;
734 fStrutMetrics.setForceStrut(this->paragraphStyle().getStrutStyle().getForceStrutHeight());
740 for (
int index = 0; index < fTextStyles.size(); ++index) {
741 auto& block = fTextStyles[index];
742 if (block.fRange.end <= textRange.
start) {
745 if (block.fRange.start >= textRange.
end) {
773 auto blocks = findAllBlocks(textExcludingSpaces);
774 return fLines.emplace_back(
this,
offset, advance, blocks,
775 textExcludingSpaces,
text, textIncludingNewLines,
776 clusters, clustersWithGhosts, widthWithSpaces, sizes);
781std::vector<TextBox> ParagraphImpl::getRectsForRange(
unsigned start,
785 std::vector<TextBox> results;
786 if (fText.isEmpty()) {
790 results.emplace_back(
SkRect::MakeXYWH(0, 0, 0, fHeight), fParagraphStyle.getTextDirection());
795 this->ensureUTF16Mapping();
814 auto utf8 = fUTF8IndexForUTF16Index[
start];
817 utf8 = fUTF8IndexForUTF16Index[
start + 1];
819 text.start = this->findNextGraphemeBoundary(
utf8);
822 auto utf8 = this->findPreviousGraphemeBoundary(fUTF8IndexForUTF16Index[
end]);
826 for (
auto&
line : fLines) {
827 auto lineText =
line.textWithNewlines();
833 line.getRectsForRange(
intersect, rectHeightStyle, rectWidthStyle, results);
848std::vector<TextBox> ParagraphImpl::getRectsForPlaceholders() {
849 std::vector<TextBox> boxes;
850 if (fText.isEmpty()) {
853 if (fPlaceholders.size() == 1) {
857 for (
auto&
line : fLines) {
858 line.getRectsForPlaceholders(boxes);
877 if (fText.isEmpty()) {
881 this->ensureUTF16Mapping();
883 for (
auto&
line : fLines) {
908 if (fWords.empty()) {
909 if (!fUnicode->getWords(fText.c_str(), fText.size(),
nullptr, &fWords)) {
916 for (
size_t i = 0;
i < fWords.size(); ++
i) {
917 auto word = fWords[
i];
931void ParagraphImpl::getLineMetrics(std::vector<LineMetrics>& metrics) {
933 for (
auto&
line : fLines) {
934 metrics.emplace_back(
line.getMetrics());
952 return fClusters[clusterIndex];
956 auto start = cluster(clusterIndex);
968 return fTextStyles[blockIndex];
972 if (fState <=
state) {
1010void ParagraphImpl::computeEmptyMetrics() {
1018 bool emptyParagraph = fRuns.empty();
1019 TextStyle textStyle = paragraphStyle().getTextStyle();
1020 if (emptyParagraph && !fTextStyles.empty()) {
1021 textStyle = fTextStyles.back().fStyle;
1024 auto typefaces = fontCollection()->findTypefaces(
1026 auto typeface = typefaces.empty() ? nullptr : typefaces.front();
1029 fEmptyMetrics = InternalLineMetrics(
font, paragraphStyle().getStrutStyle().getForceStrutHeight());
1031 if (!paragraphStyle().getStrutStyle().getForceStrutHeight() &&
1033 const auto intrinsicHeight = fEmptyMetrics.height();
1035 if (paragraphStyle().getStrutStyle().getHalfLeading()) {
1036 fEmptyMetrics.update(
1037 fEmptyMetrics.ascent(),
1038 fEmptyMetrics.descent(),
1039 fEmptyMetrics.leading() + strutHeight - intrinsicHeight);
1041 const auto multiplier = strutHeight / intrinsicHeight;
1042 fEmptyMetrics.update(
1043 fEmptyMetrics.ascent() * multiplier,
1044 fEmptyMetrics.descent() * multiplier,
1045 fEmptyMetrics.leading() * multiplier);
1049 if (emptyParagraph) {
1055 fEmptyMetrics.update(
1056 disableFirstAscent ? fEmptyMetrics.rawAscent() : fEmptyMetrics.ascent(),
1057 disableLastDescent ? fEmptyMetrics.rawDescent() : fEmptyMetrics.descent(),
1058 fEmptyMetrics.leading());
1061 if (fParagraphStyle.getStrutStyle().getStrutEnabled()) {
1062 fStrutMetrics.updateLineMetrics(fEmptyMetrics);
1068 auto ellipsis8 = fParagraphStyle.getEllipsis();
1069 auto ellipsis16 = fParagraphStyle.getEllipsisUtf16();
1070 if (!ellipsis8.isEmpty()) {
1077void ParagraphImpl::updateFontSize(
size_t from,
size_t to,
SkScalar fontSize) {
1079 SkASSERT(from == 0 && to == fText.size());
1080 auto defaultStyle = fParagraphStyle.getTextStyle();
1081 defaultStyle.setFontSize(fontSize);
1082 fParagraphStyle.setTextStyle(defaultStyle);
1084 for (
auto& textStyle : fTextStyles) {
1094 fParagraphStyle.setTextAlign(textAlign);
1101void ParagraphImpl::updateForegroundPaint(
size_t from,
size_t to,
SkPaint paint) {
1102 SkASSERT(from == 0 && to == fText.size());
1103 auto defaultStyle = fParagraphStyle.getTextStyle();
1104 defaultStyle.setForegroundColor(
paint);
1105 fParagraphStyle.setTextStyle(defaultStyle);
1107 for (
auto& textStyle : fTextStyles) {
1112void ParagraphImpl::updateBackgroundPaint(
size_t from,
size_t to,
SkPaint paint) {
1113 SkASSERT(from == 0 && to == fText.size());
1114 auto defaultStyle = fParagraphStyle.getTextStyle();
1115 defaultStyle.setBackgroundColor(
paint);
1116 fParagraphStyle.setTextStyle(defaultStyle);
1118 for (
auto& textStyle : fTextStyles) {
1126 if ((fCodeUnitProperties[textRange.
start] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1130 for (
auto index = textRange.
start; index < textRange.
end; ++index) {
1131 if ((fCodeUnitProperties[index] & SkUnicode::CodeUnitFlags::kGraphemeStart) != 0) {
1140 (fCodeUnitProperties[
utf8] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1147 while (
utf8 < fText.size() &&
1148 (fCodeUnitProperties[
utf8] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1155 while (
utf8 < fText.size() &&
1156 (fCodeUnitProperties[
utf8] & SkUnicode::CodeUnitFlags::kGlyphClusterStart) == 0) {
1164 (fCodeUnitProperties[
utf8] & SkUnicode::CodeUnitFlags::kGlyphClusterStart) == 0) {
1170void ParagraphImpl::ensureUTF16Mapping() {
1171 fillUTF16MappingOnce([&] {
1174 [&](
size_t index) { fUTF8IndexForUTF16Index.emplace_back(index); },
1175 [&](
size_t index) { fUTF16IndexForUTF8Index.emplace_back(index); });
1179void ParagraphImpl::visit(
const Visitor& visitor) {
1181 for (
auto&
line : fLines) {
1182 line.ensureTextBlobCachePopulated();
1183 for (
auto& rec :
line.fTextBlobCache) {
1184 if (rec.fBlob ==
nullptr) {
1191 const Run*
R = rec.fVisitor_Run;
1192 const uint32_t* clusterPtr = &
R->fClusterIndexes[0];
1194 if (
R->fClusterStart > 0) {
1195 int count =
R->fClusterIndexes.size();
1198 clusterStorage[
i] =
R->fClusterStart +
R->fClusterIndexes[
i];
1200 clusterPtr = &clusterStorage[0];
1202 clusterPtr += rec.fVisitor_Pos;
1208 rec.fClipRect.fRight,
1215 visitor(lineNumber, &
info);
1216 clusterPtr +=
run.count;
1219 visitor(lineNumber,
nullptr);
1224int ParagraphImpl::getLineNumberAt(
TextIndex codeUnitIndex)
const {
1225 if (codeUnitIndex >= fText.size()) {
1228 size_t startLine = 0;
1229 size_t endLine = fLines.size() - 1;
1230 if (fLines.empty() || fLines[endLine].textWithNewlines().end <= codeUnitIndex) {
1234 while (endLine > startLine) {
1236 const size_t midLine = (endLine + startLine) / 2;
1237 const TextRange midLineRange = fLines[midLine].textWithNewlines();
1238 if (codeUnitIndex < midLineRange.
start) {
1239 endLine = midLine - 1;
1240 }
else if (midLineRange.
end <= codeUnitIndex) {
1241 startLine = midLine + 1;
1250int ParagraphImpl::getLineNumberAtUTF16Offset(
size_t codeUnitIndex) {
1251 this->ensureUTF16Mapping();
1252 if (codeUnitIndex >=
SkToSizeT(fUTF8IndexForUTF16Index.size())) {
1255 const TextIndex utf8 = fUTF8IndexForUTF16Index[codeUnitIndex];
1256 return getLineNumberAt(
utf8);
1259bool ParagraphImpl::getLineMetricsAt(
int lineNumber,
LineMetrics* lineMetrics)
const {
1260 if (lineNumber < 0 || lineNumber >= fLines.size()) {
1263 auto&
line = fLines[lineNumber];
1265 *lineMetrics =
line.getMetrics();
1270TextRange ParagraphImpl::getActualTextRange(
int lineNumber,
bool includeSpaces)
const {
1271 if (lineNumber < 0 || lineNumber >= fLines.size()) {
1274 auto&
line = fLines[lineNumber];
1275 return includeSpaces ?
line.text() :
line.trimmedText();
1279 const int lineNumber = getLineNumberAt(codeUnitIndex);
1280 if (lineNumber == -1) {
1283 auto&
line = fLines[lineNumber];
1284 for (
auto c =
line.clustersWithSpaces().start; c <
line.clustersWithSpaces().end; ++c) {
1285 auto& cluster = fClusters[c];
1286 if (cluster.contains(codeUnitIndex)) {
1287 std::vector<TextBox> boxes;
1288 line.getRectsForRange(cluster.textRange(),
1289 RectHeightStyle::kTight,
1290 RectWidthStyle::kTight,
1292 if (!boxes.empty()) {
1294 *glyphInfo = {boxes[0].rect, cluster.textRange(), boxes[0].direction};
1309 this->ensureUTF16Mapping();
1311 return this->getGlyphClusterAt(fUTF8IndexForUTF16Index[utf16Offset], glyphInfo);
1314bool ParagraphImpl::getGlyphInfoAtUTF16Offset(
size_t codeUnitIndex,
GlyphInfo* glyphInfo) {
1315 this->ensureUTF16Mapping();
1316 if (codeUnitIndex >=
SkToSizeT(fUTF8IndexForUTF16Index.size())) {
1319 const TextIndex utf8 = fUTF8IndexForUTF16Index[codeUnitIndex];
1320 const int lineNumber = getLineNumberAt(
utf8);
1321 if (lineNumber == -1) {
1324 if (glyphInfo ==
nullptr) {
1328 const TextIndex startIndex = findPreviousGraphemeBoundary(
utf8);
1329 const TextIndex endIndex = findNextGraphemeBoundary(
utf8 + 1);
1331 const Cluster& glyphCluster = cluster(glyphClusterIndex);
1334 std::vector<TextBox> boxes;
1335 line.getRectsForRange({startIndex, endIndex}, RectHeightStyle::kTight, RectWidthStyle::kTight, boxes);
1339 if (glyphInfo && !boxes.empty()) {
1342 { fUTF16IndexForUTF8Index[startIndex], fUTF16IndexForUTF8Index[endIndex] },
1354 return getGlyphInfoAtUTF16Offset(utf16Offset, glyphInfo);
1358 for (
auto&
run : fRuns) {
1359 const auto textRange =
run.textRange();
1360 if (textRange.start <= codeUnitIndex && codeUnitIndex < textRange.end) {
1367SkFont ParagraphImpl::getFontAtUTF16Offset(
size_t codeUnitIndex) {
1368 ensureUTF16Mapping();
1369 if (codeUnitIndex >=
SkToSizeT(fUTF8IndexForUTF16Index.size())) {
1372 const TextIndex utf8 = fUTF8IndexForUTF16Index[codeUnitIndex];
1373 for (
auto&
run : fRuns) {
1374 const auto textRange =
run.textRange();
1375 if (textRange.start <=
utf8 &&
utf8 < textRange.end) {
1382std::vector<Paragraph::FontInfo> ParagraphImpl::getFonts()
const {
1383 std::vector<FontInfo> results;
1384 for (
auto&
run : fRuns) {
1385 results.emplace_back(
run.font(),
run.textRange());
1392 for (
auto&
line : fLines) {
1393 line.iterateThroughVisualRuns(
1399 *runWidthInLine =
line.iterateThroughSingleRunByStyles(
1400 TextLine::TextAdjustment::GlyphCluster,
1412 line.offset().fY + correctedBaseline);
1416 run->font().getBounds(
run->glyphs().data(),
1421 const uint32_t* clusterPtr =
run->clusterIndexes().data();
1422 if (
run->fClusterStart > 0) {
1424 for (
size_t i = 0;
i < context.
size; ++
i) {
1426 run->fClusterStart +
run->fClusterIndexes[
i];
1428 clusterPtr = &clusterStorage[0];
1435 &
run->glyphs()[context.
pos],
1436 &
run->fPositions[context.
pos],
1437 &glyphBounds[context.
pos],
1441 visitor(lineNumber, &
info);
1445 visitor(lineNumber,
nullptr);
1451 int notConverted = 0;
1452 auto&
line = fLines[lineNumber];
1453 line.iterateThroughVisualRuns(
1459 *runWidthInLine =
line.iterateThroughSingleRunByStyles(
1460 TextLine::TextAdjustment::GlyphCluster,
1473 line.offset().fY + correctedBaseline);
1482 &
run->positions()[context.
pos], 0};
1485 Rec* rec = reinterpret_cast<Rec*>(ctx);
1487 SkMatrix total = mx;
1488 total.postTranslate(rec->fPos->fX + rec->fOffset.fX,
1489 rec->fPos->fY + rec->fOffset.fY);
1490 rec->fPath->addPath(*path, total);
1492 rec->fNotConverted++;
1496 notConverted += rec.fNotConverted;
1501 return notConverted;
1507 while (!iter.
done()) {
1514 Rec* rec = (Rec*)ctx;
1517 tmp.postTranslate(rec->fPos->fX - rec->fOffset.fX,
1518 rec->fPos->fY - rec->fOffset.fY);
1519 rec->fDst->addPath(*src, tmp);
1534 this->getUnicode()->forEachCodepoint(iter.
text(), iter.
textSize(),
1536 if (this->getUnicode()->isEmoji(unichar)) {
1545bool ParagraphImpl::containsColorFontOrBitmap(
SkTextBlob* textBlob) {
1553 if (path == nullptr) {
1554 bool* flag1 = (bool*)ctx;
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static bool intersect(const SkPoint &p0, const SkPoint &n0, const SkPoint &p1, const SkPoint &n1, SkScalar *t)
static bool SkIsFinite(T x, Pack... values)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
#define SkScalarFloorToScalar(x)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
#define SkScalarRoundToScalar(x)
constexpr size_t SkToSizeT(S x)
constexpr int SkToInt(S x)
constexpr int16_t SkToS16(S x)
constexpr uint32_t SkToU32(S x)
void getPaths(const SkGlyphID glyphIDs[], int count, void(*glyphPathProc)(const SkPath *pathOrNull, const SkMatrix &mx, void *ctx), void *ctx) const
const char * c_str() const
const SkPoint * points() const
const uint16_t * glyphs() const
uint32_t glyphCount() const
uint32_t textSize() const
const SkFont & font() const
bool experimentalNext(ExperimentalRun *)
const SkRect & bounds() const
static bool hasPartOfWhiteSpaceBreakFlag(SkUnicode::CodeUnitFlags flags)
static bool hasHardLineBreakFlag(SkUnicode::CodeUnitFlags flags)
void forEachCodepoint(const char *utf8, int32_t utf8Units, Callback &&callback)
static SkString convertUtf16ToUtf8(const char16_t *utf16, int utf16Units)
static bool extractUtfConversionMapping(SkSpan< const char > utf8, Appender8 &&appender8, Appender16 &&appender16)
virtual bool getBidiRegions(const char utf8[], int utf8Units, TextDirection dir, std::vector< BidiRegion > *results)=0
virtual bool computeCodeUnitFlags(char utf8[], int utf8Units, bool replaceTabs, skia_private::TArray< SkUnicode::CodeUnitFlags, true > *results)=0
bool startsIn(TextRange text) const
void setHalfLetterSpacing(SkScalar halfLetterSpacing)
bool isWhitespaceBreak() const
SkScalar alphabeticBaseline() const
SkScalar ideographicBaseline() const
size_t unresolvedGlyphs()
void paint(SkCanvas *canvas, SkScalar x, SkScalar y) override
bool computeCodeUnitProperties()
void applySpacingAndBuildClusterTable()
~ParagraphImpl() override
bool codeUnitHasProperty(size_t index, SkUnicode::CodeUnitFlags property) const
Cluster & cluster(ClusterIndex clusterIndex)
bool getApplyRoundingHack() const
std::unordered_set< SkUnichar > unresolvedCodepoints() override
ParagraphImpl(const SkString &text, ParagraphStyle style, skia_private::TArray< Block, true > blocks, skia_private::TArray< Placeholder, true > placeholders, sk_sp< FontCollection > fonts, sk_sp< SkUnicode > unicode)
void breakShapedTextIntoLines(SkScalar maxWidth)
int32_t unresolvedGlyphs() override
void layout(SkScalar width) override
Block & block(BlockIndex blockIndex)
void addUnresolvedCodepoints(TextRange textRange)
void formatLines(SkScalar maxWidth)
bool shapeTextIntoEndlessLine()
SkScalar fIdeographicBaseline
SkScalar fAlphabeticBaseline
ParagraphStyle fParagraphStyle
Paragraph(ParagraphStyle style, sk_sp< FontCollection > fonts)
SkScalar fMaxIntrinsicWidth
SkScalar fMinIntrinsicWidth
sk_sp< FontCollection > fFontCollection
std::function< void(int lineNumber, const ExtendedVisitorInfo *)> ExtendedVisitor
std::function< void(int lineNumber, const VisitorInfo *)> Visitor
SkScalar calculateWidth(size_t start, size_t end, bool clip) const
SkScalar posX(size_t index) const
bool isPlaceholder() const
bool getHeightOverride() const
const std::vector< SkString > & getFontFamilies() const
SkFontStyle getFontStyle() const
SkScalar getHeight() const
SkScalar getBaselineShift() const
SkScalar getLetterSpacing() const
void setBackgroundColor(SkPaint paint)
void setFontSize(SkScalar size)
void setForegroundColor(SkPaint paint)
SkScalar getWordSpacing() const
const std::optional< FontArguments > & getFontArguments() const
SkScalar getFontSize() const
SkScalar minIntrinsicWidth() const
void breakTextIntoLines(ParagraphImpl *parent, SkScalar maxWidth, const AddLineToParagraph &addLine)
bool exceededMaxLines() const
SkScalar maxIntrinsicWidth() const
T & emplace_back(Args &&... args)
static const char * begin(const StringSlice &s)
FlutterSemanticsFlag flag
FlutterSemanticsFlag flags
static float max(float r, float g, float b)
static float min(float r, float g, float b)
sk_sp< SkBlender > blender SkRect rect
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
it will be possible to load the file into Perfetto s trace viewer disable asset fonts
font
Font Metadata and Metrics.
static bool is_ascii_7bit_space(int c)
TextRange operator*(const TextRange &a, const TextRange &b)
const SkRange< size_t > EMPTY_TEXT
SkRange< size_t > ClusterRange
const SkRange< size_t > EMPTY_RANGE
SkRange< size_t > TextRange
static bool nearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
SkScalar fLeading
distance to add between lines, typically positive or zero
SkScalar fAscent
distance to reserve above baseline, typically negative
SkScalar fDescent
distance to reserve below baseline, typically positive
static constexpr SkPoint Make(float x, float y)
constexpr float left() const
constexpr SkRect makeOffset(float dx, float dy) const
constexpr float top() const
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
static constexpr SkSize Make(SkScalar w, SkScalar h)
bool unlimited_lines() const
const StrutStyle & getStrutStyle() const
TextDirection getTextDirection() const
size_t getMaxLines() const
SkRange< size_t > intersection(SkRange< size_t > other) const
bool getForceStrutHeight() const
bool getStrutEnabled() const