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