blob: 206cbe3626e39388497f98ba2d52c382fd54d490 [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) {}
19 Cluster* cluster() const { return fCluster; }
20 size_t position() const { return fPos; }
21 void move(bool up) {
22 fCluster += up ? 1 : -1;
23 fPos = up ? 0 : fCluster->endPos();
24 }
25 void setPosition(size_t pos) { fPos = pos; }
26 void clean() {
27 fCluster = nullptr;
28 fPos = 0;
29 }
30
31 private:
32 Cluster* fCluster;
33 size_t fPos;
34 };
35 class TextStretch {
36 public:
37 TextStretch() : fStart(), fEnd(), fWidth(0) {}
Julia Lavrova9af5cc42019-06-19 13:32:01 -040038 TextStretch(Cluster* s, Cluster* e)
Julia Lavrovaa3552c52019-05-30 16:12:56 -040039 : fStart(s, 0), fEnd(e, e->endPos()), fMetrics(), fWidth(0) {
40 for (auto c = s; c <= e; ++c) {
41 if (c->run() != nullptr) {
42 fMetrics.add(c->run());
43 }
44 }
45 }
46
47 SkScalar width() const { return fWidth; }
48 Cluster* startCluster() const { return fStart.cluster(); }
49 Cluster* endCluster() const { return fEnd.cluster(); }
50 Cluster* breakCluster() const { return fBreak.cluster(); }
51 LineMetrics& metrics() { return fMetrics; }
52 size_t startPos() const { return fStart.position(); }
53 size_t endPos() const { return fEnd.position(); }
54 bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); }
55 bool endOfWord() {
56 return endOfCluster() &&
57 (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak());
58 }
59
60 void extend(TextStretch& stretch) {
61 fMetrics.add(stretch.fMetrics);
62 fEnd = stretch.fEnd;
63 fWidth += stretch.fWidth;
64 stretch.clean();
65 }
66
67 void extend(Cluster* cluster) {
Julia Lavrova9af5cc42019-06-19 13:32:01 -040068 if (fStart.cluster() == nullptr) {
69 fStart = ClusterPos(cluster, cluster->startPos());
70 }
Julia Lavrovaa3552c52019-05-30 16:12:56 -040071 fEnd = ClusterPos(cluster, cluster->endPos());
72 fMetrics.add(cluster->run());
73 fWidth += cluster->width();
74 }
75
76 void extend(Cluster* cluster, size_t pos) {
77 fEnd = ClusterPos(cluster, pos);
78 if (cluster->run() != nullptr) {
79 fMetrics.add(cluster->run());
80 }
81 }
82
83 void startFrom(Cluster* cluster, size_t pos) {
84 fStart = ClusterPos(cluster, pos);
85 fEnd = ClusterPos(cluster, pos);
86 if (cluster->run() != nullptr) {
87 fMetrics.add(cluster->run());
88 }
89 fWidth = 0;
90 }
91
92 void nextPos() {
93 if (fEnd.position() == fEnd.cluster()->endPos()) {
94 fEnd.move(true);
95 } else {
96 fEnd.setPosition(fEnd.cluster()->endPos());
97 }
98 }
99
100 void saveBreak() { fBreak = fEnd; }
101
102 void restoreBreak() { fEnd = fBreak; }
103
104 void trim() {
105 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position()));
106 }
107
108 void trim(Cluster* cluster) {
109 SkASSERT(fEnd.cluster() == cluster);
110 if (fEnd.cluster() > fStart.cluster()) {
111 fEnd.move(false);
112 fWidth -= cluster->width();
113 } else {
114 fWidth = 0;
115 }
116 }
117
118 void clean() {
119 fStart.clean();
120 fEnd.clean();
121 fWidth = 0;
122 fMetrics.clean();
123 }
124
125 private:
126 ClusterPos fStart;
127 ClusterPos fEnd;
128 ClusterPos fBreak;
129 LineMetrics fMetrics;
130 SkScalar fWidth;
131 };
132
133public:
134 TextWrapper() { fLineNumber = 1; }
135
136 using AddLineToParagraph = std::function<void(SkSpan<const char> text,
137 SkSpan<const char> textWithSpaces,
138 Cluster* start,
139 Cluster* end,
140 size_t startClip,
141 size_t endClip,
142 SkVector offset,
143 SkVector advance,
144 LineMetrics metrics,
145 bool addEllipsis)>;
146 void breakTextIntoLines(ParagraphImpl* parent,
147 SkScalar maxWidth,
148 const AddLineToParagraph& addLine);
149
150 SkScalar height() const { return fHeight; }
151 SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; }
152 SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; }
153
154private:
155 TextStretch fWords;
156 TextStretch fClusters;
157 TextStretch fClip;
158 TextStretch fEndLine;
159 size_t fLineNumber;
160 bool fTooLongWord;
161 bool fTooLongCluster;
162
163 bool fHardLineBreak;
164
165 SkScalar fHeight;
166 SkScalar fMinIntrinsicWidth;
167 SkScalar fMaxIntrinsicWidth;
168
169 void reset() {
170 fWords.clean();
171 fClusters.clean();
172 fClip.clean();
173 fTooLongCluster = false;
174 fTooLongWord = false;
175 }
176
177 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters);
178 void moveForward();
Julia Lavrova6e6333f2019-06-17 10:34:10 -0400179 void trimEndSpaces();
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400180 void trimStartSpaces(Cluster* endOfClusters);
181 SkScalar getClustersTrimmedWidth();
182};
183} // namespace textlayout
184} // namespace skia
185
186#endif // TextWrapper_DEFINED