blob: e9ef3042744b29710af28b2408ff626c952e7521 [file] [log] [blame]
Julia Lavrovaa3552c52019-05-30 16:12:56 -04001// 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
9namespace skia {
10namespace textlayout {
11
12class ParagraphImpl;
13
14class TextWrapper {
15 class ClusterPos {
16 public:
17 ClusterPos() : fCluster(nullptr), fPos(0) {}
18 ClusterPos(Cluster* cluster, size_t pos) : fCluster(cluster), fPos(pos) {}
Julia Lavrova5207f352019-06-21 12:22:32 -040019 inline Cluster* cluster() const { return fCluster; }
20 inline size_t position() const { return fPos; }
21 inline void setPosition(size_t pos) { fPos = pos; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -040022 void clean() {
23 fCluster = nullptr;
24 fPos = 0;
25 }
Julia Lavrova5207f352019-06-21 12:22:32 -040026 void move(bool up) {
27 fCluster += up ? 1 : -1;
28 fPos = up ? 0 : fCluster->endPos();
29}
Julia Lavrovaa3552c52019-05-30 16:12:56 -040030
31 private:
32 Cluster* fCluster;
33 size_t fPos;
34 };
35 class TextStretch {
36 public:
Julia Lavrovadb9f6692019-08-01 16:02:17 -040037 TextStretch() : fStart(), fEnd(), fWidth(0), fWidthWithGhostSpaces(0) {}
38 TextStretch(Cluster* s, Cluster* e, bool forceStrut)
39 : fStart(s, 0), fEnd(e, e->endPos()), fMetrics(forceStrut), fWidth(0), fWidthWithGhostSpaces(0) {
Julia Lavrovaa3552c52019-05-30 16:12:56 -040040 for (auto c = s; c <= e; ++c) {
41 if (c->run() != nullptr) {
42 fMetrics.add(c->run());
43 }
44 }
45 }
46
Julia Lavrova5207f352019-06-21 12:22:32 -040047 inline SkScalar width() const { return fWidth; }
Julia Lavrovadb9f6692019-08-01 16:02:17 -040048 SkScalar withWithGhostSpaces() const { return fWidthWithGhostSpaces; }
Julia Lavrova5207f352019-06-21 12:22:32 -040049 inline Cluster* startCluster() const { return fStart.cluster(); }
50 inline Cluster* endCluster() const { return fEnd.cluster(); }
51 inline Cluster* breakCluster() const { return fBreak.cluster(); }
Julia Lavrovaf3ed2732019-09-05 14:35:17 -040052 inline InternalLineMetrics& metrics() { return fMetrics; }
Julia Lavrova5207f352019-06-21 12:22:32 -040053 inline size_t startPos() const { return fStart.position(); }
54 inline size_t endPos() const { return fEnd.position(); }
Julia Lavrovaa3552c52019-05-30 16:12:56 -040055 bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); }
56 bool endOfWord() {
57 return endOfCluster() &&
58 (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak());
59 }
60
61 void extend(TextStretch& stretch) {
62 fMetrics.add(stretch.fMetrics);
63 fEnd = stretch.fEnd;
64 fWidth += stretch.fWidth;
65 stretch.clean();
66 }
67
Julia Lavrovaf3ed2732019-09-05 14:35:17 -040068 void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; }
69
Julia Lavrovaa3552c52019-05-30 16:12:56 -040070 void extend(Cluster* cluster) {
Julia Lavrova9af5cc42019-06-19 13:32:01 -040071 if (fStart.cluster() == nullptr) {
72 fStart = ClusterPos(cluster, cluster->startPos());
73 }
Julia Lavrovaa3552c52019-05-30 16:12:56 -040074 fEnd = ClusterPos(cluster, cluster->endPos());
Julia Lavrovaf3ed2732019-09-05 14:35:17 -040075 if (!cluster->run()->isPlaceholder()) {
76 fMetrics.add(cluster->run());
77 }
Julia Lavrovaa3552c52019-05-30 16:12:56 -040078 fWidth += cluster->width();
79 }
80
81 void extend(Cluster* cluster, size_t pos) {
82 fEnd = ClusterPos(cluster, pos);
83 if (cluster->run() != nullptr) {
84 fMetrics.add(cluster->run());
85 }
86 }
87
88 void startFrom(Cluster* cluster, size_t pos) {
89 fStart = ClusterPos(cluster, pos);
90 fEnd = ClusterPos(cluster, pos);
91 if (cluster->run() != nullptr) {
92 fMetrics.add(cluster->run());
93 }
94 fWidth = 0;
95 }
96
Julia Lavrovadb9f6692019-08-01 16:02:17 -040097 void saveBreak() {
98 fWidthWithGhostSpaces = fWidth;
99 fBreak = fEnd;
100 }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400101
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400102 void trim() {
Julia Lavrova526df262019-08-21 17:49:44 -0400103
104 if (fEnd.cluster() != nullptr &&
105 fEnd.cluster()->master() != nullptr &&
106 fEnd.cluster()->run() != nullptr &&
Julia Lavrova2e30fde2019-10-09 09:43:02 -0400107 fEnd.cluster()->run()->placeholder() == nullptr &&
108 fWidth > 0) {
Julia Lavrova916a9042019-08-08 16:51:27 -0400109 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position()));
110 }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400111 }
112
113 void trim(Cluster* cluster) {
114 SkASSERT(fEnd.cluster() == cluster);
115 if (fEnd.cluster() > fStart.cluster()) {
116 fEnd.move(false);
117 fWidth -= cluster->width();
118 } else {
119 fWidth = 0;
120 }
121 }
122
123 void clean() {
124 fStart.clean();
125 fEnd.clean();
126 fWidth = 0;
127 fMetrics.clean();
128 }
129
130 private:
131 ClusterPos fStart;
132 ClusterPos fEnd;
133 ClusterPos fBreak;
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400134 InternalLineMetrics fMetrics;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400135 SkScalar fWidth;
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400136 SkScalar fWidthWithGhostSpaces;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400137 };
138
139public:
140 TextWrapper() { fLineNumber = 1; }
141
Julia Lavrova5207f352019-06-21 12:22:32 -0400142 using AddLineToParagraph = std::function<void(TextRange text,
143 TextRange textWithSpaces,
144 ClusterRange clusters,
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400145 ClusterRange clustersWithGhosts,
146 SkScalar AddLineToParagraph,
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400147 size_t startClip,
148 size_t endClip,
149 SkVector offset,
150 SkVector advance,
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400151 InternalLineMetrics metrics,
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400152 bool addEllipsis)>;
153 void breakTextIntoLines(ParagraphImpl* parent,
154 SkScalar maxWidth,
155 const AddLineToParagraph& addLine);
156
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400157 SkScalar height() const { return fHeight; }
158 SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; }
159 SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; }
160 bool exceededMaxLines() const { return fExceededMaxLines; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400161
162private:
163 TextStretch fWords;
164 TextStretch fClusters;
165 TextStretch fClip;
166 TextStretch fEndLine;
167 size_t fLineNumber;
168 bool fTooLongWord;
169 bool fTooLongCluster;
170
171 bool fHardLineBreak;
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400172 bool fExceededMaxLines;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400173
174 SkScalar fHeight;
175 SkScalar fMinIntrinsicWidth;
176 SkScalar fMaxIntrinsicWidth;
177
178 void reset() {
179 fWords.clean();
180 fClusters.clean();
181 fClip.clean();
182 fTooLongCluster = false;
183 fTooLongWord = false;
184 }
185
186 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters);
187 void moveForward();
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400188 void trimEndSpaces(TextAlign align);
189 std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters);
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400190 SkScalar getClustersTrimmedWidth();
191};
192} // namespace textlayout
193} // namespace skia
194
195#endif // TextWrapper_DEFINED