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