Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Public Member Functions | Friends | List of all members
skia::textlayout::ParagraphImpl Class Referencefinal

#include <ParagraphImpl.h>

Inheritance diagram for skia::textlayout::ParagraphImpl:
skia::textlayout::Paragraph

Public Member Functions

 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)
 
 ParagraphImpl (const std::u16string &utf16text, ParagraphStyle style, skia_private::TArray< Block, true > blocks, skia_private::TArray< Placeholder, true > placeholders, sk_sp< FontCollection > fonts, sk_sp< SkUnicode > unicode)
 
 ~ParagraphImpl () override
 
void layout (SkScalar width) override
 
void paint (SkCanvas *canvas, SkScalar x, SkScalar y) override
 
void paint (ParagraphPainter *canvas, SkScalar x, SkScalar y) override
 
std::vector< TextBoxgetRectsForRange (unsigned start, unsigned end, RectHeightStyle rectHeightStyle, RectWidthStyle rectWidthStyle) override
 
std::vector< TextBoxgetRectsForPlaceholders () override
 
void getLineMetrics (std::vector< LineMetrics > &) override
 
PositionWithAffinity getGlyphPositionAtCoordinate (SkScalar dx, SkScalar dy) override
 
SkRange< size_t > getWordBoundary (unsigned offset) override
 
bool getApplyRoundingHack () const
 
size_t lineNumber () override
 
TextLineaddLine (SkVector offset, SkVector advance, TextRange textExcludingSpaces, TextRange text, TextRange textIncludingNewlines, ClusterRange clusters, ClusterRange clustersWithGhosts, SkScalar widthWithSpaces, InternalLineMetrics sizes)
 
SkSpan< const char > text () const
 
InternalState state () const
 
SkSpan< Runruns ()
 
SkSpan< Blockstyles ()
 
SkSpan< Placeholderplaceholders ()
 
SkSpan< TextLinelines ()
 
const ParagraphStyleparagraphStyle () const
 
SkSpan< Clusterclusters ()
 
sk_sp< FontCollectionfontCollection () const
 
void formatLines (SkScalar maxWidth)
 
void ensureUTF16Mapping ()
 
skia_private::TArray< TextIndexcountSurroundingGraphemes (TextRange textRange) const
 
TextIndex findNextGraphemeBoundary (TextIndex utf8) const
 
TextIndex findPreviousGraphemeBoundary (TextIndex utf8) const
 
TextIndex findNextGlyphClusterBoundary (TextIndex utf8) const
 
TextIndex findPreviousGlyphClusterBoundary (TextIndex utf8) const
 
size_t getUTF16Index (TextIndex index) const
 
bool strutEnabled () const
 
bool strutForceHeight () const
 
bool strutHeightOverride () const
 
InternalLineMetrics strutMetrics () const
 
SkString getEllipsis () const
 
SkSpan< const char > text (TextRange textRange)
 
SkSpan< Clusterclusters (ClusterRange clusterRange)
 
Clustercluster (ClusterIndex clusterIndex)
 
ClusterIndex clusterIndex (TextIndex textIndex)
 
Runrun (RunIndex runIndex)
 
RunrunByCluster (ClusterIndex clusterIndex)
 
SkSpan< Blockblocks (BlockRange blockRange)
 
Blockblock (BlockIndex blockIndex)
 
skia_private::TArray< ResolvedFontDescriptorresolvedFonts () const
 
void markDirty () override
 
int32_t unresolvedGlyphs () override
 
std::unordered_set< SkUnicharunresolvedCodepoints () override
 
void addUnresolvedCodepoints (TextRange textRange)
 
void setState (InternalState state)
 
sk_sp< SkPicturegetPicture ()
 
SkScalar widthWithTrailingSpaces ()
 
void resetContext ()
 
void resolveStrut ()
 
bool computeCodeUnitProperties ()
 
void applySpacingAndBuildClusterTable ()
 
void buildClusterTable ()
 
bool shapeTextIntoEndlessLine ()
 
void breakShapedTextIntoLines (SkScalar maxWidth)
 
void updateTextAlign (TextAlign textAlign) override
 
void updateFontSize (size_t from, size_t to, SkScalar fontSize) override
 
void updateForegroundPaint (size_t from, size_t to, SkPaint paint) override
 
void updateBackgroundPaint (size_t from, size_t to, SkPaint paint) override
 
void visit (const Visitor &) override
 
void extendedVisit (const ExtendedVisitor &) override
 
int getPath (int lineNumber, SkPath *dest) override
 
bool containsColorFontOrBitmap (SkTextBlob *textBlob) override
 
bool containsEmoji (SkTextBlob *textBlob) override
 
int getLineNumberAt (TextIndex codeUnitIndex) const override
 
int getLineNumberAtUTF16Offset (size_t codeUnitIndex) override
 
bool getLineMetricsAt (int lineNumber, LineMetrics *lineMetrics) const override
 
TextRange getActualTextRange (int lineNumber, bool includeSpaces) const override
 
bool getGlyphClusterAt (TextIndex codeUnitIndex, GlyphClusterInfo *glyphInfo) override
 
bool getClosestGlyphClusterAt (SkScalar dx, SkScalar dy, GlyphClusterInfo *glyphInfo) override
 
bool getGlyphInfoAtUTF16Offset (size_t codeUnitIndex, GlyphInfo *graphemeInfo) override
 
bool getClosestUTF16GlyphInfoAt (SkScalar dx, SkScalar dy, GlyphInfo *graphemeInfo) override
 
SkFont getFontAt (TextIndex codeUnitIndex) const override
 
SkFont getFontAtUTF16Offset (size_t codeUnitIndex) override
 
std::vector< FontInfogetFonts () const override
 
InternalLineMetrics getEmptyMetrics () const
 
InternalLineMetrics getStrutMetrics () const
 
BlockRange findAllBlocks (TextRange textRange)
 
void resetShifts ()
 
bool codeUnitHasProperty (size_t index, SkUnicode::CodeUnitFlags property) const
 
sk_sp< SkUnicodegetUnicode ()
 
- Public Member Functions inherited from skia::textlayout::Paragraph
 Paragraph (ParagraphStyle style, sk_sp< FontCollection > fonts)
 
virtual ~Paragraph ()=default
 
SkScalar getMaxWidth ()
 
SkScalar getHeight ()
 
SkScalar getMinIntrinsicWidth ()
 
SkScalar getMaxIntrinsicWidth ()
 
SkScalar getAlphabeticBaseline ()
 
SkScalar getIdeographicBaseline ()
 
SkScalar getLongestLine ()
 
bool didExceedMaxLines ()
 

Friends

class ParagraphBuilder
 
class ParagraphCacheKey
 
class ParagraphCacheValue
 
class ParagraphCache
 
class TextWrapper
 
class OneLineShaper
 

Additional Inherited Members

- Public Types inherited from skia::textlayout::Paragraph
enum  VisitorFlags { kWhiteSpace_VisitorFlag = 1 << 0 }
 
using Visitor = std::function< void(int lineNumber, const VisitorInfo *)>
 
using ExtendedVisitor = std::function< void(int lineNumber, const ExtendedVisitorInfo *)>
 
- Static Public Member Functions inherited from skia::textlayout::Paragraph
static SkPath GetPath (SkTextBlob *textBlob)
 
- Protected Attributes inherited from skia::textlayout::Paragraph
sk_sp< FontCollectionfFontCollection
 
ParagraphStyle fParagraphStyle
 
SkScalar fAlphabeticBaseline
 
SkScalar fIdeographicBaseline
 
SkScalar fHeight
 
SkScalar fWidth
 
SkScalar fMaxIntrinsicWidth
 
SkScalar fMinIntrinsicWidth
 
SkScalar fLongestLine
 
bool fExceededMaxLines
 

Detailed Description

Definition at line 88 of file ParagraphImpl.h.

Constructor & Destructor Documentation

◆ ParagraphImpl() [1/2]

skia::textlayout::ParagraphImpl::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 
)

Definition at line 73 of file ParagraphImpl.cpp.

79 : Paragraph(std::move(style), std::move(fonts))
80 , fTextStyles(std::move(blocks))
81 , fPlaceholders(std::move(placeholders))
82 , fText(text)
83 , fState(kUnknown)
84 , fUnresolvedGlyphs(0)
85 , fPicture(nullptr)
86 , fStrutMetrics(false)
87 , fOldWidth(0)
88 , fOldHeight(0)
89 , fUnicode(std::move(unicode))
90 , fHasLineBreaks(false)
91 , fHasWhitespacesInside(false)
92 , fTrailingSpaces(0)
93{
94 SkASSERT(fUnicode);
95}
#define SkASSERT(cond)
Definition SkAssert.h:116
SkSpan< const char > text() const
SkSpan< Placeholder > placeholders()
SkSpan< Block > blocks(BlockRange blockRange)
Paragraph(ParagraphStyle style, sk_sp< FontCollection > fonts)

◆ ParagraphImpl() [2/2]

skia::textlayout::ParagraphImpl::ParagraphImpl ( const std::u16string &  utf16text,
ParagraphStyle  style,
skia_private::TArray< Block, true >  blocks,
skia_private::TArray< Placeholder, true >  placeholders,
sk_sp< FontCollection fonts,
sk_sp< SkUnicode unicode 
)

Definition at line 97 of file ParagraphImpl.cpp.

104 std::move(style),
105 std::move(blocks),
106 std::move(placeholders),
107 std::move(fonts),
108 std::move(unicode))
109{
110 SkASSERT(fUnicode);
111 fText = SkUnicode::convertUtf16ToUtf8(utf16text);
112}
static SkString convertUtf16ToUtf8(const char16_t *utf16, int utf16Units)
Definition SkUnicode.cpp:14
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)

◆ ~ParagraphImpl()

skia::textlayout::ParagraphImpl::~ParagraphImpl ( )
overridedefault

Member Function Documentation

◆ addLine()

TextLine & skia::textlayout::ParagraphImpl::addLine ( SkVector  offset,
SkVector  advance,
TextRange  textExcludingSpaces,
TextRange  text,
TextRange  textIncludingNewlines,
ClusterRange  clusters,
ClusterRange  clustersWithGhosts,
SkScalar  widthWithSpaces,
InternalLineMetrics  sizes 
)

Definition at line 763 of file ParagraphImpl.cpp.

771 {
772 // Define a list of styles that covers the line
773 auto blocks = findAllBlocks(textExcludingSpaces);
774 return fLines.emplace_back(this, offset, advance, blocks,
775 textExcludingSpaces, text, textIncludingNewLines,
776 clusters, clustersWithGhosts, widthWithSpaces, sizes);
777}
BlockRange findAllBlocks(TextRange textRange)
Point offset

◆ addUnresolvedCodepoints()

void skia::textlayout::ParagraphImpl::addUnresolvedCodepoints ( TextRange  textRange)

Definition at line 128 of file ParagraphImpl.cpp.

128 {
129 fUnicode->forEachCodepoint(
130 &fText[textRange.start], textRange.width(),
131 [&](SkUnichar unichar, int32_t start, int32_t end, int32_t count) {
132 fUnresolvedCodepoints.emplace(unichar);
133 }
134 );
135}
int count
int32_t SkUnichar
Definition SkTypes.h:175
void forEachCodepoint(const char *utf8, int32_t utf8Units, Callback &&callback)
Definition SkUnicode.h:239
glong glong end

◆ applySpacingAndBuildClusterTable()

void skia::textlayout::ParagraphImpl::applySpacingAndBuildClusterTable ( )

Definition at line 397 of file ParagraphImpl.cpp.

397 {
398
399 // Check all text styles to see what we have to do (if anything)
400 size_t letterSpacingStyles = 0;
401 bool hasWordSpacing = false;
402 for (auto& block : fTextStyles) {
403 if (block.fRange.width() > 0) {
405 ++letterSpacingStyles;
406 }
408 hasWordSpacing = true;
409 }
410 }
411 }
412
413 if (letterSpacingStyles == 0 && !hasWordSpacing) {
414 // We don't have to do anything about spacing (most common case)
415 this->buildClusterTable();
416 return;
417 }
418
419 if (letterSpacingStyles == 1 && !hasWordSpacing && fTextStyles.size() == 1 &&
420 fTextStyles[0].fRange.width() == fText.size() && fRuns.size() == 1) {
421 // We have to letter space the entire paragraph (second most common case)
422 auto& run = fRuns[0];
423 auto& style = fTextStyles[0].fStyle;
424 run.addSpacesEvenly(style.getLetterSpacing());
425 this->buildClusterTable();
426 // This is something Flutter requires
427 for (auto& cluster : fClusters) {
428 cluster.setHalfLetterSpacing(style.getLetterSpacing()/2);
429 }
430 return;
431 }
432
433 // The complex case: many text styles with spacing (possibly not adjusted to glyphs)
434 this->buildClusterTable();
435
436 // Walk through all the clusters in the direction of shaped text
437 // (we have to walk through the styles in the same order, too)
438 // Not breaking the iteration on every run!
439 SkScalar shift = 0;
440 bool soFarWhitespacesOnly = true;
441 bool wordSpacingPending = false;
442 Cluster* lastSpaceCluster = nullptr;
443 for (auto& run : fRuns) {
444
445 // Skip placeholder runs
446 if (run.isPlaceholder()) {
447 continue;
448 }
449
450 run.iterateThroughClusters([this, &run, &shift, &soFarWhitespacesOnly, &wordSpacingPending, &lastSpaceCluster](Cluster* cluster) {
451 // Shift the cluster (shift collected from the previous clusters)
452 run.shift(cluster, shift);
453
454 // Synchronize styles (one cluster can be covered by few styles)
455 Block* currentStyle = fTextStyles.begin();
456 while (!cluster->startsIn(currentStyle->fRange)) {
457 currentStyle++;
458 SkASSERT(currentStyle != fTextStyles.end());
459 }
460
461 SkASSERT(!currentStyle->fStyle.isPlaceholder());
462
463 // Process word spacing
464 if (currentStyle->fStyle.getWordSpacing() != 0) {
466 if (!soFarWhitespacesOnly) {
467 lastSpaceCluster = cluster;
468 wordSpacingPending = true;
469 }
470 } else if (wordSpacingPending) {
471 SkScalar spacing = currentStyle->fStyle.getWordSpacing();
472 if (cluster->fRunIndex != lastSpaceCluster->fRunIndex) {
473 // If the last space cluster belongs to the previous run
474 // we have to extend that cluster and that run
475 lastSpaceCluster->run().addSpacesAtTheEnd(spacing, lastSpaceCluster);
476 lastSpaceCluster->run().extend(lastSpaceCluster, spacing);
477 } else {
478 run.addSpacesAtTheEnd(spacing, lastSpaceCluster);
479 }
480
481 run.shift(cluster, spacing);
482 shift += spacing;
483 wordSpacingPending = false;
484 }
485 }
486 // Process letter spacing
487 if (currentStyle->fStyle.getLetterSpacing() != 0) {
488 shift += run.addSpacesEvenly(currentStyle->fStyle.getLetterSpacing(), cluster);
489 }
490
491 if (soFarWhitespacesOnly && !cluster->isWhitespaceBreak()) {
492 soFarWhitespacesOnly = false;
493 }
494 });
495 }
496}
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:101
size_t size() const
Definition SkString.h:131
bool isSoftBreak() const
Definition Run.cpp:346
bool startsIn(TextRange text) const
Definition Run.h:342
void setHalfLetterSpacing(SkScalar halfLetterSpacing)
Definition Run.h:322
bool isWhitespaceBreak() const
Definition Run.h:308
Cluster & cluster(ClusterIndex clusterIndex)
Block & block(BlockIndex blockIndex)
SkScalar getLetterSpacing() const
Definition TextStyle.h:270
SkScalar getWordSpacing() const
Definition TextStyle.h:273
float SkScalar
Definition extension.cpp:12
Definition run.py:1

◆ block()

Block & skia::textlayout::ParagraphImpl::block ( BlockIndex  blockIndex)

Definition at line 966 of file ParagraphImpl.cpp.

966 {
967 SkASSERT(blockIndex < SkToSizeT(fTextStyles.size()));
968 return fTextStyles[blockIndex];
969}
constexpr size_t SkToSizeT(S x)
Definition SkTo.h:31

◆ blocks()

SkSpan< Block > skia::textlayout::ParagraphImpl::blocks ( BlockRange  blockRange)

Definition at line 960 of file ParagraphImpl.cpp.

960 {
961 SkASSERT(blockRange.start < SkToSizeT(fTextStyles.size()) &&
962 blockRange.end <= SkToSizeT(fTextStyles.size()));
963 return SkSpan<Block>(&fTextStyles[blockRange.start], blockRange.width());
964}

◆ breakShapedTextIntoLines()

void skia::textlayout::ParagraphImpl::breakShapedTextIntoLines ( SkScalar  maxWidth)

Definition at line 573 of file ParagraphImpl.cpp.

573 {
574
575 if (!fHasLineBreaks &&
576 !fHasWhitespacesInside &&
577 fPlaceholders.size() == 1 &&
578 fRuns.size() == 1 && fRuns[0].fAdvance.fX <= maxWidth) {
579 // This is a short version of a line breaking when we know that:
580 // 1. We have only one line of text
581 // 2. It's shaped into a single run
582 // 3. There are no placeholders
583 // 4. There are no linebreaks (which will format text into multiple lines)
584 // 5. There are no whitespaces so the minIntrinsicWidth=maxIntrinsicWidth
585 // (To think about that, the last condition is not quite right;
586 // we should calculate minIntrinsicWidth by soft line breaks.
587 // However, it's how it's done in Flutter now)
588 auto& run = this->fRuns[0];
589 auto advance = run.advance();
590 auto textRange = TextRange(0, this->text().size());
591 auto textExcludingSpaces = TextRange(0, fTrailingSpaces);
592 InternalLineMetrics metrics(this->strutForceHeight());
593 metrics.add(&run);
594 auto disableFirstAscent = this->paragraphStyle().getTextHeightBehavior() &
596 auto disableLastDescent = this->paragraphStyle().getTextHeightBehavior() &
598 if (disableFirstAscent) {
599 metrics.fAscent = metrics.fRawAscent;
600 }
601 if (disableLastDescent) {
602 metrics.fDescent = metrics.fRawDescent;
603 }
604 if (this->strutEnabled()) {
605 this->strutMetrics().updateLineMetrics(metrics);
606 }
607 ClusterIndex trailingSpaces = fClusters.size();
608 do {
609 --trailingSpaces;
610 auto& cluster = fClusters[trailingSpaces];
611 if (!cluster.isWhitespaceBreak()) {
612 ++trailingSpaces;
613 break;
614 }
615 advance.fX -= cluster.width();
616 } while (trailingSpaces != 0);
617
618 advance.fY = metrics.height();
619 auto clusterRange = ClusterRange(0, trailingSpaces);
620 auto clusterRangeWithGhosts = ClusterRange(0, this->clusters().size() - 1);
621 this->addLine(SkPoint::Make(0, 0), advance,
622 textExcludingSpaces, textRange, textRange,
623 clusterRange, clusterRangeWithGhosts, run.advance().x(),
624 metrics);
625
626 fLongestLine = nearlyZero(advance.fX) ? run.advance().fX : advance.fX;
627 fHeight = advance.fY;
628 fWidth = maxWidth;
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;
634 return;
635 }
636
637 TextWrapper textWrapper;
638 textWrapper.breakTextIntoLines(
639 this,
640 maxWidth,
641 [&](TextRange textExcludingSpaces,
643 TextRange textWithNewlines,
645 ClusterRange clustersWithGhosts,
646 SkScalar widthWithSpaces,
647 size_t startPos,
648 size_t endPos,
650 SkVector advance,
651 InternalLineMetrics metrics,
652 bool addEllipsis) {
653 // TODO: Take in account clipped edges
654 auto& line = this->addLine(offset, advance, textExcludingSpaces, text, textWithNewlines, clusters, clustersWithGhosts, widthWithSpaces, metrics);
655 if (addEllipsis) {
656 line.createEllipsis(maxWidth, this->getEllipsis(), true);
657 }
658 fLongestLine = std::max(fLongestLine, nearlyZero(advance.fX) ? widthWithSpaces : advance.fX);
659 });
660
661 fHeight = textWrapper.height();
662 fWidth = maxWidth;
663 fMaxIntrinsicWidth = textWrapper.maxIntrinsicWidth();
664 fMinIntrinsicWidth = textWrapper.minIntrinsicWidth();
665 fAlphabeticBaseline = fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline();
666 fIdeographicBaseline = fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline();
667 fExceededMaxLines = textWrapper.exceededMaxLines();
668}
SkScalar width() const
Definition Run.h:318
void updateLineMetrics(InternalLineMetrics &metrics)
Definition Run.h:454
SkScalar alphabeticBaseline() const
Definition Run.h:491
SkScalar ideographicBaseline() const
Definition Run.h:492
TextLine & addLine(SkVector offset, SkVector advance, TextRange textExcludingSpaces, TextRange text, TextRange textIncludingNewlines, ClusterRange clusters, ClusterRange clustersWithGhosts, SkScalar widthWithSpaces, InternalLineMetrics sizes)
InternalLineMetrics strutMetrics() const
const ParagraphStyle & paragraphStyle() const
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
Definition switches.h:259
SkRange< size_t > ClusterRange
Definition Run.h:36
SkRange< size_t > TextRange
Definition TextStyle.h:337
size_t ClusterIndex
Definition Run.h:35
static bool nearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition TextStyle.h:24
float fX
x-axis value
static constexpr SkPoint Make(float x, float y)
TextHeightBehavior getTextHeightBehavior() const

◆ buildClusterTable()

void skia::textlayout::ParagraphImpl::buildClusterTable ( )

Definition at line 499 of file ParagraphImpl.cpp.

499 {
500 // It's possible that one grapheme includes few runs; we cannot handle it
501 // so we break graphemes by the runs instead
502 // It's not the ideal solution and has to be revisited later
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;
508 }
509 if (!fRuns.empty()) {
510 fCodeUnitProperties[fRuns.back().textRange().end] |= SkUnicode::CodeUnitFlags::kGraphemeStart;
511 fCodeUnitProperties[fRuns.back().textRange().end] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
512 }
513 fClusters.reserve_exact(fClusters.size() + cluster_count);
514
515 // Walk through all the run in the direction of input text
516 for (auto& run : fRuns) {
517 auto runIndex = run.index();
518 auto runStart = fClusters.size();
519 if (run.isPlaceholder()) {
520 // Add info to cluster indexes table (text -> cluster)
521 for (auto i = run.textRange().start; i < run.textRange().end; ++i) {
522 fClustersIndexFromCodeUnit[i] = fClusters.size();
523 }
524 // There are no glyphs but we want to have one cluster
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;
528 } else {
529 // Walk through the glyph in the direction of input text
530 run.iterateThroughClustersInTextOrder([runIndex, this](size_t glyphStart,
531 size_t glyphEnd,
532 size_t charStart,
533 size_t charEnd,
536 SkASSERT(charEnd >= charStart);
537 // Add info to cluster indexes table (text -> cluster)
538 for (auto i = charStart; i < charEnd; ++i) {
539 fClustersIndexFromCodeUnit[i] = fClusters.size();
540 }
541 SkSpan<const char> text(fText.c_str() + charStart, charEnd - charStart);
542 fClusters.emplace_back(this, runIndex, glyphStart, glyphEnd, text, width, height);
543 fCodeUnitProperties[charStart] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
544 });
545 }
546 fCodeUnitProperties[run.textRange().start] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
547
548 run.setClusterRange(runStart, fClusters.size());
549 fMaxIntrinsicWidth += run.advance().fX;
550 }
551 fClustersIndexFromCodeUnit[fText.size()] = fClusters.size();
552 fClusters.emplace_back(this, EMPTY_RUN, 0, 0, this->text({fText.size(), fText.size()}), 0, 0);
553}
const char * c_str() const
Definition SkString.h:133
@ kGraphemeStart
Definition SkUnicode.h:82
@ kGlyphClusterStart
Definition SkUnicode.h:88
@ kSoftLineBreakBefore
Definition SkUnicode.h:83
const size_t EMPTY_RUN
Definition Run.h:33
int32_t height
int32_t width

◆ cluster()

Cluster & skia::textlayout::ParagraphImpl::cluster ( ClusterIndex  clusterIndex)

Definition at line 950 of file ParagraphImpl.cpp.

950 {
951 SkASSERT(clusterIndex < SkToSizeT(fClusters.size()));
952 return fClusters[clusterIndex];
953}
ClusterIndex clusterIndex(TextIndex textIndex)

◆ clusterIndex()

ClusterIndex skia::textlayout::ParagraphImpl::clusterIndex ( TextIndex  textIndex)
inline

Definition at line 167 of file ParagraphImpl.h.

167 {
168 auto clusterIndex = this->fClustersIndexFromCodeUnit[textIndex];
170 return clusterIndex;
171 }
const size_t EMPTY_INDEX
Definition DartTypes.h:91

◆ clusters() [1/2]

SkSpan< Cluster > skia::textlayout::ParagraphImpl::clusters ( )
inline

Definition at line 140 of file ParagraphImpl.h.

140{ return SkSpan<Cluster>(fClusters.begin(), fClusters.size()); }

◆ clusters() [2/2]

SkSpan< Cluster > skia::textlayout::ParagraphImpl::clusters ( ClusterRange  clusterRange)

Definition at line 944 of file ParagraphImpl.cpp.

944 {
945 SkASSERT(clusterRange.start < SkToSizeT(fClusters.size()) &&
946 clusterRange.end <= SkToSizeT(fClusters.size()));
947 return SkSpan<Cluster>(&fClusters[clusterRange.start], clusterRange.width());
948}

◆ codeUnitHasProperty()

bool skia::textlayout::ParagraphImpl::codeUnitHasProperty ( size_t  index,
SkUnicode::CodeUnitFlags  property 
) const
inline

Definition at line 243 of file ParagraphImpl.h.

243 {
244 return (fCodeUnitProperties[index] & property) == property;
245 }

◆ computeCodeUnitProperties()

bool skia::textlayout::ParagraphImpl::computeCodeUnitProperties ( )

Definition at line 267 of file ParagraphImpl.cpp.

267 {
268
269 if (nullptr == fUnicode) {
270 return false;
271 }
272
273 // Get bidi regions
277 if (!fUnicode->getBidiRegions(fText.c_str(), fText.size(), textDirection, &fBidiRegions)) {
278 return false;
279 }
280
281 // Collect all spaces and some extra information
282 // (and also substitute \t with a space while we are at it)
283 if (!fUnicode->computeCodeUnitFlags(&fText[0],
284 fText.size(),
285 this->paragraphStyle().getReplaceTabCharacters(),
286 &fCodeUnitProperties)) {
287 return false;
288 }
289
290 // Get some information about trailing spaces / hard line breaks
291 fTrailingSpaces = fText.size();
292 TextIndex firstWhitespace = EMPTY_INDEX;
293 for (int i = 0; i < fCodeUnitProperties.size(); ++i) {
294 auto flags = fCodeUnitProperties[i];
296 if (fTrailingSpaces == fText.size()) {
297 fTrailingSpaces = i;
298 }
299 if (firstWhitespace == EMPTY_INDEX) {
300 firstWhitespace = i;
301 }
302 } else {
303 fTrailingSpaces = fText.size();
304 }
306 fHasLineBreaks = true;
307 }
308 }
309
310 if (firstWhitespace < fTrailingSpaces) {
311 fHasWhitespacesInside = true;
312 }
313
314 return true;
315}
static bool hasPartOfWhiteSpaceBreakFlag(SkUnicode::CodeUnitFlags flags)
Definition SkUnicode.cpp:71
static bool hasHardLineBreakFlag(SkUnicode::CodeUnitFlags flags)
Definition SkUnicode.cpp:55
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
ParagraphStyle fParagraphStyle
Definition Paragraph.h:274
int size() const
Definition SkTArray.h:416
FlutterSemanticsFlag flags
TextDirection getTextDirection() const

◆ containsColorFontOrBitmap()

bool skia::textlayout::ParagraphImpl::containsColorFontOrBitmap ( SkTextBlob textBlob)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1545 of file ParagraphImpl.cpp.

1545 {
1546 SkTextBlobRunIterator iter(textBlob);
1547 bool flag = false;
1548 while (!iter.done() && !flag) {
1549 iter.font().getPaths(
1550 (const SkGlyphID*) iter.glyphs(),
1551 iter.glyphCount(),
1552 [](const SkPath* path, const SkMatrix& mx, void* ctx) {
1553 if (path == nullptr) {
1554 bool* flag1 = (bool*)ctx;
1555 *flag1 = true;
1556 }
1557 }, &flag);
1558 iter.next();
1559 }
1560 return flag;
1561}
uint16_t SkGlyphID
Definition SkTypes.h:179
FlutterSemanticsFlag flag

◆ containsEmoji()

bool skia::textlayout::ParagraphImpl::containsEmoji ( SkTextBlob textBlob)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1529 of file ParagraphImpl.cpp.

1529 {
1530 bool result = false;
1531 SkTextBlobRunIterator iter(textBlob);
1532 while (!iter.done() && !result) {
1533 // Walk through all the text by codepoints
1534 this->getUnicode()->forEachCodepoint(iter.text(), iter.textSize(),
1535 [&](SkUnichar unichar, int32_t start, int32_t end, int32_t count) {
1536 if (this->getUnicode()->isEmoji(unichar)) {
1537 result = true;
1538 }
1539 });
1540 iter.next();
1541 }
1542 return result;
1543}
sk_sp< SkUnicode > getUnicode()
GAsyncResult * result

◆ countSurroundingGraphemes()

TArray< TextIndex > skia::textlayout::ParagraphImpl::countSurroundingGraphemes ( TextRange  textRange) const

Definition at line 1123 of file ParagraphImpl.cpp.

1123 {
1124 textRange = textRange.intersection({0, fText.size()});
1125 TArray<TextIndex> graphemes;
1126 if ((fCodeUnitProperties[textRange.start] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1127 // Count the previous partial grapheme
1128 graphemes.emplace_back(textRange.start);
1129 }
1130 for (auto index = textRange.start; index < textRange.end; ++index) {
1131 if ((fCodeUnitProperties[index] & SkUnicode::CodeUnitFlags::kGraphemeStart) != 0) {
1132 graphemes.emplace_back(index);
1133 }
1134 }
1135 return graphemes;
1136}
T & emplace_back(Args &&... args)
Definition SkTArray.h:243

◆ ensureUTF16Mapping()

void skia::textlayout::ParagraphImpl::ensureUTF16Mapping ( )

Definition at line 1170 of file ParagraphImpl.cpp.

1170 {
1171 fillUTF16MappingOnce([&] {
1173 this->text(),
1174 [&](size_t index) { fUTF8IndexForUTF16Index.emplace_back(index); },
1175 [&](size_t index) { fUTF16IndexForUTF8Index.emplace_back(index); });
1176 });
1177}
static bool extractUtfConversionMapping(SkSpan< const char > utf8, Appender8 &&appender8, Appender16 &&appender16)
Definition SkUnicode.h:193

◆ extendedVisit()

void skia::textlayout::ParagraphImpl::extendedVisit ( const ExtendedVisitor visitor)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1390 of file ParagraphImpl.cpp.

1390 {
1391 int lineNumber = 0;
1392 for (auto& line : fLines) {
1393 line.iterateThroughVisualRuns(
1394 false,
1395 [&](const Run* run,
1396 SkScalar runOffsetInLine,
1397 TextRange textRange,
1398 SkScalar* runWidthInLine) {
1399 *runWidthInLine = line.iterateThroughSingleRunByStyles(
1401 run,
1402 runOffsetInLine,
1403 textRange,
1405 [&](TextRange textRange,
1406 const TextStyle& style,
1407 const TextLine::ClipContext& context) {
1408 SkScalar correctedBaseline = SkScalarFloorToScalar(
1409 line.baseline() + style.getBaselineShift() + 0.5);
1410 SkPoint offset =
1411 SkPoint::Make(line.offset().fX + context.fTextShift,
1412 line.offset().fY + correctedBaseline);
1413 SkRect rect = context.clip.makeOffset(line.offset());
1414 AutoSTArray<16, SkRect> glyphBounds;
1415 glyphBounds.reset(SkToInt(run->size()));
1416 run->font().getBounds(run->glyphs().data(),
1417 SkToInt(run->size()),
1418 glyphBounds.data(),
1419 nullptr);
1420 STArray<128, uint32_t> clusterStorage;
1421 const uint32_t* clusterPtr = run->clusterIndexes().data();
1422 if (run->fClusterStart > 0) {
1423 clusterStorage.reset(context.size);
1424 for (size_t i = 0; i < context.size; ++i) {
1425 clusterStorage[i] =
1426 run->fClusterStart + run->fClusterIndexes[i];
1427 }
1428 clusterPtr = &clusterStorage[0];
1429 }
1430 const Paragraph::ExtendedVisitorInfo info = {
1431 run->font(),
1432 offset,
1433 SkSize::Make(rect.width(), rect.height()),
1434 SkToS16(context.size),
1435 &run->glyphs()[context.pos],
1436 &run->fPositions[context.pos],
1437 &glyphBounds[context.pos],
1438 clusterPtr,
1439 0, // flags
1440 };
1441 visitor(lineNumber, &info);
1442 });
1443 return true;
1444 });
1445 visitor(lineNumber, nullptr); // signal end of line
1446 lineNumber += 1;
1447 }
1448}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define SkScalarFloorToScalar(x)
Definition SkScalar.h:30
constexpr int SkToInt(S x)
Definition SkTo.h:29
constexpr int16_t SkToS16(S x)
Definition SkTo.h:23
const T * data() const
void reset(int n)
Definition SkTArray.h:139
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition SkSize.h:56

◆ findAllBlocks()

BlockRange skia::textlayout::ParagraphImpl::findAllBlocks ( TextRange  textRange)

Definition at line 737 of file ParagraphImpl.cpp.

737 {
740 for (int index = 0; index < fTextStyles.size(); ++index) {
741 auto& block = fTextStyles[index];
742 if (block.fRange.end <= textRange.start) {
743 continue;
744 }
745 if (block.fRange.start >= textRange.end) {
746 break;
747 }
748 if (begin == EMPTY_BLOCK) {
749 begin = index;
750 }
751 end = index;
752 }
753
754 if (begin == EMPTY_INDEX || end == EMPTY_INDEX) {
755 // It's possible if some text is not covered with any text style
756 // Not in Flutter but in direct use of SkParagraph
757 return EMPTY_RANGE;
758 }
759
760 return { begin, end + 1 };
761}
static const char * begin(const StringSlice &s)
Definition editor.cpp:252
const size_t EMPTY_BLOCK
Definition TextStyle.h:357
const SkRange< size_t > EMPTY_RANGE
Definition DartTypes.h:128

◆ findNextGlyphClusterBoundary()

TextIndex skia::textlayout::ParagraphImpl::findNextGlyphClusterBoundary ( TextIndex  utf8) const

Definition at line 1154 of file ParagraphImpl.cpp.

1154 {
1155 while (utf8 < fText.size() &&
1156 (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGlyphClusterStart) == 0) {
1157 ++utf8;
1158 }
1159 return utf8;
1160}

◆ findNextGraphemeBoundary()

TextIndex skia::textlayout::ParagraphImpl::findNextGraphemeBoundary ( TextIndex  utf8) const

Definition at line 1146 of file ParagraphImpl.cpp.

1146 {
1147 while (utf8 < fText.size() &&
1148 (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1149 ++utf8;
1150 }
1151 return utf8;
1152}

◆ findPreviousGlyphClusterBoundary()

TextIndex skia::textlayout::ParagraphImpl::findPreviousGlyphClusterBoundary ( TextIndex  utf8) const

Definition at line 1162 of file ParagraphImpl.cpp.

1162 {
1163 while (utf8 > 0 &&
1164 (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGlyphClusterStart) == 0) {
1165 --utf8;
1166 }
1167 return utf8;
1168}

◆ findPreviousGraphemeBoundary()

TextIndex skia::textlayout::ParagraphImpl::findPreviousGraphemeBoundary ( TextIndex  utf8) const

Definition at line 1138 of file ParagraphImpl.cpp.

1138 {
1139 while (utf8 > 0 &&
1140 (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1141 --utf8;
1142 }
1143 return utf8;
1144}

◆ fontCollection()

sk_sp< FontCollection > skia::textlayout::ParagraphImpl::fontCollection ( ) const
inline

Definition at line 141 of file ParagraphImpl.h.

141{ return fFontCollection; }
sk_sp< FontCollection > fFontCollection
Definition Paragraph.h:273

◆ formatLines()

void skia::textlayout::ParagraphImpl::formatLines ( SkScalar  maxWidth)

Definition at line 670 of file ParagraphImpl.cpp.

670 {
671 auto effectiveAlign = fParagraphStyle.effective_align();
672 const bool isLeftAligned = effectiveAlign == TextAlign::kLeft
674
675 if (!SkIsFinite(maxWidth) && !isLeftAligned) {
676 // Special case: clean all text in case of maxWidth == INF & align != left
677 // We had to go through shaping though because we need all the measurement numbers
678 fLines.clear();
679 return;
680 }
681
682 for (auto& line : fLines) {
683 line.format(effectiveAlign, maxWidth);
684 }
685}
static bool SkIsFinite(T x, Pack... values)

◆ getActualTextRange()

TextRange skia::textlayout::ParagraphImpl::getActualTextRange ( int  lineNumber,
bool  includeSpaces 
) const
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1270 of file ParagraphImpl.cpp.

1270 {
1271 if (lineNumber < 0 || lineNumber >= fLines.size()) {
1272 return EMPTY_TEXT;
1273 }
1274 auto& line = fLines[lineNumber];
1275 return includeSpaces ? line.text() : line.trimmedText();
1276}
const SkRange< size_t > EMPTY_TEXT
Definition TextStyle.h:338

◆ getApplyRoundingHack()

bool skia::textlayout::ParagraphImpl::getApplyRoundingHack ( ) const
inline

Definition at line 120 of file ParagraphImpl.h.

◆ getClosestGlyphClusterAt()

bool skia::textlayout::ParagraphImpl::getClosestGlyphClusterAt ( SkScalar  dx,
SkScalar  dy,
GlyphClusterInfo glyphInfo 
)
overridevirtual

Finds the closest glyph cluster for a visual text position

Parameters
dxx coordinate
dyy coordinate
glyphInfoa glyph cluster info filled if not null
Returns
true if glyph cluster was found; false if not (which usually means the paragraph is empty)

Implements skia::textlayout::Paragraph.

Definition at line 1303 of file ParagraphImpl.cpp.

1305 {
1306 const PositionWithAffinity res = this->getGlyphPositionAtCoordinate(dx, dy);
1307 SkASSERT(res.position != 0 || res.affinity != Affinity::kUpstream);
1308 const size_t utf16Offset = res.position + (res.affinity == Affinity::kDownstream ? 0 : -1);
1309 this->ensureUTF16Mapping();
1310 SkASSERT(utf16Offset < SkToSizeT(fUTF8IndexForUTF16Index.size()));
1311 return this->getGlyphClusterAt(fUTF8IndexForUTF16Index[utf16Offset], glyphInfo);
1312}
PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) override
bool getGlyphClusterAt(TextIndex codeUnitIndex, GlyphClusterInfo *glyphInfo) override

◆ getClosestUTF16GlyphInfoAt()

bool skia::textlayout::ParagraphImpl::getClosestUTF16GlyphInfoAt ( SkScalar  dx,
SkScalar  dy,
GlyphInfo glyphInfo 
)
overridevirtual

Finds the information associated with the closest glyph to the given paragraph coordinates.

Parameters
dxx coordinate
dyy coordinate
glyphInfoan optional GlyphInfo struct to hold the information associated with the glyph found. The text indices and text ranges are described using UTF-16 offsets
Returns
true if a graphme cluster was found; false if not (which usually means the paragraph is empty)

Implements skia::textlayout::Paragraph.

Definition at line 1350 of file ParagraphImpl.cpp.

1350 {
1351 const PositionWithAffinity res = this->getGlyphPositionAtCoordinate(dx, dy);
1352 SkASSERT(res.position != 0 || res.affinity != Affinity::kUpstream);
1353 const size_t utf16Offset = res.position + (res.affinity == Affinity::kDownstream ? 0 : -1);
1354 return getGlyphInfoAtUTF16Offset(utf16Offset, glyphInfo);
1355}
bool getGlyphInfoAtUTF16Offset(size_t codeUnitIndex, GlyphInfo *graphemeInfo) override

◆ getEllipsis()

SkString skia::textlayout::ParagraphImpl::getEllipsis ( ) const

Definition at line 1066 of file ParagraphImpl.cpp.

1066 {
1067
1068 auto ellipsis8 = fParagraphStyle.getEllipsis();
1069 auto ellipsis16 = fParagraphStyle.getEllipsisUtf16();
1070 if (!ellipsis8.isEmpty()) {
1071 return ellipsis8;
1072 } else {
1074 }
1075}
std::u16string getEllipsisUtf16() const

◆ getEmptyMetrics()

InternalLineMetrics skia::textlayout::ParagraphImpl::getEmptyMetrics ( ) const
inline

Definition at line 232 of file ParagraphImpl.h.

232{ return fEmptyMetrics; }

◆ getFontAt()

SkFont skia::textlayout::ParagraphImpl::getFontAt ( TextIndex  codeUnitIndex) const
overridevirtual

Returns the font that is used to shape the text at the position

Parameters
codeUnitIndextext index
Returns
font info or an empty font info if the text is not found

Implements skia::textlayout::Paragraph.

Definition at line 1357 of file ParagraphImpl.cpp.

1357 {
1358 for (auto& run : fRuns) {
1359 const auto textRange = run.textRange();
1360 if (textRange.start <= codeUnitIndex && codeUnitIndex < textRange.end) {
1361 return run.font();
1362 }
1363 }
1364 return SkFont();
1365}

◆ getFontAtUTF16Offset()

SkFont skia::textlayout::ParagraphImpl::getFontAtUTF16Offset ( size_t  codeUnitIndex)
overridevirtual

Returns the font used to shape the text at the given UTF-16 offset.

Parameters
codeUnitIndexa UTF-16 offset in the paragraph
Returns
font info or an empty font info if the text is not found

Implements skia::textlayout::Paragraph.

Definition at line 1367 of file ParagraphImpl.cpp.

1367 {
1369 if (codeUnitIndex >= SkToSizeT(fUTF8IndexForUTF16Index.size())) {
1370 return SkFont();
1371 }
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) {
1376 return run.font();
1377 }
1378 }
1379 return SkFont();
1380}

◆ getFonts()

std::vector< Paragraph::FontInfo > skia::textlayout::ParagraphImpl::getFonts ( ) const
overridevirtual

Returns the information about all the fonts used to shape the paragraph text

Returns
a list of fonts and text ranges

Implements skia::textlayout::Paragraph.

Definition at line 1382 of file ParagraphImpl.cpp.

1382 {
1383 std::vector<FontInfo> results;
1384 for (auto& run : fRuns) {
1385 results.emplace_back(run.font(), run.textRange());
1386 }
1387 return results;
1388}

◆ getGlyphClusterAt()

bool skia::textlayout::ParagraphImpl::getGlyphClusterAt ( TextIndex  codeUnitIndex,
GlyphClusterInfo glyphInfo 
)
overridevirtual

Finds a glyph cluster for text index

Parameters
codeUnitIndexa text index
glyphInfoa glyph cluster info filled if not null
Returns
true if glyph cluster was found; false if not

Implements skia::textlayout::Paragraph.

Definition at line 1278 of file ParagraphImpl.cpp.

1278 {
1279 const int lineNumber = getLineNumberAt(codeUnitIndex);
1280 if (lineNumber == -1) {
1281 return false;
1282 }
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(),
1291 boxes);
1292 if (!boxes.empty()) {
1293 if (glyphInfo) {
1294 *glyphInfo = {boxes[0].rect, cluster.textRange(), boxes[0].direction};
1295 }
1296 return true;
1297 }
1298 }
1299 }
1300 return false;
1301}
TextRange textRange() const
Definition Run.h:325
bool contains(TextIndex ch) const
Definition Run.h:336
int getLineNumberAt(TextIndex codeUnitIndex) const override

◆ getGlyphInfoAtUTF16Offset()

bool skia::textlayout::ParagraphImpl::getGlyphInfoAtUTF16Offset ( size_t  codeUnitIndex,
GlyphInfo glyphInfo 
)
overridevirtual

Retrives the information associated with the glyph located at the given codeUnitIndex.

Parameters
codeUnitIndexa UTF-16 offset into the paragraph
glyphInfoan optional GlyphInfo struct to hold the information associated with the glyph found at the given index
Returns
false only if the offset is out of bounds

Implements skia::textlayout::Paragraph.

Definition at line 1314 of file ParagraphImpl.cpp.

1314 {
1315 this->ensureUTF16Mapping();
1316 if (codeUnitIndex >= SkToSizeT(fUTF8IndexForUTF16Index.size())) {
1317 return false;
1318 }
1319 const TextIndex utf8 = fUTF8IndexForUTF16Index[codeUnitIndex];
1320 const int lineNumber = getLineNumberAt(utf8);
1321 if (lineNumber == -1) {
1322 return false;
1323 }
1324 if (glyphInfo == nullptr) {
1325 return true;
1326 }
1327 const TextLine& line = fLines[lineNumber];
1328 const TextIndex startIndex = findPreviousGraphemeBoundary(utf8);
1329 const TextIndex endIndex = findNextGraphemeBoundary(utf8 + 1);
1330 const ClusterIndex glyphClusterIndex = clusterIndex(utf8);
1331 const Cluster& glyphCluster = cluster(glyphClusterIndex);
1332
1333 // `startIndex` and `endIndex` must be on the same line.
1334 std::vector<TextBox> boxes;
1335 line.getRectsForRange({startIndex, endIndex}, RectHeightStyle::kTight, RectWidthStyle::kTight, boxes);
1336 // TODO: currently placeholders with height=0 and width=0 are ignored so boxes
1337 // can be empty. These placeholders should still be reported for their
1338 // offset information.
1339 if (glyphInfo && !boxes.empty()) {
1340 *glyphInfo = {
1341 boxes[0].rect,
1342 { fUTF16IndexForUTF8Index[startIndex], fUTF16IndexForUTF8Index[endIndex] },
1343 boxes[0].direction,
1344 glyphCluster.run().isEllipsis(),
1345 };
1346 }
1347 return true;
1348}
TextIndex findPreviousGraphemeBoundary(TextIndex utf8) const
TextIndex findNextGraphemeBoundary(TextIndex utf8) const

◆ getGlyphPositionAtCoordinate()

PositionWithAffinity skia::textlayout::ParagraphImpl::getGlyphPositionAtCoordinate ( SkScalar  dx,
SkScalar  dy 
)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 875 of file ParagraphImpl.cpp.

875 {
876
877 if (fText.isEmpty()) {
878 return {0, Affinity::kDownstream};
879 }
880
881 this->ensureUTF16Mapping();
882
883 for (auto& line : fLines) {
884 // Let's figure out if we can stop looking
885 auto offsetY = line.offset().fY;
886 if (dy >= offsetY + line.height() && &line != &fLines.back()) {
887 // This line is not good enough
888 continue;
889 }
890
891 // This is so far the the line vertically closest to our coordinates
892 // (or the first one, or the only one - all the same)
893
894 auto result = line.getGlyphPositionAtCoordinate(dx);
895 //SkDebugf("getGlyphPositionAtCoordinate(%f, %f): %d %s\n", dx, dy, result.position,
896 // result.affinity == Affinity::kUpstream ? "up" : "down");
897 return result;
898 }
899
900 return {0, Affinity::kDownstream};
901}
bool isEmpty() const
Definition SkString.h:130
SkScalar offsetY

◆ getLineMetrics()

void skia::textlayout::ParagraphImpl::getLineMetrics ( std::vector< LineMetrics > &  metrics)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 931 of file ParagraphImpl.cpp.

931 {
932 metrics.clear();
933 for (auto& line : fLines) {
934 metrics.emplace_back(line.getMetrics());
935 }
936}

◆ getLineMetricsAt()

bool skia::textlayout::ParagraphImpl::getLineMetricsAt ( int  lineNumber,
LineMetrics lineMetrics 
) const
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1259 of file ParagraphImpl.cpp.

1259 {
1260 if (lineNumber < 0 || lineNumber >= fLines.size()) {
1261 return false;
1262 }
1263 auto& line = fLines[lineNumber];
1264 if (lineMetrics) {
1265 *lineMetrics = line.getMetrics();
1266 }
1267 return true;
1268}

◆ getLineNumberAt()

int skia::textlayout::ParagraphImpl::getLineNumberAt ( TextIndex  codeUnitIndex) const
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1224 of file ParagraphImpl.cpp.

1224 {
1225 if (codeUnitIndex >= fText.size()) {
1226 return -1;
1227 }
1228 size_t startLine = 0;
1229 size_t endLine = fLines.size() - 1;
1230 if (fLines.empty() || fLines[endLine].textWithNewlines().end <= codeUnitIndex) {
1231 return -1;
1232 }
1233
1234 while (endLine > startLine) {
1235 // startLine + 1 <= endLine, so we have startLine <= midLine <= endLine - 1.
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;
1242 } else {
1243 return midLine;
1244 }
1245 }
1246 SkASSERT(startLine == endLine);
1247 return startLine;
1248}

◆ getLineNumberAtUTF16Offset()

int skia::textlayout::ParagraphImpl::getLineNumberAtUTF16Offset ( size_t  codeUnitIndex)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1250 of file ParagraphImpl.cpp.

1250 {
1251 this->ensureUTF16Mapping();
1252 if (codeUnitIndex >= SkToSizeT(fUTF8IndexForUTF16Index.size())) {
1253 return -1;
1254 }
1255 const TextIndex utf8 = fUTF8IndexForUTF16Index[codeUnitIndex];
1256 return getLineNumberAt(utf8);
1257}

◆ getPath()

int skia::textlayout::ParagraphImpl::getPath ( int  lineNumber,
SkPath dest 
)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1450 of file ParagraphImpl.cpp.

1450 {
1451 int notConverted = 0;
1452 auto& line = fLines[lineNumber];
1453 line.iterateThroughVisualRuns(
1454 false,
1455 [&](const Run* run,
1456 SkScalar runOffsetInLine,
1457 TextRange textRange,
1458 SkScalar* runWidthInLine) {
1459 *runWidthInLine = line.iterateThroughSingleRunByStyles(
1461 run,
1462 runOffsetInLine,
1463 textRange,
1465 [&](TextRange textRange,
1466 const TextStyle& style,
1467 const TextLine::ClipContext& context) {
1468 const SkFont& font = run->font();
1469 SkScalar correctedBaseline = SkScalarFloorToScalar(
1470 line.baseline() + style.getBaselineShift() + 0.5);
1471 SkPoint offset =
1472 SkPoint::Make(line.offset().fX + context.fTextShift,
1473 line.offset().fY + correctedBaseline);
1474 SkRect rect = context.clip.makeOffset(offset);
1475 struct Rec {
1476 SkPath* fPath;
1477 SkPoint fOffset;
1478 const SkPoint* fPos;
1479 int fNotConverted;
1480 } rec =
1481 {dest, SkPoint::Make(rect.left(), rect.top()),
1482 &run->positions()[context.pos], 0};
1483 font.getPaths(&run->glyphs()[context.pos], context.size,
1484 [](const SkPath* path, const SkMatrix& mx, void* ctx) {
1485 Rec* rec = reinterpret_cast<Rec*>(ctx);
1486 if (path) {
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);
1491 } else {
1492 rec->fNotConverted++;
1493 }
1494 rec->fPos += 1; // move to the next glyph's position
1495 }, &rec);
1496 notConverted += rec.fNotConverted;
1497 });
1498 return true;
1499 });
1500
1501 return notConverted;
1502}
SkPath fPath
font
Font Metadata and Metrics.
dest
Definition zip.py:79

◆ getPicture()

sk_sp< SkPicture > skia::textlayout::ParagraphImpl::getPicture ( )
inline

Definition at line 193 of file ParagraphImpl.h.

193{ return fPicture; }

◆ getRectsForPlaceholders()

std::vector< TextBox > skia::textlayout::ParagraphImpl::getRectsForPlaceholders ( )
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 848 of file ParagraphImpl.cpp.

848 {
849 std::vector<TextBox> boxes;
850 if (fText.isEmpty()) {
851 return boxes;
852 }
853 if (fPlaceholders.size() == 1) {
854 // We always have one fake placeholder
855 return boxes;
856 }
857 for (auto& line : fLines) {
858 line.getRectsForPlaceholders(boxes);
859 }
860 /*
861 SkDebugf("getRectsForPlaceholders('%s'): %d\n", fText.c_str(), boxes.size());
862 for (auto& r : boxes) {
863 r.rect.fLeft = littleRound(r.rect.fLeft);
864 r.rect.fRight = littleRound(r.rect.fRight);
865 r.rect.fTop = littleRound(r.rect.fTop);
866 r.rect.fBottom = littleRound(r.rect.fBottom);
867 SkDebugf("[%f:%f * %f:%f] %s\n", r.rect.fLeft, r.rect.fRight, r.rect.fTop, r.rect.fBottom,
868 (r.direction == TextDirection::kLtr ? "left" : "right"));
869 }
870 */
871 return boxes;
872}

◆ getRectsForRange()

std::vector< TextBox > skia::textlayout::ParagraphImpl::getRectsForRange ( unsigned  start,
unsigned  end,
RectHeightStyle  rectHeightStyle,
RectWidthStyle  rectWidthStyle 
)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 781 of file ParagraphImpl.cpp.

784 {
785 std::vector<TextBox> results;
786 if (fText.isEmpty()) {
787 if (start == 0 && end > 0) {
788 // On account of implied "\n" that is always at the end of the text
789 //SkDebugf("getRectsForRange(%d, %d): %f\n", start, end, fHeight);
790 results.emplace_back(SkRect::MakeXYWH(0, 0, 0, fHeight), fParagraphStyle.getTextDirection());
791 }
792 return results;
793 }
794
795 this->ensureUTF16Mapping();
796
797 if (start >= end || start > SkToSizeT(fUTF8IndexForUTF16Index.size()) || end == 0) {
798 return results;
799 }
800
801 // Adjust the text to grapheme edges
802 // Apparently, text editor CAN move inside graphemes but CANNOT select a part of it.
803 // I don't know why - the solution I have here returns an empty box for every query that
804 // does not contain an end of a grapheme.
805 // Once a cursor is inside a complex grapheme I can press backspace and cause trouble.
806 // To avoid any problems, I will not allow any selection of a part of a grapheme.
807 // One flutter test fails because of it but the editing experience is correct
808 // (although you have to press the cursor many times before it moves to the next grapheme).
809 TextRange text(fText.size(), fText.size());
810 // TODO: This is probably a temp change that makes SkParagraph work as TxtLib
811 // (so we can compare the results). We now include in the selection box only the graphemes
812 // that belongs to the given [start:end) range entirely (not the ones that intersect with it)
813 if (start < SkToSizeT(fUTF8IndexForUTF16Index.size())) {
814 auto utf8 = fUTF8IndexForUTF16Index[start];
815 // If start points to a trailing surrogate, skip it
816 if (start > 0 && fUTF8IndexForUTF16Index[start - 1] == utf8) {
817 utf8 = fUTF8IndexForUTF16Index[start + 1];
818 }
819 text.start = this->findNextGraphemeBoundary(utf8);
820 }
821 if (end < SkToSizeT(fUTF8IndexForUTF16Index.size())) {
822 auto utf8 = this->findPreviousGraphemeBoundary(fUTF8IndexForUTF16Index[end]);
823 text.end = utf8;
824 }
825 //SkDebugf("getRectsForRange(%d,%d) -> (%d:%d)\n", start, end, text.start, text.end);
826 for (auto& line : fLines) {
827 auto lineText = line.textWithNewlines();
828 auto intersect = lineText * text;
829 if (intersect.empty() && lineText.start != text.start) {
830 continue;
831 }
832
833 line.getRectsForRange(intersect, rectHeightStyle, rectWidthStyle, results);
834 }
835/*
836 SkDebugf("getRectsForRange(%d, %d)\n", start, end);
837 for (auto& r : results) {
838 r.rect.fLeft = littleRound(r.rect.fLeft);
839 r.rect.fRight = littleRound(r.rect.fRight);
840 r.rect.fTop = littleRound(r.rect.fTop);
841 r.rect.fBottom = littleRound(r.rect.fBottom);
842 SkDebugf("[%f:%f * %f:%f]\n", r.rect.fLeft, r.rect.fRight, r.rect.fTop, r.rect.fBottom);
843 }
844*/
845 return results;
846}
static bool intersect(const SkPoint &p0, const SkPoint &n0, const SkPoint &p1, const SkPoint &n1, SkScalar *t)
constexpr T * end() const
Definition SkSpan_impl.h:91
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659

◆ getStrutMetrics()

InternalLineMetrics skia::textlayout::ParagraphImpl::getStrutMetrics ( ) const
inline

Definition at line 233 of file ParagraphImpl.h.

233{ return fStrutMetrics; }

◆ getUnicode()

sk_sp< SkUnicode > skia::textlayout::ParagraphImpl::getUnicode ( )
inline

Definition at line 247 of file ParagraphImpl.h.

247{ return fUnicode; }

◆ getUTF16Index()

size_t skia::textlayout::ParagraphImpl::getUTF16Index ( TextIndex  index) const
inline

Definition at line 149 of file ParagraphImpl.h.

149 {
150 return fUTF16IndexForUTF8Index[index];
151 }

◆ getWordBoundary()

SkRange< size_t > skia::textlayout::ParagraphImpl::getWordBoundary ( unsigned  offset)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 906 of file ParagraphImpl.cpp.

906 {
907
908 if (fWords.empty()) {
909 if (!fUnicode->getWords(fText.c_str(), fText.size(), nullptr, &fWords)) {
910 return {0, 0 };
911 }
912 }
913
914 int32_t start = 0;
915 int32_t end = 0;
916 for (size_t i = 0; i < fWords.size(); ++i) {
917 auto word = fWords[i];
918 if (word <= offset) {
919 start = word;
920 end = word;
921 } else if (word > offset) {
922 end = word;
923 break;
924 }
925 }
926
927 //SkDebugf("getWordBoundary(%d): %d - %d\n", offset, start, end);
928 return { SkToU32(start), SkToU32(end) };
929}
constexpr uint32_t SkToU32(S x)
Definition SkTo.h:26
virtual bool getWords(const char utf8[], int utf8Units, const char *locale, std::vector< Position > *results)=0
intptr_t word
Definition globals.h:500

◆ layout()

void skia::textlayout::ParagraphImpl::layout ( SkScalar  width)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 137 of file ParagraphImpl.cpp.

137 {
138 // TODO: This rounding is done to match Flutter tests. Must be removed...
139 auto floorWidth = rawWidth;
140 if (getApplyRoundingHack()) {
141 floorWidth = SkScalarFloorToScalar(floorWidth);
142 }
143
144 if ((!SkIsFinite(rawWidth) || fLongestLine <= floorWidth) &&
145 fState >= kLineBroken &&
146 fLines.size() == 1 && fLines.front().ellipsis() == nullptr) {
147 // Most common case: one line of text (and one line is never justified, so no cluster shifts)
148 // We cannot mark it as kLineBroken because the new width can be bigger than the old width
149 fWidth = floorWidth;
150 fState = kShaped;
151 } else if (fState >= kLineBroken && fOldWidth != floorWidth) {
152 // We can use the results from SkShaper but have to do EVERYTHING ELSE again
153 fState = kShaped;
154 } else {
155 // Nothing changed case: we can reuse the data from the last layout
156 }
157
158 if (fState < kShaped) {
159 // Check if we have the text in the cache and don't need to shape it again
160 if (!fFontCollection->getParagraphCache()->findParagraph(this)) {
161 if (fState < kIndexed) {
162 // This only happens once at the first layout; the text is immutable
163 // and there is no reason to repeat it
164 if (this->computeCodeUnitProperties()) {
165 fState = kIndexed;
166 }
167 }
168 this->fRuns.clear();
169 this->fClusters.clear();
170 this->fClustersIndexFromCodeUnit.clear();
171 this->fClustersIndexFromCodeUnit.push_back_n(fText.size() + 1, EMPTY_INDEX);
172 if (!this->shapeTextIntoEndlessLine()) {
173 this->resetContext();
174 // TODO: merge the two next calls - they always come together
175 this->resolveStrut();
176 this->computeEmptyMetrics();
177 this->fLines.clear();
178
179 // Set the important values that are not zero
180 fWidth = floorWidth;
181 fHeight = fEmptyMetrics.height();
184 fHeight = fStrutMetrics.height();
185 }
186 fAlphabeticBaseline = fEmptyMetrics.alphabeticBaseline();
188 fLongestLine = FLT_MIN - FLT_MAX; // That is what flutter has
191 this->fOldWidth = floorWidth;
192 this->fOldHeight = this->fHeight;
193
194 return;
195 } else {
196 // Add the paragraph to the cache
197 fFontCollection->getParagraphCache()->updateParagraph(this);
198 }
199 }
200 fState = kShaped;
201 }
202
203 if (fState == kShaped) {
204 this->resetContext();
205 this->resolveStrut();
206 this->computeEmptyMetrics();
207 this->fLines.clear();
208 this->breakShapedTextIntoLines(floorWidth);
209 fState = kLineBroken;
210 }
211
212 if (fState == kLineBroken) {
213 // Build the picture lazily not until we actually have to paint (or never)
214 this->resetShifts();
215 this->formatLines(fWidth);
216 fState = kFormatted;
217 }
218
219 this->fOldWidth = floorWidth;
220 this->fOldHeight = this->fHeight;
221
222 if (getApplyRoundingHack()) {
223 // TODO: This rounding is done to match Flutter tests. Must be removed...
226 }
227
228 // TODO: This is strictly Flutter thing. Must be factored out into some flutter code
229 if (fParagraphStyle.getMaxLines() == 1 ||
232 }
233
234 // TODO: Since min and max are calculated differently it's possible to get a rounding error
235 // that would make min > max. Sort it out later, make it the same for now
238 }
239
240 //SkDebugf("layout('%s', %f): %f %f\n", fText.c_str(), rawWidth, fMinIntrinsicWidth, fMaxIntrinsicWidth);
241}
void breakShapedTextIntoLines(SkScalar maxWidth)
void formatLines(SkScalar maxWidth)
T * push_back_n(int n)
Definition SkTArray.h:262
const StrutStyle & getStrutStyle() const

◆ lineNumber()

size_t skia::textlayout::ParagraphImpl::lineNumber ( )
inlineoverridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 122 of file ParagraphImpl.h.

122{ return fLines.size(); }

◆ lines()

SkSpan< TextLine > skia::textlayout::ParagraphImpl::lines ( )
inline

Definition at line 138 of file ParagraphImpl.h.

138{ return SkSpan<TextLine>(fLines.data(), fLines.size()); }

◆ markDirty()

void skia::textlayout::ParagraphImpl::markDirty ( )
inlineoverridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 182 of file ParagraphImpl.h.

182 {
183 if (fState > kIndexed) {
184 fState = kIndexed;
185 }
186 }

◆ paint() [1/2]

void skia::textlayout::ParagraphImpl::paint ( ParagraphPainter canvas,
SkScalar  x,
SkScalar  y 
)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 248 of file ParagraphImpl.cpp.

248 {
249 for (auto& line : fLines) {
250 line.paint(painter, x, y);
251 }
252}
double y
double x

◆ paint() [2/2]

void skia::textlayout::ParagraphImpl::paint ( SkCanvas canvas,
SkScalar  x,
SkScalar  y 
)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 243 of file ParagraphImpl.cpp.

243 {
244 CanvasParagraphPainter painter(canvas);
245 paint(&painter, x, y);
246}
const Paint & paint

◆ paragraphStyle()

const ParagraphStyle & skia::textlayout::ParagraphImpl::paragraphStyle ( ) const
inline

Definition at line 139 of file ParagraphImpl.h.

139{ return fParagraphStyle; }

◆ placeholders()

SkSpan< Placeholder > skia::textlayout::ParagraphImpl::placeholders ( )
inline

Definition at line 135 of file ParagraphImpl.h.

135 {
136 return SkSpan<Placeholder>(fPlaceholders.data(), fPlaceholders.size());
137 }

◆ resetContext()

void skia::textlayout::ParagraphImpl::resetContext ( )

Definition at line 254 of file ParagraphImpl.cpp.

254 {
256 fHeight = 0;
257 fWidth = 0;
261 fLongestLine = 0;
262 fMaxWidthWithTrailingSpaces = 0;
263 fExceededMaxLines = false;
264}

◆ resetShifts()

void skia::textlayout::ParagraphImpl::resetShifts ( )
inline

Definition at line 237 of file ParagraphImpl.h.

237 {
238 for (auto& run : fRuns) {
239 run.resetJustificationShifts();
240 }
241 }

◆ resolvedFonts()

skia_private::TArray< ResolvedFontDescriptor > skia::textlayout::ParagraphImpl::resolvedFonts ( ) const
inline

Definition at line 180 of file ParagraphImpl.h.

180{ return fFontSwitches; }

◆ resolveStrut()

void skia::textlayout::ParagraphImpl::resolveStrut ( )

Definition at line 687 of file ParagraphImpl.cpp.

687 {
688 auto strutStyle = this->paragraphStyle().getStrutStyle();
689 if (!strutStyle.getStrutEnabled() || strutStyle.getFontSize() < 0) {
690 return;
691 }
692
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");
696 return;
697 }
698
699 SkFont font(typefaces.front(), strutStyle.getFontSize());
700 SkFontMetrics metrics;
701 font.getMetrics(&metrics);
702 const SkScalar strutLeading = strutStyle.getLeading() < 0 ? 0 : strutStyle.getLeading() * strutStyle.getFontSize();
703
704 if (strutStyle.getHeightOverride()) {
705 SkScalar strutAscent = 0.0f;
706 SkScalar strutDescent = 0.0f;
707 // The half leading flag doesn't take effect unless there's height override.
708 if (strutStyle.getHalfLeading()) {
709 const auto occupiedHeight = metrics.fDescent - metrics.fAscent;
710 auto flexibleHeight = strutStyle.getHeight() * strutStyle.getFontSize() - occupiedHeight;
711 // Distribute the flexible height evenly over and under.
712 flexibleHeight /= 2;
713 strutAscent = metrics.fAscent - flexibleHeight;
714 strutDescent = metrics.fDescent + flexibleHeight;
715 } else {
716 const SkScalar strutMetricsHeight = metrics.fDescent - metrics.fAscent + metrics.fLeading;
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;
722 }
723 fStrutMetrics = InternalLineMetrics(
724 strutAscent,
725 strutDescent,
726 strutLeading,
727 metrics.fAscent, metrics.fDescent, metrics.fLeading);
728 } else {
729 fStrutMetrics = InternalLineMetrics(
730 metrics.fAscent,
731 metrics.fDescent,
732 strutLeading);
733 }
734 fStrutMetrics.setForceStrut(this->paragraphStyle().getStrutStyle().getForceStrutHeight());
735}
#define SkDEBUGF(...)
Definition SkDebug.h:24
void setForceStrut(bool value)
Definition Run.h:500
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

◆ run()

Run & skia::textlayout::ParagraphImpl::run ( RunIndex  runIndex)
inline

Definition at line 172 of file ParagraphImpl.h.

172 {
173 SkASSERT(runIndex < SkToSizeT(fRuns.size()));
174 return fRuns[runIndex];
175 }

◆ runByCluster()

Run & skia::textlayout::ParagraphImpl::runByCluster ( ClusterIndex  clusterIndex)

Definition at line 955 of file ParagraphImpl.cpp.

955 {
956 auto start = cluster(clusterIndex);
957 return this->run(start.fRunIndex);
958}

◆ runs()

SkSpan< Run > skia::textlayout::ParagraphImpl::runs ( )
inline

Definition at line 131 of file ParagraphImpl.h.

131{ return SkSpan<Run>(fRuns.data(), fRuns.size()); }

◆ setState()

void skia::textlayout::ParagraphImpl::setState ( InternalState  state)

Definition at line 971 of file ParagraphImpl.cpp.

971 {
972 if (fState <= state) {
973 fState = state;
974 return;
975 }
976
977 fState = state;
978 switch (fState) {
979 case kUnknown:
980 SkASSERT(false);
981 /*
982 // The text is immutable and so are all the text indexing properties
983 // taken from SkUnicode
984 fCodeUnitProperties.reset();
985 fWords.clear();
986 fBidiRegions.clear();
987 fUTF8IndexForUTF16Index.reset();
988 fUTF16IndexForUTF8Index.reset();
989 */
990 [[fallthrough]];
991
992 case kIndexed:
993 fRuns.clear();
994 fClusters.clear();
995 [[fallthrough]];
996
997 case kShaped:
998 fLines.clear();
999 [[fallthrough]];
1000
1001 case kLineBroken:
1002 fPicture = nullptr;
1003 [[fallthrough]];
1004
1005 default:
1006 break;
1007 }
1008}
InternalState state() const

◆ shapeTextIntoEndlessLine()

bool skia::textlayout::ParagraphImpl::shapeTextIntoEndlessLine ( )

Definition at line 555 of file ParagraphImpl.cpp.

555 {
556
557 if (fText.size() == 0) {
558 return false;
559 }
560
561 fUnresolvedCodepoints.clear();
562 fFontSwitches.clear();
563
564 OneLineShaper oneLineShaper(this);
565 auto result = oneLineShaper.shape();
566 fUnresolvedGlyphs = oneLineShaper.unresolvedGlyphs();
567
569
570 return result;
571}

◆ state()

InternalState skia::textlayout::ParagraphImpl::state ( ) const
inline

Definition at line 130 of file ParagraphImpl.h.

130{ return fState; }

◆ strutEnabled()

bool skia::textlayout::ParagraphImpl::strutEnabled ( ) const
inline

Definition at line 153 of file ParagraphImpl.h.

◆ strutForceHeight()

bool skia::textlayout::ParagraphImpl::strutForceHeight ( ) const
inline

Definition at line 154 of file ParagraphImpl.h.

154 {
156 }

◆ strutHeightOverride()

bool skia::textlayout::ParagraphImpl::strutHeightOverride ( ) const
inline

Definition at line 157 of file ParagraphImpl.h.

157 {
159 }

◆ strutMetrics()

InternalLineMetrics skia::textlayout::ParagraphImpl::strutMetrics ( ) const
inline

Definition at line 160 of file ParagraphImpl.h.

160{ return fStrutMetrics; }

◆ styles()

SkSpan< Block > skia::textlayout::ParagraphImpl::styles ( )
inline

Definition at line 132 of file ParagraphImpl.h.

132 {
133 return SkSpan<Block>(fTextStyles.data(), fTextStyles.size());
134 }

◆ text() [1/2]

SkSpan< const char > skia::textlayout::ParagraphImpl::text ( ) const
inline

Definition at line 129 of file ParagraphImpl.h.

129{ return SkSpan<const char>(fText.c_str(), fText.size()); }

◆ text() [2/2]

SkSpan< const char > skia::textlayout::ParagraphImpl::text ( TextRange  textRange)

Definition at line 938 of file ParagraphImpl.cpp.

938 {
939 SkASSERT(textRange.start <= fText.size() && textRange.end <= fText.size());
940 auto start = fText.c_str() + textRange.start;
941 return SkSpan<const char>(start, textRange.width());
942}

◆ unresolvedCodepoints()

std::unordered_set< SkUnichar > skia::textlayout::ParagraphImpl::unresolvedCodepoints ( )
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 124 of file ParagraphImpl.cpp.

124 {
125 return fUnresolvedCodepoints;
126}

◆ unresolvedGlyphs()

int32_t skia::textlayout::ParagraphImpl::unresolvedGlyphs ( )
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 116 of file ParagraphImpl.cpp.

116 {
117 if (fState < kShaped) {
118 return -1;
119 }
120
121 return fUnresolvedGlyphs;
122}

◆ updateBackgroundPaint()

void skia::textlayout::ParagraphImpl::updateBackgroundPaint ( size_t  from,
size_t  to,
SkPaint  paint 
)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1112 of file ParagraphImpl.cpp.

1112 {
1113 SkASSERT(from == 0 && to == fText.size());
1114 auto defaultStyle = fParagraphStyle.getTextStyle();
1115 defaultStyle.setBackgroundColor(paint);
1116 fParagraphStyle.setTextStyle(defaultStyle);
1117
1118 for (auto& textStyle : fTextStyles) {
1119 textStyle.fStyle.setBackgroundColor(paint);
1120 }
1121}
void setBackgroundColor(SkPaint paint)
Definition TextStyle.h:204
void setTextStyle(const TextStyle &textStyle)
const TextStyle & getTextStyle() const

◆ updateFontSize()

void skia::textlayout::ParagraphImpl::updateFontSize ( size_t  from,
size_t  to,
SkScalar  fontSize 
)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1077 of file ParagraphImpl.cpp.

1077 {
1078
1079 SkASSERT(from == 0 && to == fText.size());
1080 auto defaultStyle = fParagraphStyle.getTextStyle();
1081 defaultStyle.setFontSize(fontSize);
1082 fParagraphStyle.setTextStyle(defaultStyle);
1083
1084 for (auto& textStyle : fTextStyles) {
1085 textStyle.fStyle.setFontSize(fontSize);
1086 }
1087
1088 fState = std::min(fState, kIndexed);
1089 fOldWidth = 0;
1090 fOldHeight = 0;
1091}
void setFontSize(SkScalar size)
Definition TextStyle.h:250

◆ updateForegroundPaint()

void skia::textlayout::ParagraphImpl::updateForegroundPaint ( size_t  from,
size_t  to,
SkPaint  paint 
)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1101 of file ParagraphImpl.cpp.

1101 {
1102 SkASSERT(from == 0 && to == fText.size());
1103 auto defaultStyle = fParagraphStyle.getTextStyle();
1104 defaultStyle.setForegroundColor(paint);
1105 fParagraphStyle.setTextStyle(defaultStyle);
1106
1107 for (auto& textStyle : fTextStyles) {
1108 textStyle.fStyle.setForegroundColor(paint);
1109 }
1110}
void setForegroundColor(SkPaint paint)
Definition TextStyle.h:181

◆ updateTextAlign()

void skia::textlayout::ParagraphImpl::updateTextAlign ( TextAlign  textAlign)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1093 of file ParagraphImpl.cpp.

1093 {
1094 fParagraphStyle.setTextAlign(textAlign);
1095
1096 if (fState >= kLineBroken) {
1097 fState = kLineBroken;
1098 }
1099}
void setTextAlign(TextAlign align)

◆ visit()

void skia::textlayout::ParagraphImpl::visit ( const Visitor visitor)
overridevirtual

Implements skia::textlayout::Paragraph.

Definition at line 1179 of file ParagraphImpl.cpp.

1179 {
1180 int lineNumber = 0;
1181 for (auto& line : fLines) {
1182 line.ensureTextBlobCachePopulated();
1183 for (auto& rec : line.fTextBlobCache) {
1184 if (rec.fBlob == nullptr) {
1185 continue;
1186 }
1187 SkTextBlob::Iter iter(*rec.fBlob);
1189
1190 STArray<128, uint32_t> clusterStorage;
1191 const Run* R = rec.fVisitor_Run;
1192 const uint32_t* clusterPtr = &R->fClusterIndexes[0];
1193
1194 if (R->fClusterStart > 0) {
1195 int count = R->fClusterIndexes.size();
1196 clusterStorage.reset(count);
1197 for (int i = 0; i < count; ++i) {
1198 clusterStorage[i] = R->fClusterStart + R->fClusterIndexes[i];
1199 }
1200 clusterPtr = &clusterStorage[0];
1201 }
1202 clusterPtr += rec.fVisitor_Pos;
1203
1204 while (iter.experimentalNext(&run)) {
1205 const Paragraph::VisitorInfo info = {
1206 run.font,
1207 rec.fOffset,
1208 rec.fClipRect.fRight,
1209 run.count,
1210 run.glyphs,
1211 run.positions,
1212 clusterPtr,
1213 0, // flags
1214 };
1215 visitor(lineNumber, &info);
1216 clusterPtr += run.count;
1217 }
1218 }
1219 visitor(lineNumber, nullptr); // signal end of line
1220 lineNumber += 1;
1221 }
1222}
#define R(r)

◆ widthWithTrailingSpaces()

SkScalar skia::textlayout::ParagraphImpl::widthWithTrailingSpaces ( )
inline

Definition at line 195 of file ParagraphImpl.h.

195{ return fMaxWidthWithTrailingSpaces; }

Friends And Related Symbol Documentation

◆ OneLineShaper

friend class OneLineShaper
friend

Definition at line 256 of file ParagraphImpl.h.

◆ ParagraphBuilder

friend class ParagraphBuilder
friend

Definition at line 250 of file ParagraphImpl.h.

◆ ParagraphCache

friend class ParagraphCache
friend

Definition at line 253 of file ParagraphImpl.h.

◆ ParagraphCacheKey

friend class ParagraphCacheKey
friend

Definition at line 251 of file ParagraphImpl.h.

◆ ParagraphCacheValue

friend class ParagraphCacheValue
friend

Definition at line 252 of file ParagraphImpl.h.

◆ TextWrapper

friend class TextWrapper
friend

Definition at line 255 of file ParagraphImpl.h.


The documentation for this class was generated from the following files: