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