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 enum class RoundRectType {
56 NONE,
57 LEFT_ONLY,
58 RIGHT_ONLY,
59 ALL,
60 };
61
62 class Run {
63 public:
64 Run(ParagraphImpl* owner,
65 const SkShaper::RunHandler::RunInfo& info,
66 size_t firstChar,
67 SkScalar heightMultiplier,
68 bool useHalfLeading,
69 SkScalar baselineShift,
70 size_t index,
71 SkScalar shiftX);
72 Run(const Run&) = default;
73 Run& operator=(const Run&) = delete;
74 Run(Run&&) = default;
75 Run& operator=(Run&&) = delete;
76 ~Run() = default;
77
setOwner(ParagraphImpl * owner)78 void setOwner(ParagraphImpl* owner) { fOwner = owner; }
79
80 SkShaper::RunHandler::Buffer newRunBuffer();
81
posX(size_t index)82 SkScalar posX(size_t index) const { return fPositions[index].fX; }
addX(size_t index,SkScalar shift)83 void addX(size_t index, SkScalar shift) { fPositions[index].fX += shift; }
posY(size_t index)84 SkScalar posY(size_t index) const { return fPositions[index].fY; }
size()85 size_t size() const { return fGlyphs.size(); }
setWidth(SkScalar width)86 void setWidth(SkScalar width) { fAdvance.fX = width; }
setHeight(SkScalar height)87 void setHeight(SkScalar height) { fAdvance.fY = height; }
shift(SkScalar shiftX,SkScalar shiftY)88 void shift(SkScalar shiftX, SkScalar shiftY) {
89 fOffset.fX += shiftX;
90 fOffset.fY += shiftY;
91 }
fAdvanceX()92 SkScalar fAdvanceX() const { return fAdvance.fX; }
advance()93 SkVector advance() const {
94 return SkVector::Make(fAdvance.fX, fFontMetrics.fDescent - fFontMetrics.fAscent + fFontMetrics.fLeading);
95 }
offset()96 SkVector offset() const { return fOffset; }
ascent()97 SkScalar ascent() const { return fFontMetrics.fAscent + fBaselineShift; }
descent()98 SkScalar descent() const { return fFontMetrics.fDescent + fBaselineShift; }
leading()99 SkScalar leading() const { return fFontMetrics.fLeading; }
correctAscent()100 SkScalar correctAscent() const { return fCorrectAscent + fBaselineShift; }
correctDescent()101 SkScalar correctDescent() const { return fCorrectDescent + fBaselineShift; }
correctLeading()102 SkScalar correctLeading() const { return fCorrectLeading; }
font()103 const SkFont& font() const { return fFont; }
leftToRight()104 bool leftToRight() const { return fBidiLevel % 2 == 0; }
getTextDirection()105 TextDirection getTextDirection() const { return leftToRight() ? TextDirection::kLtr : TextDirection::kRtl; }
index()106 size_t index() const { return fIndex; }
heightMultiplier()107 SkScalar heightMultiplier() const { return fHeightMultiplier; }
useHalfLeading()108 bool useHalfLeading() const { return fUseHalfLeading; }
baselineShift()109 SkScalar baselineShift() const { return fBaselineShift; }
110 PlaceholderStyle* placeholderStyle() const;
isPlaceholder()111 bool isPlaceholder() const { return fPlaceholderIndex != std::numeric_limits<size_t>::max(); }
clusterIndex(size_t pos)112 size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }
globalClusterIndex(size_t pos)113 size_t globalClusterIndex(size_t pos) const { return fClusterStart + fClusterIndexes[pos]; }
114 SkScalar positionX(size_t pos) const;
115
textRange()116 TextRange textRange() const { return fTextRange; }
clusterRange()117 ClusterRange clusterRange() const { return fClusterRange; }
118
owner()119 ParagraphImpl* owner() const { return fOwner; }
120
isEllipsis()121 bool isEllipsis() const { return fEllipsis; }
122
123 void calculateMetrics();
124 void updateMetrics(InternalLineMetrics* endlineMetrics);
125
setClusterRange(size_t from,size_t to)126 void setClusterRange(size_t from, size_t to) { fClusterRange = ClusterRange(from, to); }
clip()127 SkRect clip() const {
128 return SkRect::MakeXYWH(fOffset.fX, fOffset.fY, fAdvance.fX, fAdvance.fY);
129 }
130
131 void addSpacesAtTheEnd(SkScalar space, Cluster* cluster);
132 SkScalar addSpacesEvenly(SkScalar space, Cluster* cluster);
133 SkScalar addSpacesEvenly(SkScalar space);
134 void shift(const Cluster* cluster, SkScalar offset);
135
calculateHeight(LineMetricStyle ascentStyle,LineMetricStyle descentStyle)136 SkScalar calculateHeight(LineMetricStyle ascentStyle, LineMetricStyle descentStyle) const {
137 auto ascent = ascentStyle == LineMetricStyle::Typographic ? this->ascent()
138 : this->correctAscent();
139 auto descent = descentStyle == LineMetricStyle::Typographic ? this->descent()
140 : this->correctDescent();
141 return descent - ascent;
142 }
143 SkScalar calculateWidth(size_t start, size_t end, bool clip) const;
144
145 void copyTo(SkTextBlobBuilder& builder, size_t pos, size_t size) const;
146
147 template<typename Visitor>
148 void iterateThroughClustersInTextOrder(Visitor visitor);
149
150 using ClusterVisitor = std::function<void(Cluster* cluster)>;
151 void iterateThroughClusters(const ClusterVisitor& visitor);
152
153 std::tuple<bool, ClusterIndex, ClusterIndex> findLimitingClusters(TextRange text) const;
154 std::tuple<bool, TextIndex, TextIndex> findLimitingGlyphClusters(TextRange text) const;
155 std::tuple<bool, TextIndex, TextIndex> findLimitingGraphemes(TextRange text) const;
glyphs()156 SkSpan<const SkGlyphID> glyphs() const {
157 return SkSpan<const SkGlyphID>(fGlyphs.begin(), fGlyphs.size());
158 }
positions()159 SkSpan<const SkPoint> positions() const {
160 return SkSpan<const SkPoint>(fPositions.begin(), fPositions.size());
161 }
offsets()162 SkSpan<const SkPoint> offsets() const {
163 return SkSpan<const SkPoint>(fOffsets.begin(), fOffsets.size());
164 }
clusterIndexes()165 SkSpan<const uint32_t> clusterIndexes() const {
166 return SkSpan<const uint32_t>(fClusterIndexes.begin(), fClusterIndexes.size());
167 }
168
commit()169 void commit() { }
170
resetJustificationShifts()171 void resetJustificationShifts() {
172 fJustificationShifts.reset();
173 }
174
175 bool isResolved() const;
176
getRoundRectType()177 RoundRectType getRoundRectType() const { return fRoundRectType; }
setRoundRectType(RoundRectType type)178 void setRoundRectType(RoundRectType type) { fRoundRectType = type; }
179
getTopInGroup()180 SkScalar getTopInGroup() const { return fTopInGroup; }
setTopInGroup(SkScalar top)181 void setTopInGroup(SkScalar top) { fTopInGroup = top; }
182
getBottomInGroup()183 SkScalar getBottomInGroup() const { return fBottomInGroup; }
setBottomInGroup(SkScalar bottom)184 void setBottomInGroup(SkScalar bottom) { fBottomInGroup = bottom; }
185
getMaxRoundRectRadius()186 SkScalar getMaxRoundRectRadius() const { return fMaxRoundRectRadius; }
setMaxRoundRectRadius(SkScalar radius)187 void setMaxRoundRectRadius(SkScalar radius) { fMaxRoundRectRadius = radius; }
188
getIndexInLine()189 size_t getIndexInLine() const { return indexInLine; }
setIndexInLine(size_t index)190 void setIndexInLine(size_t index) { indexInLine = index; }
191
192 private:
193 friend class ParagraphImpl;
194 friend class TextLine;
195 friend class InternalLineMetrics;
196 friend class ParagraphCache;
197 friend class OneLineShaper;
198
199 ParagraphImpl* fOwner;
200 TextRange fTextRange;
201 ClusterRange fClusterRange;
202
203 SkFont fFont;
204 size_t fPlaceholderIndex;
205 size_t fIndex;
206 SkVector fAdvance;
207 SkVector fOffset;
208 TextIndex fClusterStart;
209 SkShaper::RunHandler::Range fUtf8Range;
210
211 // These fields are not modified after shaping completes and can safely be
212 // shared among copies of the run that are held by different paragraphs.
213 struct GlyphData {
214 SkSTArray<64, SkGlyphID, true> glyphs;
215 SkSTArray<64, SkPoint, true> positions;
216 SkSTArray<64, SkPoint, true> offsets;
217 SkSTArray<64, uint32_t, true> clusterIndexes;
218 };
219 std::shared_ptr<GlyphData> fGlyphData;
220 SkSTArray<64, SkGlyphID, true>& fGlyphs;
221 SkSTArray<64, SkPoint, true>& fPositions;
222 SkSTArray<64, SkPoint, true>& fOffsets;
223 SkSTArray<64, uint32_t, true>& fClusterIndexes;
224
225 SkSTArray<64, SkPoint, true> fJustificationShifts; // For justification
226 // (current and prev shifts)
227
228 SkFontMetrics fFontMetrics;
229 const SkScalar fHeightMultiplier;
230 const bool fUseHalfLeading;
231 const SkScalar fBaselineShift;
232 SkScalar fCorrectAscent;
233 SkScalar fCorrectDescent;
234 SkScalar fCorrectLeading;
235
236 bool fEllipsis;
237 uint8_t fBidiLevel;
238
239 RoundRectType fRoundRectType = RoundRectType::NONE;
240 SkScalar fTopInGroup = 0.0f;
241 SkScalar fBottomInGroup = 0.0f;
242 SkScalar fMaxRoundRectRadius = 0.0f;
243 size_t indexInLine;
244 };
245
246 template<typename Visitor>
iterateThroughClustersInTextOrder(Visitor visitor)247 void Run::iterateThroughClustersInTextOrder(Visitor visitor) {
248 // Can't figure out how to do it with one code for both cases without 100 ifs
249 // Can't go through clusters because there are no cluster table yet
250 if (leftToRight()) {
251 size_t start = 0;
252 size_t cluster = this->clusterIndex(start);
253 for (size_t glyph = 1; glyph <= this->size(); ++glyph) {
254 auto nextCluster = this->clusterIndex(glyph);
255 if (nextCluster <= cluster) {
256 continue;
257 }
258
259 visitor(start,
260 glyph,
261 fClusterStart + cluster,
262 fClusterStart + nextCluster,
263 this->calculateWidth(start, glyph, glyph == size()),
264 this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
265
266 start = glyph;
267 cluster = nextCluster;
268 }
269 } else {
270 size_t glyph = this->size();
271 size_t cluster = this->fUtf8Range.begin();
272 for (int32_t start = this->size() - 1; start >= 0; --start) {
273 size_t nextCluster =
274 start == 0 ? this->fUtf8Range.end() : this->clusterIndex(start - 1);
275 if (nextCluster <= cluster) {
276 continue;
277 }
278
279 visitor(start,
280 glyph,
281 fClusterStart + cluster,
282 fClusterStart + nextCluster,
283 this->calculateWidth(start, glyph, glyph == 0),
284 this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
285
286 glyph = start;
287 cluster = nextCluster;
288 }
289 }
290 }
291
292 class Cluster {
293 public:
294 enum BreakType {
295 None,
296 GraphemeBreak, // calculated for all clusters (UBRK_CHARACTER)
297 SoftLineBreak, // calculated for all clusters (UBRK_LINE & UBRK_CHARACTER)
298 HardLineBreak, // calculated for all clusters (UBRK_LINE)
299 };
300
Cluster()301 Cluster()
302 : fOwner(nullptr)
303 , fRunIndex(EMPTY_RUN)
304 , fTextRange(EMPTY_TEXT)
305 , fGraphemeRange(EMPTY_RANGE)
306 , fStart(0)
307 , fEnd()
308 , fWidth()
309 , fHeight()
310 , fHalfLetterSpacing(0.0) {}
311
312 Cluster(ParagraphImpl* owner,
313 RunIndex runIndex,
314 size_t start,
315 size_t end,
316 SkSpan<const char> text,
317 SkScalar width,
318 SkScalar height);
319
Cluster(TextRange textRange)320 Cluster(TextRange textRange) : fTextRange(textRange), fGraphemeRange(EMPTY_RANGE) { }
321
322 Cluster(const Cluster&) = default;
323 ~Cluster() = default;
324
325 SkScalar sizeToChar(TextIndex ch) const;
326 SkScalar sizeFromChar(TextIndex ch) const;
327
328 size_t roundPos(SkScalar s) const;
329
space(SkScalar shift)330 void space(SkScalar shift) {
331 fWidth += shift;
332 }
333
getOwner()334 ParagraphImpl* getOwner() const { return fOwner; }
setOwner(ParagraphImpl * owner)335 void setOwner(ParagraphImpl* owner) { fOwner = owner; }
336
isWhitespaceBreak()337 bool isWhitespaceBreak() const { return fIsWhiteSpaceBreak; }
isIntraWordBreak()338 bool isIntraWordBreak() const { return fIsIntraWordBreak; }
isHardBreak()339 bool isHardBreak() const { return fIsHardBreak; }
isWordBreak()340 bool isWordBreak() const { return isWhitespaceBreak() || isHardBreak() || isSoftBreak() || run().isPlaceholder(); }
341
342 bool isSoftBreak() const;
343 bool isGraphemeBreak() const;
canBreakLineAfter()344 bool canBreakLineAfter() const { return isHardBreak() || isSoftBreak(); }
startPos()345 size_t startPos() const { return fStart; }
endPos()346 size_t endPos() const { return fEnd; }
width()347 SkScalar width() const { return fWidth; }
height()348 SkScalar height() const { return fHeight; }
size()349 size_t size() const { return fEnd - fStart; }
350
setHalfLetterSpacing(SkScalar halfLetterSpacing)351 void setHalfLetterSpacing(SkScalar halfLetterSpacing) { fHalfLetterSpacing = halfLetterSpacing; }
getHalfLetterSpacing()352 SkScalar getHalfLetterSpacing() const { return fHalfLetterSpacing; }
353
textRange()354 TextRange textRange() const { return fTextRange; }
355
runIndex()356 RunIndex runIndex() const { return fRunIndex; }
owner()357 ParagraphImpl* owner() const { return fOwner; }
358
359 Run* runOrNull() const;
360 Run& run() const;
361 SkFont font() const;
362
363 SkScalar trimmedWidth(size_t pos) const;
364
contains(TextIndex ch)365 bool contains(TextIndex ch) const { return ch >= fTextRange.start && ch < fTextRange.end; }
366
belongs(TextRange text)367 bool belongs(TextRange text) const {
368 return fTextRange.start >= text.start && fTextRange.end <= text.end;
369 }
370
startsIn(TextRange text)371 bool startsIn(TextRange text) const {
372 return fTextRange.start >= text.start && fTextRange.start < text.end;
373 }
374
375 private:
376
377 friend ParagraphImpl;
378
379 ParagraphImpl* fOwner;
380 RunIndex fRunIndex;
381 TextRange fTextRange;
382 GraphemeRange fGraphemeRange;
383
384 size_t fStart;
385 size_t fEnd;
386 SkScalar fWidth;
387 SkScalar fHeight;
388 SkScalar fHalfLetterSpacing;
389
390 bool fIsWhiteSpaceBreak;
391 bool fIsIntraWordBreak;
392 bool fIsHardBreak;
393 };
394
395 class InternalLineMetrics {
396 public:
397
InternalLineMetrics()398 InternalLineMetrics() {
399 clean();
400 fForceStrut = false;
401 }
402
InternalLineMetrics(bool forceStrut)403 InternalLineMetrics(bool forceStrut) {
404 clean();
405 fForceStrut = forceStrut;
406 }
407
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l)408 InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l) {
409 fAscent = a;
410 fDescent = d;
411 fLeading = l;
412 fRawAscent = a;
413 fRawDescent = d;
414 fRawLeading = l;
415 fForceStrut = false;
416 }
417
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l,SkScalar ra,SkScalar rd,SkScalar rl)418 InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l, SkScalar ra, SkScalar rd, SkScalar rl) {
419 fAscent = a;
420 fDescent = d;
421 fLeading = l;
422 fRawAscent = ra;
423 fRawDescent = rd;
424 fRawLeading = rl;
425 fForceStrut = false;
426 }
427
InternalLineMetrics(const SkFont & font,bool forceStrut)428 InternalLineMetrics(const SkFont& font, bool forceStrut) {
429 SkFontMetrics metrics;
430 font.getMetrics(&metrics);
431 fAscent = metrics.fAscent;
432 fDescent = metrics.fDescent;
433 fLeading = metrics.fLeading;
434 fRawAscent = metrics.fAscent;
435 fRawDescent = metrics.fDescent;
436 fRawLeading = metrics.fLeading;
437 fForceStrut = forceStrut;
438 }
439
add(Run * run)440 void add(Run* run) {
441 if (fForceStrut) {
442 return;
443 }
444 fAscent = std::min(fAscent, run->correctAscent());
445 fDescent = std::max(fDescent, run->correctDescent());
446 fLeading = std::max(fLeading, run->correctLeading());
447
448 fRawAscent = std::min(fRawAscent, run->ascent());
449 fRawDescent = std::max(fRawDescent, run->descent());
450 fRawLeading = std::max(fRawLeading, run->leading());
451 }
452
add(InternalLineMetrics other)453 void add(InternalLineMetrics other) {
454 fAscent = std::min(fAscent, other.fAscent);
455 fDescent = std::max(fDescent, other.fDescent);
456 fLeading = std::max(fLeading, other.fLeading);
457 fRawAscent = std::min(fRawAscent, other.fRawAscent);
458 fRawDescent = std::max(fRawDescent, other.fRawDescent);
459 fRawLeading = std::max(fRawLeading, other.fRawLeading);
460 }
461
clean()462 void clean() {
463 fAscent = SK_ScalarMax;
464 fDescent = SK_ScalarMin;
465 fLeading = 0;
466 fRawAscent = SK_ScalarMax;
467 fRawDescent = SK_ScalarMin;
468 fRawLeading = 0;
469 }
470
isClean()471 bool isClean() {
472 return (fAscent == SK_ScalarMax &&
473 fDescent == SK_ScalarMin &&
474 fLeading == 0 &&
475 fRawAscent == SK_ScalarMax &&
476 fRawDescent == SK_ScalarMin &&
477 fRawLeading == 0);
478 }
479
delta()480 SkScalar delta() const { return height() - ideographicBaseline(); }
481
updateLineMetrics(InternalLineMetrics & metrics)482 void updateLineMetrics(InternalLineMetrics& metrics) {
483 if (metrics.fForceStrut) {
484 metrics.fAscent = fAscent;
485 metrics.fDescent = fDescent;
486 metrics.fLeading = fLeading;
487 metrics.fRawAscent = fRawAscent;
488 metrics.fRawDescent = fRawDescent;
489 metrics.fRawLeading = fRawLeading;
490 } else {
491 // This is another of those flutter changes. To be removed...
492 metrics.fAscent = std::min(metrics.fAscent, fAscent - fLeading / 2.0f);
493 metrics.fDescent = std::max(metrics.fDescent, fDescent + fLeading / 2.0f);
494 metrics.fRawAscent = std::min(metrics.fRawAscent, fRawAscent - fRawLeading / 2.0f);
495 metrics.fRawDescent = std::max(metrics.fRawDescent, fRawDescent + fRawLeading / 2.0f);
496 }
497 }
498
runTop(const Run * run,LineMetricStyle ascentStyle)499 SkScalar runTop(const Run* run, LineMetricStyle ascentStyle) const {
500 return fLeading / 2 - fAscent +
501 (ascentStyle == LineMetricStyle::Typographic ? run->ascent() : run->correctAscent()) + delta();
502 }
503
height()504 SkScalar height() const {
505 return ::round((double)fDescent - fAscent + fLeading);
506 }
507
update(SkScalar a,SkScalar d,SkScalar l)508 void update(SkScalar a, SkScalar d, SkScalar l) {
509 fAscent = a;
510 fDescent = d;
511 fLeading = l;
512 }
513
updateRawData(SkScalar ra,SkScalar rd)514 void updateRawData(SkScalar ra, SkScalar rd) {
515 fRawAscent = ra;
516 fRawDescent = rd;
517 }
518
alphabeticBaseline()519 SkScalar alphabeticBaseline() const { return fLeading / 2 - fAscent; }
ideographicBaseline()520 SkScalar ideographicBaseline() const { return fDescent - fAscent + fLeading; }
deltaBaselines()521 SkScalar deltaBaselines() const { return fLeading / 2 + fDescent; }
baseline()522 SkScalar baseline() const { return fLeading / 2 - fAscent; }
ascent()523 SkScalar ascent() const { return fAscent; }
descent()524 SkScalar descent() const { return fDescent; }
leading()525 SkScalar leading() const { return fLeading; }
rawAscent()526 SkScalar rawAscent() const { return fRawAscent; }
rawDescent()527 SkScalar rawDescent() const { return fRawDescent; }
setForceStrut(bool value)528 void setForceStrut(bool value) { fForceStrut = value; }
getForceStrut()529 bool getForceStrut() const { return fForceStrut; }
530
531 private:
532
533 friend class ParagraphImpl;
534 friend class TextWrapper;
535 friend class TextLine;
536
537 SkScalar fAscent;
538 SkScalar fDescent;
539 SkScalar fLeading;
540
541 SkScalar fRawAscent;
542 SkScalar fRawDescent;
543 SkScalar fRawLeading;
544
545 bool fForceStrut;
546 };
547 } // namespace textlayout
548 } // namespace skia
549
550 #endif // Run_DEFINED
551