• 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 &&
45                  glyphRange.fEnd < SkToSizeT(fPositions.size()));
46         return fPositions[glyphRange.fEnd].fX - fPositions[glyphRange.fStart].fX;
47     }
calculateWidth(GlyphIndex start,GlyphIndex end)48     SkScalar calculateWidth(GlyphIndex start, GlyphIndex end) const {
49       return calculateWidth(GlyphRange(start, end));
50     }
width()51     SkScalar width() const { return fAdvance.fX; }
height()52     SkScalar height() const { return fAdvance.fY; }
firstGlyphPosition()53     SkScalar firstGlyphPosition() const { return fPositions[0].fX; }
textMetrics()54     TextMetrics textMetrics() const { return fTextMetrics; }
55 
leftToRight()56     bool leftToRight() const { return fDirTextRange.fLeftToRight; }
size()57     size_t size() const { return fGlyphs.size(); }
baseLine()58     SkScalar baseLine() const { return fLineBaseLine; }
trailingSpacesStart()59     GlyphIndex trailingSpacesStart() const { return fTrailingSpacesStart; }
dirTextRange()60     DirTextRange dirTextRange() const { return fDirTextRange; }
61 
62     template <typename Callback>
forEachTextBlockInGlyphRange(SkSpan<TextIndex> textBlock,Callback && callback)63     void forEachTextBlockInGlyphRange(SkSpan<TextIndex> textBlock, Callback&& callback) const {
64         if (this->leftToRight()) {
65             DirTextRange dirTextRange(fDirTextRange.fStart, fDirTextRange.fStart, fDirTextRange.fLeftToRight);
66             for (auto currentIndex : textBlock) {
67                 if (currentIndex >= fDirTextRange.fEnd) {
68                     break;
69                 }
70                 if (currentIndex < fDirTextRange.fStart) {
71                     continue;
72                 }
73                 dirTextRange.fStart = dirTextRange.fEnd;
74                 dirTextRange.fEnd = currentIndex;
75                 dirTextRange.fEnd = std::min(fDirTextRange.fEnd, dirTextRange.fEnd);
76 
77                 callback(dirTextRange);
78             }
79         } else {
80             // Revert chunks
81             std::vector<TextIndex> revertedChunks;
82         }
83     }
84 
85     private:
86     friend class WrappedText;
87     SkFont fFont;
88     TextMetrics fTextMetrics;
89     SkScalar fLineBaseLine;
90 
91     SkVector fAdvance;
92     DirTextRange fDirTextRange;
93     SkSTArray<128, SkGlyphID, true> fGlyphs;
94     SkSTArray<128, SkPoint, true> fPositions;
95     SkSTArray<128, TextIndex, true> fClusters;
96     GlyphIndex fTrailingSpacesStart;
97 };
98 
99 class VisualLine {
100 public:
VisualLine(TextRange text,bool hardLineBreak,SkScalar verticalOffset,SkSpan<VisualRun> runs)101     VisualLine(TextRange text, bool hardLineBreak, SkScalar verticalOffset, SkSpan<VisualRun> runs)
102         : fText(text)
103         , fRuns(runs)
104         , fTrailingSpaces(0, 0)
105         , fOffset(SkPoint::Make(0, verticalOffset))
106         , fActualWidth(0.0f)
107         , fTextMetrics()
108         , fIsHardBreak(hardLineBreak)
109         , fGlyphCount(0ul) {
110         // Calculate all the info
111         for (auto& run : fRuns) {
112             fTextMetrics.merge(run.textMetrics());
113             fActualWidth += run.width();  // What about trailing spaces?
114             if (run.trailingSpacesStart() == 0) {
115                 // The entire run is trailing spaces, do not move the counter
116             } else {
117                 // We can reset the trailing spaces counter
118                 fTrailingSpaces.fStart = fTrailingSpaces.fEnd + run.trailingSpacesStart();
119             }
120             fTrailingSpaces.fEnd += run.size();
121         }
122     }
123 
baseline()124     SkScalar baseline() const { return fTextMetrics.baseline(); }
text()125     TextRange text() const { return fText; }
trailingSpaces()126     GlyphRange trailingSpaces() const { return fTrailingSpaces; }
isHardBreak()127     bool isHardBreak() const { return fIsHardBreak; }
glyphCount()128     size_t glyphCount() const { return fGlyphCount; }
129 
isFirst(VisualRun * run)130     bool isFirst(VisualRun* run) { return &fRuns.front() == run; }
isLast(VisualRun * run)131     bool isLast(VisualRun* run) { return &fRuns.back() == run; }
132 private:
133     friend class WrappedText;
134     friend class VisualRun;
135     TextRange fText;
136     SkSpan<VisualRun> fRuns;
137     GlyphRange fTrailingSpaces; // This is a zero-based index across the line
138     SkPoint fOffset;            // For left/right/center formatting and for height
139     SkScalar fActualWidth;
140     TextMetrics fTextMetrics;
141     bool fIsHardBreak;
142     size_t fGlyphCount;
143 };
144 } // namespace text
145 } // namespace skia
146 #endif
147