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 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 SkScalar addSpacesAtTheEnd(SkScalar space, Cluster* cluster);
124 SkScalar addSpacesEvenly(SkScalar space, Cluster* cluster);
125 void shift(const Cluster* cluster, SkScalar offset);
126
calculateHeight(LineMetricStyle ascentStyle,LineMetricStyle descentStyle)127 SkScalar calculateHeight(LineMetricStyle ascentStyle, LineMetricStyle descentStyle) const {
128 auto ascent = ascentStyle == LineMetricStyle::Typographic ? this->ascent()
129 : this->correctAscent();
130 auto descent = descentStyle == LineMetricStyle::Typographic ? this->descent()
131 : this->correctDescent();
132 return descent - ascent;
133 }
134 SkScalar calculateWidth(size_t start, size_t end, bool clip) const;
135
136 void copyTo(SkTextBlobBuilder& builder, size_t pos, size_t size) const;
137
138 template<typename Visitor>
139 void iterateThroughClustersInTextOrder(Visitor visitor);
140
141 using ClusterVisitor = std::function<void(Cluster* cluster)>;
142 void iterateThroughClusters(const ClusterVisitor& visitor);
143
144 std::tuple<bool, ClusterIndex, ClusterIndex> findLimitingClusters(TextRange text) const;
145 std::tuple<bool, TextIndex, TextIndex> findLimitingGraphemes(TextRange text) const;
glyphs()146 SkSpan<const SkGlyphID> glyphs() const {
147 return SkSpan<const SkGlyphID>(fGlyphs.begin(), fGlyphs.size());
148 }
positions()149 SkSpan<const SkPoint> positions() const {
150 return SkSpan<const SkPoint>(fPositions.begin(), fPositions.size());
151 }
clusterIndexes()152 SkSpan<const uint32_t> clusterIndexes() const {
153 return SkSpan<const uint32_t>(fClusterIndexes.begin(), fClusterIndexes.size());
154 }
shifts()155 SkSpan<const SkScalar> shifts() const { return SkSpan<const SkScalar>(fShifts.begin(), fShifts.size()); }
156
157 void commit();
158
getBounds(size_t pos)159 SkRect getBounds(size_t pos) const { return fBounds[pos]; }
160
resetShifts()161 void resetShifts() {
162 for (auto& r: fShifts) { r = 0; }
163 fSpaced = false;
164 }
165
resetJustificationShifts()166 void resetJustificationShifts() {
167 fJustificationShifts.reset();
168 }
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 SkSTArray<128, SkGlyphID, true> glyphs;
192 SkSTArray<128, SkPoint, true> positions;
193 SkSTArray<128, uint32_t, true> clusterIndexes;
194 SkSTArray<128, SkRect, true> bounds;
195 };
196 std::shared_ptr<GlyphData> fGlyphData;
197 SkSTArray<128, SkGlyphID, true>& fGlyphs;
198 SkSTArray<128, SkPoint, true>& fPositions;
199 SkSTArray<128, uint32_t, true>& fClusterIndexes;
200 SkSTArray<128, SkRect, true>& fBounds;
201
202 SkSTArray<128, SkScalar, true> fShifts; // For formatting (letter/word spacing)
203 SkSTArray<128, SkPoint, true> fJustificationShifts; // For justification (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 fSpaced;
214 bool fEllipsis;
215 uint8_t fBidiLevel;
216 };
217
218 template<typename Visitor>
iterateThroughClustersInTextOrder(Visitor visitor)219 void Run::iterateThroughClustersInTextOrder(Visitor visitor) {
220 // Can't figure out how to do it with one code for both cases without 100 ifs
221 // Can't go through clusters because there are no cluster table yet
222 if (leftToRight()) {
223 size_t start = 0;
224 size_t cluster = this->clusterIndex(start);
225 for (size_t glyph = 1; glyph <= this->size(); ++glyph) {
226 auto nextCluster = this->clusterIndex(glyph);
227 if (nextCluster <= cluster) {
228 continue;
229 }
230
231 visitor(start,
232 glyph,
233 fClusterStart + cluster,
234 fClusterStart + nextCluster,
235 this->calculateWidth(start, glyph, glyph == size()),
236 this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
237
238 start = glyph;
239 cluster = nextCluster;
240 }
241 } else {
242 size_t glyph = this->size();
243 size_t cluster = this->fUtf8Range.begin();
244 for (int32_t start = this->size() - 1; start >= 0; --start) {
245 size_t nextCluster =
246 start == 0 ? this->fUtf8Range.end() : this->clusterIndex(start - 1);
247 if (nextCluster <= cluster) {
248 continue;
249 }
250
251 visitor(start,
252 glyph,
253 fClusterStart + cluster,
254 fClusterStart + nextCluster,
255 this->calculateWidth(start, glyph, glyph == 0),
256 this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
257
258 glyph = start;
259 cluster = nextCluster;
260 }
261 }
262 }
263
264 class Cluster {
265 public:
266 enum BreakType {
267 None,
268 GraphemeBreak, // calculated for all clusters (UBRK_CHARACTER)
269 SoftLineBreak, // calculated for all clusters (UBRK_LINE & UBRK_CHARACTER)
270 HardLineBreak, // calculated for all clusters (UBRK_LINE)
271 };
272
Cluster()273 Cluster()
274 : fOwner(nullptr)
275 , fRunIndex(EMPTY_RUN)
276 , fTextRange(EMPTY_TEXT)
277 , fGraphemeRange(EMPTY_RANGE)
278 , fStart(0)
279 , fEnd()
280 , fWidth()
281 , fSpacing(0)
282 , fHeight()
283 , fHalfLetterSpacing(0.0) {}
284
285 Cluster(ParagraphImpl* owner,
286 RunIndex runIndex,
287 size_t start,
288 size_t end,
289 SkSpan<const char> text,
290 SkScalar width,
291 SkScalar height);
292
Cluster(TextRange textRange)293 Cluster(TextRange textRange) : fTextRange(textRange), fGraphemeRange(EMPTY_RANGE) { }
294
295 Cluster(const Cluster&) = default;
296 ~Cluster() = default;
297
298 SkScalar sizeToChar(TextIndex ch) const;
299 SkScalar sizeFromChar(TextIndex ch) const;
300
301 size_t roundPos(SkScalar s) const;
302
space(SkScalar shift,SkScalar space)303 void space(SkScalar shift, SkScalar space) {
304 fSpacing += space;
305 fWidth += shift;
306 }
307
isWhitespaceBreak()308 bool isWhitespaceBreak() const { return fIsWhiteSpaceBreak; }
isIntraWordBreak()309 bool isIntraWordBreak() const { return fIsIntraWordBreak; }
isHardBreak()310 bool isHardBreak() const { return fIsHardBreak; }
311
312 bool isSoftBreak() const;
313 bool isGraphemeBreak() const;
canBreakLineAfter()314 bool canBreakLineAfter() const { return isHardBreak() || isSoftBreak(); }
startPos()315 size_t startPos() const { return fStart; }
endPos()316 size_t endPos() const { return fEnd; }
width()317 SkScalar width() const { return fWidth; }
height()318 SkScalar height() const { return fHeight; }
size()319 size_t size() const { return fEnd - fStart; }
320
setHalfLetterSpacing(SkScalar halfLetterSpacing)321 void setHalfLetterSpacing(SkScalar halfLetterSpacing) { fHalfLetterSpacing = halfLetterSpacing; }
getHalfLetterSpacing()322 SkScalar getHalfLetterSpacing() const { return fHalfLetterSpacing; }
323
textRange()324 TextRange textRange() const { return fTextRange; }
325
runIndex()326 RunIndex runIndex() const { return fRunIndex; }
owner()327 ParagraphImpl* owner() const { return fOwner; }
328
329 Run* runOrNull() const;
330 Run& run() const;
331 SkFont font() const;
332
333 SkScalar trimmedWidth(size_t pos) const;
334
contains(TextIndex ch)335 bool contains(TextIndex ch) const { return ch >= fTextRange.start && ch < fTextRange.end; }
336
belongs(TextRange text)337 bool belongs(TextRange text) const {
338 return fTextRange.start >= text.start && fTextRange.end <= text.end;
339 }
340
startsIn(TextRange text)341 bool startsIn(TextRange text) const {
342 return fTextRange.start >= text.start && fTextRange.start < text.end;
343 }
344
345 private:
346
347 friend ParagraphImpl;
348
349 ParagraphImpl* fOwner;
350 RunIndex fRunIndex;
351 TextRange fTextRange;
352 GraphemeRange fGraphemeRange;
353
354 size_t fStart;
355 size_t fEnd;
356 SkScalar fWidth;
357 SkScalar fSpacing;
358 SkScalar fHeight;
359 SkScalar fHalfLetterSpacing;
360
361 bool fIsWhiteSpaceBreak;
362 bool fIsIntraWordBreak;
363 bool fIsHardBreak;
364 };
365
366 class InternalLineMetrics {
367 public:
368
InternalLineMetrics()369 InternalLineMetrics() {
370 clean();
371 fForceStrut = false;
372 }
373
InternalLineMetrics(bool forceStrut)374 InternalLineMetrics(bool forceStrut) {
375 clean();
376 fForceStrut = forceStrut;
377 }
378
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l)379 InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l) {
380 fAscent = a;
381 fDescent = d;
382 fLeading = l;
383 fRawAscent = a;
384 fRawDescent = d;
385 fRawLeading = l;
386 fForceStrut = false;
387 }
388
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l,SkScalar ra,SkScalar rd,SkScalar rl)389 InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l, SkScalar ra, SkScalar rd, SkScalar rl) {
390 fAscent = a;
391 fDescent = d;
392 fLeading = l;
393 fRawAscent = ra;
394 fRawDescent = rd;
395 fRawLeading = rl;
396 fForceStrut = false;
397 }
398
InternalLineMetrics(const SkFont & font,bool forceStrut)399 InternalLineMetrics(const SkFont& font, bool forceStrut) {
400 SkFontMetrics metrics;
401 font.getMetrics(&metrics);
402 fAscent = metrics.fAscent;
403 fDescent = metrics.fDescent;
404 fLeading = metrics.fLeading;
405 fRawAscent = metrics.fAscent;
406 fRawDescent = metrics.fDescent;
407 fRawLeading = metrics.fLeading;
408 fForceStrut = forceStrut;
409 }
410
add(Run * run)411 void add(Run* run) {
412 if (fForceStrut) {
413 return;
414 }
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
delta()443 SkScalar delta() const { return height() - ideographicBaseline(); }
444
updateLineMetrics(InternalLineMetrics & metrics)445 void updateLineMetrics(InternalLineMetrics& metrics) {
446 if (metrics.fForceStrut) {
447 metrics.fAscent = fAscent;
448 metrics.fDescent = fDescent;
449 metrics.fLeading = fLeading;
450 metrics.fRawAscent = fRawAscent;
451 metrics.fRawDescent = fRawDescent;
452 metrics.fRawLeading = fRawLeading;
453 } else {
454 // This is another of those flutter changes. To be removed...
455 metrics.fAscent = std::min(metrics.fAscent, fAscent - fLeading / 2.0f);
456 metrics.fDescent = std::max(metrics.fDescent, fDescent + fLeading / 2.0f);
457 metrics.fRawAscent = std::min(metrics.fRawAscent, fRawAscent - fRawLeading / 2.0f);
458 metrics.fRawDescent = std::max(metrics.fRawDescent, fRawDescent + fRawLeading / 2.0f);
459 }
460 }
461
runTop(const Run * run,LineMetricStyle ascentStyle)462 SkScalar runTop(const Run* run, LineMetricStyle ascentStyle) const {
463 return fLeading / 2 - fAscent +
464 (ascentStyle == LineMetricStyle::Typographic ? run->ascent() : run->correctAscent()) + delta();
465 }
466
height()467 SkScalar height() const {
468 return ::round((double)fDescent - fAscent + fLeading);
469 }
470
update(SkScalar a,SkScalar d,SkScalar l)471 void update(SkScalar a, SkScalar d, SkScalar l) {
472 fAscent = a;
473 fDescent = d;
474 fLeading = l;
475 }
476
alphabeticBaseline()477 SkScalar alphabeticBaseline() const { return fLeading / 2 - fAscent; }
ideographicBaseline()478 SkScalar ideographicBaseline() const { return fDescent - fAscent + fLeading; }
deltaBaselines()479 SkScalar deltaBaselines() const { return fLeading / 2 + fDescent; }
baseline()480 SkScalar baseline() const { return fLeading / 2 - fAscent; }
ascent()481 SkScalar ascent() const { return fAscent; }
descent()482 SkScalar descent() const { return fDescent; }
leading()483 SkScalar leading() const { return fLeading; }
rawAscent()484 SkScalar rawAscent() const { return fRawAscent; }
rawDescent()485 SkScalar rawDescent() const { return fRawDescent; }
setForceStrut(bool value)486 void setForceStrut(bool value) { fForceStrut = value; }
getForceStrut()487 bool getForceStrut() const { return fForceStrut; }
488
489 private:
490
491 friend class TextWrapper;
492 friend class TextLine;
493
494 SkScalar fAscent;
495 SkScalar fDescent;
496 SkScalar fLeading;
497
498 SkScalar fRawAscent;
499 SkScalar fRawDescent;
500 SkScalar fRawLeading;
501
502 bool fForceStrut;
503 };
504 } // namespace textlayout
505 } // namespace skia
506
507 #endif // Run_DEFINED
508