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