• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 Google LLC.
2 #ifndef VisualRun_DEFINED
3 #define VisualRun_DEFINED
4 
5 #include "experimental/sktext/include/Types.h"
6 #include "experimental/sktext/src/Line.h"
7 #include "modules/skshaper/include/SkShaper.h"
8 
9 namespace skia {
10 namespace text {
11 
12 class VisualRun {
13     public:
VisualRun(TextRange textRange,GlyphIndex trailingSpacesStart,const SkFont & font,SkScalar lineBaseLine,SkPoint runOffset,bool leftToRight,SkSpan<SkPoint> positions,SkSpan<SkGlyphID> glyphs,SkSpan<uint32_t> clusters)14     VisualRun(TextRange textRange, GlyphIndex trailingSpacesStart, const SkFont& font, SkScalar lineBaseLine,
15               SkPoint runOffset,
16               bool leftToRight,
17               SkSpan<SkPoint> positions, SkSpan<SkGlyphID> glyphs, SkSpan<uint32_t> clusters)
18         : fFont(font)
19         , fTextMetrics(TextMetrics(fFont))
20         , fLineBaseLine(lineBaseLine)
21         , fDirTextRange(textRange, leftToRight)
22         , fTrailingSpacesStart(trailingSpacesStart) {
23         if (positions.size() == 0) {
24             SkASSERT(false);
25             return;
26         }
27         fPositions.reserve_back(positions.size());
28         runOffset -= SkPoint::Make(positions[0].fX, - fLineBaseLine);
29         for (auto& pos : positions) {
30             fPositions.emplace_back(pos + runOffset);
31         }
32         fGlyphs.reserve_back(glyphs.size());
33         for (auto glyph : glyphs) {
34             fGlyphs.emplace_back(glyph);
35         }
36         fClusters.reserve_back(clusters.size());
37         for (auto cluster : clusters) {
38             fClusters.emplace_back(SkToU16(cluster));
39         }
40         fAdvance= SkVector::Make(this->calculateWidth(0, glyphs.size()), fTextMetrics.height());
41     }
42 
calculateWidth(GlyphRange glyphRange)43     SkScalar calculateWidth(GlyphRange glyphRange) const {
44         SkASSERT(glyphRange.fStart <= glyphRange.fEnd && glyphRange.fEnd < fPositions.size());
45         return fPositions[glyphRange.fEnd].fX - fPositions[glyphRange.fStart].fX;
46     }
calculateWidth(GlyphIndex start,GlyphIndex end)47     SkScalar calculateWidth(GlyphIndex start, GlyphIndex end) const {
48       return calculateWidth(GlyphRange(start, end));
49     }
width()50     SkScalar width() const { return fAdvance.fX; }
height()51     SkScalar height() const { return fAdvance.fY; }
firstGlyphPosition()52     SkScalar firstGlyphPosition() const { return fPositions[0].fX; }
textMetrics()53     TextMetrics textMetrics() const { return fTextMetrics; }
54 
leftToRight()55     bool leftToRight() const { return fDirTextRange.fLeftToRight; }
size()56     size_t size() const { return fGlyphs.size(); }
baseLine()57     SkScalar baseLine() const { return fLineBaseLine; }
trailingSpacesStart()58     GlyphIndex trailingSpacesStart() const { return fTrailingSpacesStart; }
dirTextRange()59     DirTextRange dirTextRange() const { return fDirTextRange; }
60 
61     template <typename Callback>
forEachTextBlockInGlyphRange(SkSpan<TextIndex> textBlock,Callback && callback)62     void forEachTextBlockInGlyphRange(SkSpan<TextIndex> textBlock, Callback&& callback) const {
63         if (this->leftToRight()) {
64             DirTextRange dirTextRange(fDirTextRange.fStart, fDirTextRange.fStart, fDirTextRange.fLeftToRight);
65             for (auto currentIndex : textBlock) {
66                 if (currentIndex >= fDirTextRange.fEnd) {
67                     break;
68                 }
69                 if (currentIndex < fDirTextRange.fStart) {
70                     continue;
71                 }
72                 dirTextRange.fStart = dirTextRange.fEnd;
73                 dirTextRange.fEnd = currentIndex;
74                 dirTextRange.fEnd = std::min(fDirTextRange.fEnd, dirTextRange.fEnd);
75 
76                 callback(dirTextRange);
77             }
78         } else {
79             // Revert chunks
80             std::vector<TextIndex> revertedChunks;
81         }
82     }
83 
84     private:
85     friend class WrappedText;
86     SkFont fFont;
87     TextMetrics fTextMetrics;
88     SkScalar fLineBaseLine;
89 
90     SkVector fAdvance;
91     DirTextRange fDirTextRange;
92     SkSTArray<128, SkGlyphID, true> fGlyphs;
93     SkSTArray<128, SkPoint, true> fPositions;
94     SkSTArray<128, TextIndex, true> fClusters;
95     GlyphIndex fTrailingSpacesStart;
96 };
97 
98 class VisualLine {
99 public:
VisualLine(TextRange text,bool hardLineBreak,SkScalar verticalOffset,SkSpan<VisualRun> runs)100     VisualLine(TextRange text, bool hardLineBreak, SkScalar verticalOffset, SkSpan<VisualRun> runs)
101         : fText(text)
102         , fRuns(runs)
103         , fTrailingSpaces(0, 0)
104         , fOffset(SkPoint::Make(0, verticalOffset))
105         , fActualWidth(0.0f)
106         , fTextMetrics()
107         , fIsHardBreak(hardLineBreak)
108         , fGlyphCount(0ul) {
109         // Calculate all the info
110         for (auto& run : fRuns) {
111             fTextMetrics.merge(run.textMetrics());
112             fActualWidth += run.width();  // What about trailing spaces?
113             if (run.trailingSpacesStart() == 0) {
114                 // The entire run is trailing spaces, do not move the counter
115             } else {
116                 // We can reset the trailing spaces counter
117                 fTrailingSpaces.fStart = fTrailingSpaces.fEnd + run.trailingSpacesStart();
118             }
119             fTrailingSpaces.fEnd += run.size();
120         }
121     }
122 
baseline()123     SkScalar baseline() const { return fTextMetrics.baseline(); }
text()124     TextRange text() const { return fText; }
trailingSpaces()125     GlyphRange trailingSpaces() const { return fTrailingSpaces; }
isHardBreak()126     bool isHardBreak() const { return fIsHardBreak; }
glyphCount()127     size_t glyphCount() const { return fGlyphCount; }
128 
isFirst(VisualRun * run)129     bool isFirst(VisualRun* run) { return &fRuns.front() == run; }
isLast(VisualRun * run)130     bool isLast(VisualRun* run) { return &fRuns.back() == run; }
131 private:
132     friend class WrappedText;
133     friend class VisualRun;
134     TextRange fText;
135     SkSpan<VisualRun> fRuns;
136     GlyphRange fTrailingSpaces; // This is a zero-based index across the line
137     SkPoint fOffset;            // For left/right/center formatting and for height
138     SkScalar fActualWidth;
139     TextMetrics fTextMetrics;
140     bool fIsHardBreak;
141     size_t fGlyphCount;
142 };
143 }; // namespace text
144 } // namespace skia
145 #endif
146