• 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 "modules/skparagraph/src/TextLine.h"
7 #include "src/core/SkSpan.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 (c->run() != nullptr) {
42                     fMetrics.add(c->run());
43                 }
44             }
45         }
46 
width()47         inline SkScalar width() const { return fWidth; }
widthWithGhostSpaces()48         SkScalar widthWithGhostSpaces() const { return fWidthWithGhostSpaces; }
startCluster()49         inline Cluster* startCluster() const { return fStart.cluster(); }
endCluster()50         inline Cluster* endCluster() const { return fEnd.cluster(); }
breakCluster()51         inline Cluster* breakCluster() const { return fBreak.cluster(); }
metrics()52         inline InternalLineMetrics& metrics() { return fMetrics; }
startPos()53         inline size_t startPos() const { return fStart.position(); }
endPos()54         inline size_t endPos() const { return fEnd.position(); }
endOfCluster()55         bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); }
endOfWord()56         bool endOfWord() {
57             return endOfCluster() &&
58                    (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak());
59         }
60 
extend(TextStretch & stretch)61         void extend(TextStretch& stretch) {
62             fMetrics.add(stretch.fMetrics);
63             fEnd = stretch.fEnd;
64             fWidth += stretch.fWidth;
65             stretch.clean();
66         }
67 
empty()68         bool empty() { return fStart.cluster() == fEnd.cluster() &&
69                               fStart.position() == fEnd.position(); }
70 
setMetrics(const InternalLineMetrics & metrics)71         void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; }
72 
extend(Cluster * cluster)73         void extend(Cluster* cluster) {
74             if (fStart.cluster() == nullptr) {
75                 fStart = ClusterPos(cluster, cluster->startPos());
76             }
77             fEnd = ClusterPos(cluster, cluster->endPos());
78             if (!cluster->run()->isPlaceholder()) {
79                 fMetrics.add(cluster->run());
80             }
81             fWidth += cluster->width();
82         }
83 
extend(Cluster * cluster,size_t pos)84         void extend(Cluster* cluster, size_t pos) {
85             fEnd = ClusterPos(cluster, pos);
86             if (cluster->run() != nullptr) {
87                 fMetrics.add(cluster->run());
88             }
89         }
90 
startFrom(Cluster * cluster,size_t pos)91         void startFrom(Cluster* cluster, size_t pos) {
92             fStart = ClusterPos(cluster, pos);
93             fEnd = ClusterPos(cluster, pos);
94             if (cluster->run() != nullptr) {
95                 fMetrics.add(cluster->run());
96             }
97             fWidth = 0;
98         }
99 
saveBreak()100         void saveBreak() {
101             fWidthWithGhostSpaces = fWidth;
102             fBreak = fEnd;
103         }
104 
restoreBreak()105         void restoreBreak() {
106             fWidth = fWidthWithGhostSpaces;
107             fEnd = fBreak;
108         }
109 
trim()110         void trim() {
111 
112             if (fEnd.cluster() != nullptr &&
113                 fEnd.cluster()->master() != nullptr &&
114                 fEnd.cluster()->run() != nullptr &&
115                 fEnd.cluster()->run()->placeholderStyle() == nullptr &&
116                 fWidth > 0) {
117                 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position()));
118             }
119         }
120 
trim(Cluster * cluster)121         void trim(Cluster* cluster) {
122             SkASSERT(fEnd.cluster() == cluster);
123             if (fEnd.cluster() > fStart.cluster()) {
124                 fEnd.move(false);
125                 fWidth -= cluster->width();
126             } else {
127                 fWidth = 0;
128             }
129         }
130 
clean()131         void clean() {
132             fStart.clean();
133             fEnd.clean();
134             fWidth = 0;
135             fMetrics.clean();
136         }
137 
138     private:
139         ClusterPos fStart;
140         ClusterPos fEnd;
141         ClusterPos fBreak;
142         InternalLineMetrics fMetrics;
143         SkScalar fWidth;
144         SkScalar fWidthWithGhostSpaces;
145     };
146 
147 public:
TextWrapper()148     TextWrapper() {
149          fLineNumber = 1;
150          fHardLineBreak = false;
151          fExceededMaxLines = false;
152     }
153 
154     using AddLineToParagraph = std::function<void(TextRange text,
155                                                   TextRange textWithSpaces,
156                                                   ClusterRange clusters,
157                                                   ClusterRange clustersWithGhosts,
158                                                   SkScalar AddLineToParagraph,
159                                                   size_t startClip,
160                                                   size_t endClip,
161                                                   SkVector offset,
162                                                   SkVector advance,
163                                                   InternalLineMetrics metrics,
164                                                   bool addEllipsis)>;
165     void breakTextIntoLines(ParagraphImpl* parent,
166                             SkScalar maxWidth,
167                             const AddLineToParagraph& addLine);
168 
height()169     SkScalar height() const { return fHeight; }
minIntrinsicWidth()170     SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; }
maxIntrinsicWidth()171     SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; }
exceededMaxLines()172     bool exceededMaxLines() const { return fExceededMaxLines; }
173 
174 private:
175     TextStretch fWords;
176     TextStretch fClusters;
177     TextStretch fClip;
178     TextStretch fEndLine;
179     size_t fLineNumber;
180     bool fTooLongWord;
181     bool fTooLongCluster;
182 
183     bool fHardLineBreak;
184     bool fExceededMaxLines;
185 
186     SkScalar fHeight;
187     SkScalar fMinIntrinsicWidth;
188     SkScalar fMaxIntrinsicWidth;
189 
reset()190     void reset() {
191         fWords.clean();
192         fClusters.clean();
193         fClip.clean();
194         fTooLongCluster = false;
195         fTooLongWord = false;
196     }
197 
198     void lookAhead(SkScalar maxWidth, Cluster* endOfClusters);
199     void moveForward(bool hasEllipsis);
200     void trimEndSpaces(TextAlign align);
201     std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters);
202     SkScalar getClustersTrimmedWidth();
203 };
204 }  // namespace textlayout
205 }  // namespace skia
206 
207 #endif  // TextWrapper_DEFINED
208