1// Copyright 2019 Google LLC.
2#ifndef Run_DEFINED
3#define Run_DEFINED
4
5#include "include/core/SkFont.h"
6#include "include/core/SkFontMetrics.h"
7#include "include/core/SkPoint.h"
8#include "include/core/SkRect.h"
9#include "include/core/SkScalar.h"
10#include "include/core/SkTypes.h"
11#include "include/private/SkTArray.h"
12#include "modules/skparagraph/include/DartTypes.h"
13#include "modules/skparagraph/include/TextStyle.h"
14#include "modules/skshaper/include/SkShaper.h"
15#include "src/core/SkSpan.h"
16
17#include <math.h>
18#include <algorithm>
19#include <functional>
20#include <limits>
21#include <tuple>
22
23class SkTextBlobBuilder;
24
25namespace skia {
26namespace textlayout {
27
28class Cluster;
29class InternalLineMetrics;
30class ParagraphImpl;
31
32typedef size_t RunIndex;
33const size_t EMPTY_RUN = EMPTY_INDEX;
34
35typedef size_t ClusterIndex;
36typedef SkRange<size_t> ClusterRange;
37const size_t EMPTY_CLUSTER = EMPTY_INDEX;
38const SkRange<size_t> EMPTY_CLUSTERS = EMPTY_RANGE;
39
40typedef size_t GraphemeIndex;
41typedef SkRange<GraphemeIndex> GraphemeRange;
42
43typedef size_t GlyphIndex;
44typedef SkRange<GlyphIndex> GlyphRange;
45
46// LTR: [start: end) where start <= end
47// RTL: [end: start) where start >= end
48class DirText {
49 DirText(bool dir, size_t s, size_t e) : start(s), end(e) { }
50 bool isLeftToRight() const { return start <= end; }
51 size_t start;
52 size_t end;
53};
54
55class Run {
56public:
57 Run(ParagraphImpl* owner,
58 const SkShaper::RunHandler::RunInfo& info,
59 size_t firstChar,
60 SkScalar heightMultiplier,
61 size_t index,
62 SkScalar shiftX);
63 Run(const Run&) = default;
64 Run& operator=(const Run&) = delete;
65 Run(Run&&) = default;
66 Run& operator=(Run&&) = delete;
67 ~Run() = default;
68
69 void setOwner(ParagraphImpl* owner) { fOwner = owner; }
70
71 SkShaper::RunHandler::Buffer newRunBuffer();
72
73 SkScalar posX(size_t index) const { return fPositions[index].fX; }
74 void addX(size_t index, SkScalar shift) { fPositions[index].fX += shift; }
75 SkScalar posY(size_t index) const { return fPositions[index].fY; }
76 size_t size() const { return fGlyphs.size(); }
77 void setWidth(SkScalar width) { fAdvance.fX = width; }
78 void setHeight(SkScalar height) { fAdvance.fY = height; }
79 void shift(SkScalar shiftX, SkScalar shiftY) {
80 fOffset.fX += shiftX;
81 fOffset.fY += shiftY;
82 }
83 SkVector advance() const {
84 return SkVector::Make(fAdvance.fX, fFontMetrics.fDescent - fFontMetrics.fAscent + fFontMetrics.fLeading);
85 }
86 SkVector offset() const { return fOffset; }
87 SkScalar ascent() const { return fFontMetrics.fAscent; }
88 SkScalar descent() const { return fFontMetrics.fDescent; }
89 SkScalar leading() const { return fFontMetrics.fLeading; }
90 SkScalar correctAscent() const { return fCorrectAscent; }
91 SkScalar correctDescent() const { return fCorrectDescent; }
92 SkScalar correctLeading() const { return fCorrectLeading; }
93 const SkFont& font() const { return fFont; }
94 bool leftToRight() const { return fBidiLevel % 2 == 0; }
95 TextDirection getTextDirection() const { return leftToRight() ? TextDirection::kLtr : TextDirection::kRtl; }
96 size_t index() const { return fIndex; }
97 SkScalar heightMultiplier() const { return fHeightMultiplier; }
98 PlaceholderStyle* placeholderStyle() const;
99 bool isPlaceholder() const { return fPlaceholderIndex != std::numeric_limits<size_t>::max(); }
100 size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }
101 size_t globalClusterIndex(size_t pos) const { return fClusterStart + fClusterIndexes[pos]; }
102 SkScalar positionX(size_t pos) const;
103
104 TextRange textRange() const { return fTextRange; }
105 ClusterRange clusterRange() const { return fClusterRange; }
106
107 ParagraphImpl* owner() const { return fOwner; }
108
109 bool isEllipsis() const { return fEllipsis; }
110
111 void calculateMetrics();
112 void updateMetrics(InternalLineMetrics* endlineMetrics);
113
114 void setClusterRange(size_t from, size_t to) { fClusterRange = ClusterRange(from, to); }
115 SkRect clip() const {
116 return SkRect::MakeXYWH(fOffset.fX, fOffset.fY, fAdvance.fX, fAdvance.fY);
117 }
118
119 SkScalar addSpacesAtTheEnd(SkScalar space, Cluster* cluster);
120 SkScalar addSpacesEvenly(SkScalar space, Cluster* cluster);
121 void shift(const Cluster* cluster, SkScalar offset);
122
123 SkScalar calculateHeight(LineMetricStyle ascentStyle, LineMetricStyle descentStyle) const {
124 auto ascent = ascentStyle == LineMetricStyle::Typographic ? this->ascent()
125 : this->correctAscent();
126 auto descent = descentStyle == LineMetricStyle::Typographic ? this->descent()
127 : this->correctDescent();
128 return descent - ascent;
129 }
130 SkScalar calculateWidth(size_t start, size_t end, bool clip) const;
131
132 void copyTo(SkTextBlobBuilder& builder, size_t pos, size_t size) const;
133
134 using ClusterTextVisitor = std::function<void(size_t glyphStart,
135 size_t glyphEnd,
136 size_t charStart,
137 size_t charEnd,
138 SkScalar width,
139 SkScalar height)>;
140 void iterateThroughClustersInTextOrder(const ClusterTextVisitor& visitor);
141
142 using ClusterVisitor = std::function<void(Cluster* cluster)>;
143 void iterateThroughClusters(const ClusterVisitor& visitor);
144
145 std::tuple<bool, ClusterIndex, ClusterIndex> findLimitingClusters(TextRange text) const;
146 SkSpan<const SkGlyphID> glyphs() const {
147 return SkSpan<const SkGlyphID>(fGlyphs.begin(), fGlyphs.size());
148 }
149 SkSpan<const SkPoint> positions() const {
150 return SkSpan<const SkPoint>(fPositions.begin(), fPositions.size());
151 }
152 SkSpan<const uint32_t> clusterIndexes() const {
153 return SkSpan<const uint32_t>(fClusterIndexes.begin(), fClusterIndexes.size());
154 }
155 SkSpan<const SkScalar> shifts() const { return SkSpan<const SkScalar>(fShifts.begin(), fShifts.size()); }
156
157 void commit();
158
159 SkRect getBounds(size_t pos) const { return fBounds[pos]; }
160
161 void resetShifts() {
162 for (auto& r: fShifts) { r = 0; }
163 fSpaced = false;
164 }
165
166 void resetJustificationShifts() {
167 fJustificationShifts.reset();
168 }
169private:
170 friend class ParagraphImpl;
171 friend class TextLine;
172 friend class InternalLineMetrics;
173 friend class ParagraphCache;
174 friend class OneLineShaper;
175
176 ParagraphImpl* fOwner;
177 TextRange fTextRange;
178 ClusterRange fClusterRange;
179
180 SkFont fFont;
181 size_t fPlaceholderIndex;
182 size_t fIndex;
183 SkVector fAdvance;
184 SkVector fOffset;
185 TextIndex fClusterStart;
186 SkShaper::RunHandler::Range fUtf8Range;
187 SkSTArray<128, SkGlyphID, true> fGlyphs;
188 SkSTArray<128, SkPoint, true> fPositions;
189 SkSTArray<128, SkPoint, true> fJustificationShifts; // For justification (current and prev shifts)
190 SkSTArray<128, uint32_t, true> fClusterIndexes;
191 SkSTArray<128, SkRect, true> fBounds;
192
193 SkSTArray<128, SkScalar, true> fShifts; // For formatting (letter/word spacing)
194
195 SkFontMetrics fFontMetrics;
196 const SkScalar fHeightMultiplier;
197 SkScalar fCorrectAscent;
198 SkScalar fCorrectDescent;
199 SkScalar fCorrectLeading;
200
201 bool fSpaced;
202 bool fEllipsis;
203 uint8_t fBidiLevel;
204};
205
206class Cluster {
207public:
208 enum BreakType {
209 None,
210 GraphemeBreak, // calculated for all clusters (UBRK_CHARACTER)
211 SoftLineBreak, // calculated for all clusters (UBRK_LINE & UBRK_CHARACTER)
212 HardLineBreak, // calculated for all clusters (UBRK_LINE)
213 };
214
215 Cluster()
216 : fOwner(nullptr)
217 , fRunIndex(EMPTY_RUN)
218 , fTextRange(EMPTY_TEXT)
219 , fGraphemeRange(EMPTY_RANGE)
220 , fStart(0)
221 , fEnd()
222 , fWidth()
223 , fSpacing(0)
224 , fHeight()
225 , fHalfLetterSpacing(0.0) {}
226
227 Cluster(ParagraphImpl* owner,
228 RunIndex runIndex,
229 size_t start,
230 size_t end,
231 SkSpan<const char> text,
232 SkScalar width,
233 SkScalar height);
234
235 Cluster(TextRange textRange) : fTextRange(textRange), fGraphemeRange(EMPTY_RANGE) { }
236
237 ~Cluster() = default;
238
239 SkScalar sizeToChar(TextIndex ch) const;
240 SkScalar sizeFromChar(TextIndex ch) const;
241
242 size_t roundPos(SkScalar s) const;
243
244 void space(SkScalar shift, SkScalar space) {
245 fSpacing += space;
246 fWidth += shift;
247 }
248
249 bool isWhitespaces() const { return fIsWhiteSpaces; }
250 bool isHardBreak() const;
251 bool isSoftBreak() const;
252 bool isGraphemeBreak() const;
253 bool canBreakLineAfter() const { return isHardBreak() || isSoftBreak(); }
254 size_t startPos() const { return fStart; }
255 size_t endPos() const { return fEnd; }
256 SkScalar width() const { return fWidth; }
257 SkScalar height() const { return fHeight; }
258 size_t size() const { return fEnd - fStart; }
259
260 void setHalfLetterSpacing(SkScalar halfLetterSpacing) { fHalfLetterSpacing = halfLetterSpacing; }
261 SkScalar getHalfLetterSpacing() const { return fHalfLetterSpacing; }
262
263 TextRange textRange() const { return fTextRange; }
264
265 RunIndex runIndex() const { return fRunIndex; }
266 ParagraphImpl* owner() const { return fOwner; }
267
268 Run* run() const;
269 SkFont font() const;
270
271 SkScalar trimmedWidth(size_t pos) const;
272
273 bool contains(TextIndex ch) const { return ch >= fTextRange.start && ch < fTextRange.end; }
274
275 bool belongs(TextRange text) const {
276 return fTextRange.start >= text.start && fTextRange.end <= text.end;
277 }
278
279 bool startsIn(TextRange text) const {
280 return fTextRange.start >= text.start && fTextRange.start < text.end;
281 }
282
283private:
284
285 friend ParagraphImpl;
286
287 ParagraphImpl* fOwner;
288 RunIndex fRunIndex;
289 TextRange fTextRange;
290 GraphemeRange fGraphemeRange;
291
292 size_t fStart;
293 size_t fEnd;
294 SkScalar fWidth;
295 SkScalar fSpacing;
296 SkScalar fHeight;
297 SkScalar fHalfLetterSpacing;
298 bool fIsWhiteSpaces;
299};
300
301class InternalLineMetrics {
302public:
303
304 InternalLineMetrics() {
305 clean();
306 fForceStrut = false;
307 }
308
309 InternalLineMetrics(bool forceStrut) {
310 clean();
311 fForceStrut = forceStrut;
312 }
313
314 InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l) {
315 fAscent = a;
316 fDescent = d;
317 fLeading = l;
318 fForceStrut = false;
319 }
320
321 InternalLineMetrics(const SkFont& font, bool forceStrut) {
322 SkFontMetrics metrics;
323 font.getMetrics(&metrics);
324 fAscent = metrics.fAscent;
325 fDescent = metrics.fDescent;
326 fLeading = metrics.fLeading;
327 fForceStrut = forceStrut;
328 }
329
330 void add(Run* run) {
331
332 if (fForceStrut) {
333 return;
334 }
335
336 fAscent = std::min(fAscent, run->correctAscent());
337 fDescent = std::max(fDescent, run->correctDescent());
338 fLeading = std::max(fLeading, run->correctLeading());
339 }
340
341 void add(InternalLineMetrics other) {
342 fAscent = std::min(fAscent, other.fAscent);
343 fDescent = std::max(fDescent, other.fDescent);
344 fLeading = std::max(fLeading, other.fLeading);
345 }
346 void clean() {
347 fAscent = 0;
348 fDescent = 0;
349 fLeading = 0;
350 }
351
352 SkScalar delta() const { return height() - ideographicBaseline(); }
353
354 void updateLineMetrics(InternalLineMetrics& metrics) {
355 if (metrics.fForceStrut) {
356 metrics.fAscent = fAscent;
357 metrics.fDescent = fDescent;
358 metrics.fLeading = fLeading;
359 } else {
360 // This is another of those flutter changes. To be removed...
361 metrics.fAscent = std::min(metrics.fAscent, fAscent - fLeading / 2.0f);
362 metrics.fDescent = std::max(metrics.fDescent, fDescent + fLeading / 2.0f);
363 }
364 }
365
366 SkScalar runTop(const Run* run, LineMetricStyle ascentStyle) const {
367 return fLeading / 2 - fAscent +
368 (ascentStyle == LineMetricStyle::Typographic ? run->ascent() : run->correctAscent()) + delta();
369 }
370
371 SkScalar height() const {
372 return ::round((double)fDescent - fAscent + fLeading);
373 }
374
375 SkScalar alphabeticBaseline() const { return fLeading / 2 - fAscent; }
376 SkScalar ideographicBaseline() const { return fDescent - fAscent + fLeading; }
377 SkScalar deltaBaselines() const { return fLeading / 2 + fDescent; }
378 SkScalar baseline() const { return fLeading / 2 - fAscent; }
379 SkScalar ascent() const { return fAscent; }
380 SkScalar descent() const { return fDescent; }
381 SkScalar leading() const { return fLeading; }
382 void setForceStrut(bool value) { fForceStrut = value; }
383 bool getForceStrut() const { return fForceStrut; }
384
385private:
386
387 friend class TextWrapper;
388 friend class TextLine;
389
390 SkScalar fAscent;
391 SkScalar fDescent;
392 SkScalar fLeading;
393 bool fForceStrut;
394};
395} // namespace textlayout
396} // namespace skia
397
398#endif // Run_DEFINED
399