• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC.
2 #ifndef TextWrapper_DEFINED
3 #define TextWrapper_DEFINED
4 
5 #include <string>
6 #include "include/core/SkSpan.h"
7 #include "modules/skparagraph/src/TextLine.h"
8 
9 namespace skia {
10 namespace textlayout {
11 
12 class ParagraphImpl;
13 
14 class TextWrapper {
15     class ClusterPos {
16     public:
ClusterPos()17         ClusterPos() : fCluster(nullptr), fPos(0) {}
ClusterPos(Cluster * cluster,size_t pos)18         ClusterPos(Cluster* cluster, size_t pos) : fCluster(cluster), fPos(pos) {}
cluster()19         inline Cluster* cluster() const { return fCluster; }
position()20         inline size_t position() const { return fPos; }
setPosition(size_t pos)21         inline void setPosition(size_t pos) { fPos = pos; }
clean()22         void clean() {
23             fCluster = nullptr;
24             fPos = 0;
25         }
move(bool up)26         void move(bool up) {
27             fCluster += up ? 1 : -1;
28             fPos = up ? 0 : fCluster->endPos();
29         }
30 
31     private:
32         Cluster* fCluster;
33         size_t fPos;
34     };
35     class TextStretch {
36     public:
TextStretch()37         TextStretch() : fStart(), fEnd(), fWidth(0), fWidthWithGhostSpaces(0) {}
TextStretch(Cluster * s,Cluster * e,bool forceStrut)38         TextStretch(Cluster* s, Cluster* e, bool forceStrut)
39                 : fStart(s, 0), fEnd(e, e->endPos()), fMetrics(forceStrut), fWidth(0), fWidthWithGhostSpaces(0) {
40             for (auto c = s; c <= e; ++c) {
41                 if (auto r = c->runOrNull()) {
42                     fMetrics.add(r);
43                 }
44                 if (c < e) {
45                     fWidth += c->width();
46                 }
47             }
48             fWidthWithGhostSpaces = fWidth;
49         }
50 
width()51         inline SkScalar width() const { return fWidth; }
widthWithGhostSpaces()52         SkScalar widthWithGhostSpaces() const { return fWidthWithGhostSpaces; }
startCluster()53         inline Cluster* startCluster() const { return fStart.cluster(); }
endCluster()54         inline Cluster* endCluster() const { return fEnd.cluster(); }
breakCluster()55         inline Cluster* breakCluster() const { return fBreak.cluster(); }
metrics()56         inline InternalLineMetrics& metrics() { return fMetrics; }
startPos()57         inline size_t startPos() const { return fStart.position(); }
endPos()58         inline size_t endPos() const { return fEnd.position(); }
endOfCluster()59         bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); }
endOfWord()60         bool endOfWord() {
61             return endOfCluster() &&
62                    (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak());
63         }
64 
extend(TextStretch & stretch)65         void extend(TextStretch& stretch) {
66             fMetrics.add(stretch.fMetrics);
67             fEnd = stretch.fEnd;
68             fWidth += stretch.fWidth;
69             stretch.clean();
70         }
71 
empty()72         bool empty() { return fStart.cluster() == fEnd.cluster() &&
73                               fStart.position() == fEnd.position(); }
74 
setMetrics(const InternalLineMetrics & metrics)75         void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; }
76 
extend(Cluster * cluster)77         void extend(Cluster* cluster) {
78             if (fStart.cluster() == nullptr) {
79                 fStart = ClusterPos(cluster, cluster->startPos());
80             }
81             fEnd = ClusterPos(cluster, cluster->endPos());
82             // TODO: Make sure all the checks are correct and there are no unnecessary checks
83             auto& r = cluster->run();
84             if (!cluster->isHardBreak() && !r.isPlaceholder()) {
85                 // We ignore metrics for \n as the Flutter does
86                 fMetrics.add(&r);
87             }
88             fWidth += cluster->width();
89         }
90 
extend(Cluster * cluster,size_t pos)91         void extend(Cluster* cluster, size_t pos) {
92             fEnd = ClusterPos(cluster, pos);
93             if (auto r = cluster->runOrNull()) {
94                 fMetrics.add(r);
95             }
96         }
97 
startFrom(Cluster * cluster,size_t pos)98         void startFrom(Cluster* cluster, size_t pos) {
99             fStart = ClusterPos(cluster, pos);
100             fEnd = ClusterPos(cluster, pos);
101             if (auto r = cluster->runOrNull()) {
102                 // In case of placeholder we should ignore the default text style -
103                 // we will pick up the correct one from the placeholder
104                 if (!r->isPlaceholder()) {
105                     fMetrics.add(r);
106                 }
107             }
108             fWidth = 0;
109         }
110 
saveBreak()111         void saveBreak() {
112             fWidthWithGhostSpaces = fWidth;
113             fBreak = fEnd;
114         }
115 
restoreBreak()116         void restoreBreak() {
117             fWidth = fWidthWithGhostSpaces;
118             fEnd = fBreak;
119         }
120 
shiftBreak()121         void shiftBreak() {
122             fBreak.move(true);
123         }
124 
trim()125         void trim() {
126 
127             if (fEnd.cluster() != nullptr &&
128                 fEnd.cluster()->owner() != nullptr &&
129                 fEnd.cluster()->runOrNull() != nullptr &&
130                 fEnd.cluster()->run().placeholderStyle() == nullptr &&
131                 fWidth > 0) {
132                 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position()));
133             }
134         }
135 
trim(Cluster * cluster)136         void trim(Cluster* cluster) {
137             SkASSERT(fEnd.cluster() == cluster);
138             if (fEnd.cluster() > fStart.cluster()) {
139                 fEnd.move(false);
140                 fWidth -= cluster->width();
141             } else {
142                 fEnd.setPosition(fStart.position());
143                 fWidth = 0;
144             }
145         }
146 
clean()147         void clean() {
148             fStart.clean();
149             fEnd.clean();
150             fWidth = 0;
151             fMetrics.clean();
152         }
153 
154     private:
155         ClusterPos fStart;
156         ClusterPos fEnd;
157         ClusterPos fBreak;
158         InternalLineMetrics fMetrics;
159         SkScalar fWidth;
160         SkScalar fWidthWithGhostSpaces;
161     };
162 
163 public:
TextWrapper()164     TextWrapper() {
165          fLineNumber = 1;
166          fHardLineBreak = false;
167          fExceededMaxLines = false;
168     }
169 
170     using AddLineToParagraph = std::function<void(TextRange textExcludingSpaces,
171                                                   TextRange text,
172                                                   TextRange textIncludingNewlines,
173                                                   ClusterRange clusters,
174                                                   ClusterRange clustersWithGhosts,
175                                                   SkScalar AddLineToParagraph,
176                                                   size_t startClip,
177                                                   size_t endClip,
178                                                   SkVector offset,
179                                                   SkVector advance,
180                                                   InternalLineMetrics metrics,
181                                                   bool addEllipsis)>;
182     void breakTextIntoLines(ParagraphImpl* parent,
183                             SkScalar maxWidth,
184                             const AddLineToParagraph& addLine);
185 
height()186     SkScalar height() const { return fHeight; }
minIntrinsicWidth()187     SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; }
maxIntrinsicWidth()188     SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; }
exceededMaxLines()189     bool exceededMaxLines() const { return fExceededMaxLines; }
190 
191 private:
192     TextStretch fWords;
193     TextStretch fClusters;
194     TextStretch fClip;
195     TextStretch fEndLine;
196     size_t fLineNumber;
197     bool fTooLongWord;
198     bool fTooLongCluster;
199 
200     bool fHardLineBreak;
201     bool fExceededMaxLines;
202 
203     SkScalar fHeight;
204     SkScalar fMinIntrinsicWidth;
205     SkScalar fMaxIntrinsicWidth;
206 
reset()207     void reset() {
208         fWords.clean();
209         fClusters.clean();
210         fClip.clean();
211         fTooLongCluster = false;
212         fTooLongWord = false;
213     }
214 
215     void lookAhead(SkScalar maxWidth, Cluster* endOfClusters);
216     void moveForward(bool hasEllipsis);
217     void trimEndSpaces(TextAlign align);
218     std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters);
219     SkScalar getClustersTrimmedWidth();
220 };
221 }  // namespace textlayout
222 }  // namespace skia
223 
224 #endif  // TextWrapper_DEFINED
225