blob: ae95f529bb3e0fce0e33dd6fee503a99266ef083 [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) {}
38 explicit TextStretch(Cluster* s, Cluster* e)
39 : 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) {
68 fEnd = ClusterPos(cluster, cluster->endPos());
69 fMetrics.add(cluster->run());
70 fWidth += cluster->width();
71 }
72
73 void extend(Cluster* cluster, size_t pos) {
74 fEnd = ClusterPos(cluster, pos);
75 if (cluster->run() != nullptr) {
76 fMetrics.add(cluster->run());
77 }
78 }
79
80 void startFrom(Cluster* cluster, size_t pos) {
81 fStart = ClusterPos(cluster, pos);
82 fEnd = ClusterPos(cluster, pos);
83 if (cluster->run() != nullptr) {
84 fMetrics.add(cluster->run());
85 }
86 fWidth = 0;
87 }
88
89 void nextPos() {
90 if (fEnd.position() == fEnd.cluster()->endPos()) {
91 fEnd.move(true);
92 } else {
93 fEnd.setPosition(fEnd.cluster()->endPos());
94 }
95 }
96
97 void saveBreak() { fBreak = fEnd; }
98
99 void restoreBreak() { fEnd = fBreak; }
100
101 void trim() {
102 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position()));
103 }
104
105 void trim(Cluster* cluster) {
106 SkASSERT(fEnd.cluster() == cluster);
107 if (fEnd.cluster() > fStart.cluster()) {
108 fEnd.move(false);
109 fWidth -= cluster->width();
110 } else {
111 fWidth = 0;
112 }
113 }
114
115 void clean() {
116 fStart.clean();
117 fEnd.clean();
118 fWidth = 0;
119 fMetrics.clean();
120 }
121
122 private:
123 ClusterPos fStart;
124 ClusterPos fEnd;
125 ClusterPos fBreak;
126 LineMetrics fMetrics;
127 SkScalar fWidth;
128 };
129
130public:
131 TextWrapper() { fLineNumber = 1; }
132
133 using AddLineToParagraph = std::function<void(SkSpan<const char> text,
134 SkSpan<const char> textWithSpaces,
135 Cluster* start,
136 Cluster* end,
137 size_t startClip,
138 size_t endClip,
139 SkVector offset,
140 SkVector advance,
141 LineMetrics metrics,
142 bool addEllipsis)>;
143 void breakTextIntoLines(ParagraphImpl* parent,
144 SkScalar maxWidth,
145 const AddLineToParagraph& addLine);
146
147 SkScalar height() const { return fHeight; }
148 SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; }
149 SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; }
150
151private:
152 TextStretch fWords;
153 TextStretch fClusters;
154 TextStretch fClip;
155 TextStretch fEndLine;
156 size_t fLineNumber;
157 bool fTooLongWord;
158 bool fTooLongCluster;
159
160 bool fHardLineBreak;
161
162 SkScalar fHeight;
163 SkScalar fMinIntrinsicWidth;
164 SkScalar fMaxIntrinsicWidth;
165
166 void reset() {
167 fWords.clean();
168 fClusters.clean();
169 fClip.clean();
170 fTooLongCluster = false;
171 fTooLongWord = false;
172 }
173
174 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters);
175 void moveForward();
Julia Lavrova6e6333f2019-06-17 10:34:10 -0400176 void trimEndSpaces();
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400177 void trimStartSpaces(Cluster* endOfClusters);
178 SkScalar getClustersTrimmedWidth();
179};
180} // namespace textlayout
181} // namespace skia
182
183#endif // TextWrapper_DEFINED