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