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 constexpr int PARAM_64 = 64;
28
29 class Cluster;
30 class InternalLineMetrics;
31 class ParagraphImpl;
32
33 typedef size_t RunIndex;
34 const size_t EMPTY_RUN = EMPTY_INDEX;
35
36 typedef size_t ClusterIndex;
37 typedef SkRange<size_t> ClusterRange;
38 const size_t EMPTY_CLUSTER = EMPTY_INDEX;
39 const SkRange<size_t> EMPTY_CLUSTERS = EMPTY_RANGE;
40
41 typedef size_t GraphemeIndex;
42 typedef SkRange<GraphemeIndex> GraphemeRange;
43
44 typedef size_t GlyphIndex;
45 typedef SkRange<GlyphIndex> GlyphRange;
46
47 // LTR: [start: end) where start <= end
48 // RTL: [end: start) where start >= end
49 class DirText {
DirText(bool dir,size_t s,size_t e)50 DirText(bool dir, size_t s, size_t e) : start(s), end(e) { }
isLeftToRight()51 bool isLeftToRight() const { return start <= end; }
52 size_t start;
53 size_t end;
54 };
55
56 enum class RoundRectType {
57 NONE,
58 LEFT_ONLY,
59 RIGHT_ONLY,
60 ALL,
61 };
62
63 // first: words length, second: spacing width ratio
64 constexpr SkScalar AUTO_SPACING_WIDTH_RATIO = 8;
65
66 #ifdef OHOS_SUPPORT
67 enum class ScaleOP {
68 COMPRESS,
69 DECOMPRESS,
70 };
71 #ifdef USE_SKIA_TXT
72 void scaleFontWithCompressionConfig(RSFont& font, ScaleOP op);
73 void metricsIncludeFontPadding(RSFontMetrics* metrics, const RSFont& font);
74 #else
75 void scaleFontWithCompressionConfig(SkFont& font, ScaleOP op);
76 void metricsIncludeFontPadding(SkFontMetrics* metrics, const SkFont& font);
77 #endif
78 #endif
79
80 class Run {
81 public:
82 Run(ParagraphImpl* owner,
83 const SkShaper::RunHandler::RunInfo& info,
84 size_t firstChar,
85 SkScalar heightMultiplier,
86 bool useHalfLeading,
87 SkScalar baselineShift,
88 size_t index,
89 SkScalar shiftX);
90 Run(const Run&) = default;
91 Run& operator=(const Run&) = delete;
92 Run(Run&&) = default;
93 Run& operator=(Run&&) = delete;
94 ~Run() = default;
95
setOwner(ParagraphImpl * owner)96 void setOwner(ParagraphImpl* owner) { fOwner = owner; }
97
98 SkShaper::RunHandler::Buffer newRunBuffer();
99
100 SkScalar posX(size_t index) const;
addX(size_t index,SkScalar shift)101 void addX(size_t index, SkScalar shift) { fPositions[index].fX += shift; }
halfLetterspacing(size_t index)102 SkScalar halfLetterspacing(size_t index) const { return fHalfLetterspacings[index]; }
posY(size_t index)103 SkScalar posY(size_t index) const { return fPositions[index].fY; }
size()104 size_t size() const { return fGlyphs.size(); }
setWidth(SkScalar width)105 void setWidth(SkScalar width) { fAdvance.fX = width; }
setHeight(SkScalar height)106 void setHeight(SkScalar height) { fAdvance.fY = height; }
shift(SkScalar shiftX,SkScalar shiftY)107 void shift(SkScalar shiftX, SkScalar shiftY) {
108 fOffset.fX += shiftX;
109 fOffset.fY += shiftY;
110 }
fAdvanceX()111 SkScalar fAdvanceX() const { return fAdvance.fX; }
advance()112 SkVector advance() const {
113 return SkVector::Make(fAdvance.fX, fFontMetrics.fDescent - fFontMetrics.fAscent + fFontMetrics.fLeading);
114 }
offset()115 SkVector offset() const { return fOffset; }
ascent()116 SkScalar ascent() const { return fFontMetrics.fAscent + fBaselineShift; }
descent()117 SkScalar descent() const { return fFontMetrics.fDescent + fBaselineShift; }
leading()118 SkScalar leading() const { return fFontMetrics.fLeading; }
correctAscent()119 SkScalar correctAscent() const { return fCorrectAscent + fBaselineShift; }
correctDescent()120 SkScalar correctDescent() const { return fCorrectDescent + fBaselineShift; }
correctLeading()121 SkScalar correctLeading() const { return fCorrectLeading; }
122 #ifndef USE_SKIA_TXT
font()123 const SkFont& font() const { return fFont; }
124 #else
font()125 const RSFont& font() const { return fFont; }
126 #endif
leftToRight()127 bool leftToRight() const { return fBidiLevel % 2 == 0; }
getTextDirection()128 TextDirection getTextDirection() const { return leftToRight() ? TextDirection::kLtr : TextDirection::kRtl; }
index()129 size_t index() const { return fIndex; }
heightMultiplier()130 SkScalar heightMultiplier() const { return fHeightMultiplier; }
useHalfLeading()131 bool useHalfLeading() const { return fUseHalfLeading; }
baselineShift()132 SkScalar baselineShift() const { return fBaselineShift; }
133 PlaceholderStyle* placeholderStyle() const;
isPlaceholder()134 bool isPlaceholder() const { return fPlaceholderIndex != std::numeric_limits<size_t>::max(); }
clusterIndex(size_t pos)135 size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }
globalClusterIndex(size_t pos)136 size_t globalClusterIndex(size_t pos) const { return fClusterStart + fClusterIndexes[pos]; }
137 SkScalar positionX(size_t pos) const;
138
textRange()139 TextRange textRange() const { return fTextRange; }
clusterRange()140 ClusterRange clusterRange() const { return fClusterRange; }
141
owner()142 ParagraphImpl* owner() const { return fOwner; }
143
isEllipsis()144 bool isEllipsis() const { return fEllipsis; }
145
146 void calculateMetrics();
147 void updateMetrics(InternalLineMetrics* endlineMetrics);
148
setClusterRange(size_t from,size_t to)149 void setClusterRange(size_t from, size_t to) { fClusterRange = ClusterRange(from, to); }
clip()150 SkRect clip() const {
151 return SkRect::MakeXYWH(fOffset.fX, fOffset.fY, fAdvance.fX, fAdvance.fY);
152 }
153
154 void addSpacesAtTheEnd(SkScalar space, Cluster* cluster);
155 SkScalar addSpacesEvenly(SkScalar space, Cluster* cluster);
156 SkScalar addSpacesEvenly(SkScalar space);
157 void shift(const Cluster* cluster, SkScalar offset);
158
calculateHeight(LineMetricStyle ascentStyle,LineMetricStyle descentStyle)159 SkScalar calculateHeight(LineMetricStyle ascentStyle, LineMetricStyle descentStyle) const {
160 auto ascent = ascentStyle == LineMetricStyle::Typographic ? this->ascent()
161 : this->correctAscent();
162 auto descent = descentStyle == LineMetricStyle::Typographic ? this->descent()
163 : this->correctDescent();
164 return descent - ascent;
165 }
166 SkScalar calculateWidth(size_t start, size_t end, bool clip) const;
167
168 #ifndef USE_SKIA_TXT
169 void copyTo(SkTextBlobBuilder& builder, size_t pos, size_t size) const;
170 #else
171 void copyTo(RSTextBlobBuilder& builder, size_t pos, size_t size) const;
172 void copyTo(RSTextBlobBuilder& builder,
173 const RSPath* path,
174 float hOffset,
175 float vOffset,
176 float fTextShift,
177 size_t pos,
178 size_t size) const;
179 #endif
180
181 template<typename Visitor>
182 void iterateThroughClustersInTextOrder(Visitor visitor);
183
184 #ifdef OHOS_SUPPORT
185 template<typename Visitor>
186 void iterateGlyphRangeInTextOrder(const GlyphRange& glyphRange, Visitor visitor);
187 #endif
188
189 using ClusterVisitor = std::function<void(Cluster* cluster)>;
190 void iterateThroughClusters(const ClusterVisitor& visitor);
191
192 std::tuple<bool, ClusterIndex, ClusterIndex> findLimitingClusters(TextRange text) const;
193 std::tuple<bool, TextIndex, TextIndex> findLimitingGlyphClusters(TextRange text) const;
194 std::tuple<bool, TextIndex, TextIndex> findLimitingGraphemes(TextRange text) const;
glyphs()195 SkSpan<const SkGlyphID> glyphs() const {
196 return SkSpan<const SkGlyphID>(fGlyphs.begin(), fGlyphs.size());
197 }
positions()198 SkSpan<const SkPoint> positions() const {
199 return SkSpan<const SkPoint>(fPositions.begin(), fPositions.size());
200 }
offsets()201 SkSpan<const SkPoint> offsets() const {
202 return SkSpan<const SkPoint>(fOffsets.begin(), fOffsets.size());
203 }
clusterIndexes()204 SkSpan<const uint32_t> clusterIndexes() const {
205 return SkSpan<const uint32_t>(fClusterIndexes.begin(), fClusterIndexes.size());
206 }
207
commit()208 void commit() { }
209
resetJustificationShifts()210 void resetJustificationShifts() {
211 fJustificationShifts.reset();
212 }
213
resetAutoSpacing()214 void resetAutoSpacing() {
215 fAutoSpacings.reset();
216 }
217
218 bool isResolved() const;
219
getRoundRectType()220 RoundRectType getRoundRectType() const { return fRoundRectType; }
setRoundRectType(RoundRectType type)221 void setRoundRectType(RoundRectType type) { fRoundRectType = type; }
222
getTopInGroup()223 SkScalar getTopInGroup() const { return fTopInGroup; }
setTopInGroup(SkScalar top)224 void setTopInGroup(SkScalar top) { fTopInGroup = top; }
225
getBottomInGroup()226 SkScalar getBottomInGroup() const { return fBottomInGroup; }
setBottomInGroup(SkScalar bottom)227 void setBottomInGroup(SkScalar bottom) { fBottomInGroup = bottom; }
228
getMaxRoundRectRadius()229 SkScalar getMaxRoundRectRadius() const { return fMaxRoundRectRadius; }
setMaxRoundRectRadius(SkScalar radius)230 void setMaxRoundRectRadius(SkScalar radius) { fMaxRoundRectRadius = radius; }
231
getIndexInLine()232 size_t getIndexInLine() const { return indexInLine; }
setIndexInLine(size_t index)233 void setIndexInLine(size_t index) { indexInLine = index; }
234
235 private:
236 friend class ParagraphImpl;
237 friend class TextLine;
238 friend class InternalLineMetrics;
239 friend class ParagraphCache;
240 friend class OneLineShaper;
241
242 ParagraphImpl* fOwner;
243 TextRange fTextRange;
244 ClusterRange fClusterRange;
245
246 #ifndef USE_SKIA_TXT
247 SkFont fFont;
248 #else
249 RSFont fFont;
250 #endif
251 size_t fPlaceholderIndex;
252 size_t fIndex;
253 SkVector fAdvance;
254 SkVector fOffset;
255 TextIndex fClusterStart;
256 SkShaper::RunHandler::Range fUtf8Range;
257
258 // These fields are not modified after shaping completes and can safely be
259 // shared among copies of the run that are held by different paragraphs.
260 struct GlyphData {
261 SkSTArray<64, SkGlyphID, true> glyphs;
262 SkSTArray<64, SkPoint, true> positions;
263 SkSTArray<64, SkPoint, true> offsets;
264 SkSTArray<64, uint32_t, true> clusterIndexes;
265 };
266 std::shared_ptr<GlyphData> fGlyphData;
267 SkSTArray<64, SkGlyphID, true>& fGlyphs;
268 SkSTArray<64, SkPoint, true>& fPositions;
269 SkSTArray<64, SkPoint, true>& fOffsets;
270 SkSTArray<64, uint32_t, true>& fClusterIndexes;
271
272 SkSTArray<64, SkPoint, true> fJustificationShifts; // For justification
273 // (current and prev shifts)
274 SkSTArray<PARAM_64, SkPoint, true> fAutoSpacings; // For auto spacing
275 // (current and prev spacings)
276 SkSTArray<PARAM_64, SkScalar, true> fHalfLetterspacings; // For letterspacing
277
278 #ifndef USE_SKIA_TXT
279 SkFontMetrics fFontMetrics;
280 #else
281 RSFontMetrics fFontMetrics;
282 #endif
283 const SkScalar fHeightMultiplier;
284 const bool fUseHalfLeading;
285 const SkScalar fBaselineShift;
286 SkScalar fCorrectAscent;
287 SkScalar fCorrectDescent;
288 SkScalar fCorrectLeading;
289
290 bool fEllipsis;
291 uint8_t fBidiLevel;
292
293 RoundRectType fRoundRectType = RoundRectType::NONE;
294 SkScalar fTopInGroup = 0.0f;
295 SkScalar fBottomInGroup = 0.0f;
296 SkScalar fMaxRoundRectRadius = 0.0f;
297 size_t indexInLine;
298 #ifdef OHOS_SUPPORT
299 SkScalar fCompressionBaselineShift{ 0.0f };
300 #endif
301 };
302
303 template<typename Visitor>
iterateThroughClustersInTextOrder(Visitor visitor)304 void Run::iterateThroughClustersInTextOrder(Visitor visitor) {
305 // Can't figure out how to do it with one code for both cases without 100 ifs
306 // Can't go through clusters because there are no cluster table yet
307 if (leftToRight()) {
308 size_t start = 0;
309 size_t cluster = this->clusterIndex(start);
310 for (size_t glyph = 1; glyph <= this->size(); ++glyph) {
311 auto nextCluster = this->clusterIndex(glyph);
312 if (nextCluster <= cluster) {
313 continue;
314 }
315
316 visitor(start,
317 glyph,
318 fClusterStart + cluster,
319 fClusterStart + nextCluster,
320 this->calculateWidth(start, glyph, glyph == size()),
321 this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
322
323 start = glyph;
324 cluster = nextCluster;
325 }
326 } else {
327 size_t glyph = this->size();
328 size_t cluster = this->fUtf8Range.begin();
329 for (int32_t start = this->size() - 1; start >= 0; --start) {
330 size_t nextCluster =
331 start == 0 ? this->fUtf8Range.end() : this->clusterIndex(start - 1);
332 if (nextCluster <= cluster) {
333 continue;
334 }
335
336 visitor(start,
337 glyph,
338 fClusterStart + cluster,
339 fClusterStart + nextCluster,
340 this->calculateWidth(start, glyph, glyph == 0),
341 this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
342
343 glyph = start;
344 cluster = nextCluster;
345 }
346 }
347 }
348
349 #ifdef OHOS_SUPPORT
350 template<typename Visitor>
iterateGlyphRangeInTextOrder(const GlyphRange & glyphRange,Visitor visitor)351 void Run::iterateGlyphRangeInTextOrder(const GlyphRange& glyphRange, Visitor visitor) {
352 if (glyphRange.start >= glyphRange.end || glyphRange.end > size()) {
353 return;
354 }
355 if (leftToRight()) {
356 size_t start = glyphRange.start;
357 size_t cluster = this->clusterIndex(start);
358 for (size_t glyph = glyphRange.start + 1; glyph <= glyphRange.end; ++glyph) {
359 auto nextCluster = this->clusterIndex(glyph);
360 if (nextCluster <= cluster) {
361 continue;
362 }
363
364 visitor(start, glyph, fClusterStart + cluster, fClusterStart + nextCluster);
365 start = glyph;
366 cluster = nextCluster;
367 }
368 } else {
369 size_t glyph = glyphRange.end;
370 size_t cluster = this->clusterIndex(glyphRange.end - 1);
371 int32_t glyphStart = std::max((int32_t)glyphRange.start, 0);
372 for (int32_t start = glyphRange.end - 1; start >= glyphStart; --start) {
373 size_t nextCluster = start == 0 ? this->fUtf8Range.end() : this->clusterIndex(start - 1);
374 if (nextCluster <= cluster) {
375 continue;
376 }
377
378 visitor(start, glyph, fClusterStart + cluster, fClusterStart + nextCluster);
379 glyph = start;
380 cluster = nextCluster;
381 }
382 }
383 }
384 #endif
385
386 class Cluster {
387 public:
388 enum BreakType {
389 None,
390 GraphemeBreak, // calculated for all clusters (UBRK_CHARACTER)
391 SoftLineBreak, // calculated for all clusters (UBRK_LINE & UBRK_CHARACTER)
392 HardLineBreak, // calculated for all clusters (UBRK_LINE)
393 };
394
Cluster()395 Cluster()
396 : fOwner(nullptr)
397 , fRunIndex(EMPTY_RUN)
398 , fTextRange(EMPTY_TEXT)
399 , fGraphemeRange(EMPTY_RANGE)
400 , fStart(0)
401 , fEnd()
402 , fWidth()
403 , fHeight()
404 , fHalfLetterSpacing(0.0) {}
405
406 Cluster(ParagraphImpl* owner,
407 RunIndex runIndex,
408 size_t start,
409 size_t end,
410 SkSpan<const char> text,
411 SkScalar width,
412 SkScalar height);
413
Cluster(TextRange textRange)414 Cluster(TextRange textRange) : fTextRange(textRange), fGraphemeRange(EMPTY_RANGE) { }
415
416 Cluster(const Cluster&) = default;
417 ~Cluster() = default;
418
419 SkScalar sizeToChar(TextIndex ch) const;
420 SkScalar sizeFromChar(TextIndex ch) const;
421
422 size_t roundPos(SkScalar s) const;
423
space(SkScalar shift)424 void space(SkScalar shift) {
425 fWidth += shift;
426 }
427
getOwner()428 ParagraphImpl* getOwner() const { return fOwner; }
setOwner(ParagraphImpl * owner)429 void setOwner(ParagraphImpl* owner) { fOwner = owner; }
430
isWhitespaceBreak()431 bool isWhitespaceBreak() const { return fIsWhiteSpaceBreak; }
isIntraWordBreak()432 bool isIntraWordBreak() const { return fIsIntraWordBreak; }
isHardBreak()433 bool isHardBreak() const { return fIsHardBreak; }
isIdeographic()434 bool isIdeographic() const { return fIsIdeographic; }
isWordBreak()435 bool isWordBreak() const { return isWhitespaceBreak() || isHardBreak() || isSoftBreak() || run().isPlaceholder(); }
isCJK()436 bool isCJK() const { return fIsCJK; }
isCopyright()437 bool isCopyright() const { return fIsCopyright; }
isWestern()438 bool isWestern() const { return fIsWestern; }
439
440 bool isSoftBreak() const;
441 bool isGraphemeBreak() const;
canBreakLineAfter()442 bool canBreakLineAfter() const { return isHardBreak() || isSoftBreak(); }
startPos()443 size_t startPos() const { return fStart; }
endPos()444 size_t endPos() const { return fEnd; }
width()445 SkScalar width() const { return fWidth; }
height()446 SkScalar height() const { return fHeight; }
size()447 size_t size() const { return fEnd - fStart; }
448
setHalfLetterSpacing(SkScalar halfLetterSpacing)449 void setHalfLetterSpacing(SkScalar halfLetterSpacing) { fHalfLetterSpacing = halfLetterSpacing; }
getHalfLetterSpacing()450 SkScalar getHalfLetterSpacing() const { return fHalfLetterSpacing; }
451
textRange()452 TextRange textRange() const { return fTextRange; }
453
runIndex()454 RunIndex runIndex() const { return fRunIndex; }
owner()455 ParagraphImpl* owner() const { return fOwner; }
456
457 Run* runOrNull() const;
458 Run& run() const;
459 #ifndef USE_SKIA_TXT
460 SkFont font() const;
461 #else
462 RSFont font() const;
463 #endif
464
465 SkScalar trimmedWidth(size_t pos) const;
466
contains(TextIndex ch)467 bool contains(TextIndex ch) const { return ch >= fTextRange.start && ch < fTextRange.end; }
468
belongs(TextRange text)469 bool belongs(TextRange text) const {
470 return fTextRange.start >= text.start && fTextRange.end <= text.end;
471 }
472
startsIn(TextRange text)473 bool startsIn(TextRange text) const {
474 return fTextRange.start >= text.start && fTextRange.start < text.end;
475 }
476
getFontSize()477 SkScalar getFontSize() const {
478 return font().GetSize();
479 }
480
481 private:
482
483 friend ParagraphImpl;
484
485 ParagraphImpl* fOwner;
486 RunIndex fRunIndex;
487 TextRange fTextRange;
488 GraphemeRange fGraphemeRange;
489
490 size_t fStart;
491 size_t fEnd;
492 SkScalar fWidth;
493 SkScalar fHeight;
494 SkScalar fHalfLetterSpacing;
495
496 bool fIsWhiteSpaceBreak;
497 bool fIsIntraWordBreak;
498 bool fIsHardBreak;
499 bool fIsIdeographic;
500 bool fIsCJK;
501 bool fIsCopyright;
502 bool fIsWestern;
503 };
504
505 class InternalLineMetrics {
506 public:
507
InternalLineMetrics()508 InternalLineMetrics() {
509 clean();
510 fForceStrut = false;
511 }
512
InternalLineMetrics(bool forceStrut)513 InternalLineMetrics(bool forceStrut) {
514 clean();
515 fForceStrut = forceStrut;
516 }
517
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l)518 InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l) {
519 fAscent = a;
520 fDescent = d;
521 fLeading = l;
522 fRawAscent = a;
523 fRawDescent = d;
524 fRawLeading = l;
525 fForceStrut = false;
526 }
527
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l,SkScalar ra,SkScalar rd,SkScalar rl)528 InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l, SkScalar ra, SkScalar rd, SkScalar rl) {
529 fAscent = a;
530 fDescent = d;
531 fLeading = l;
532 fRawAscent = ra;
533 fRawDescent = rd;
534 fRawLeading = rl;
535 fForceStrut = false;
536 }
537
538 #ifdef OHOS_SUPPORT
539 #ifdef USE_SKIA_TXT
InternalLineMetrics(const RSFont & font,bool forceStrut)540 InternalLineMetrics(const RSFont& font, bool forceStrut) {
541 RSFontMetrics metrics;
542 auto compressFont = font;
543 scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
544 compressFont.GetMetrics(&metrics);
545 #else
546 InternalLineMetrics(const SkFont& font, bool forceStrut) {
547 SkFontMetrics metrics;
548 auto compressFont = font;
549 scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
550 compressFont.getMetrics(&metrics);
551 #endif
552 metricsIncludeFontPadding(&metrics, font);
553 #else
554 InternalLineMetrics(const SkFont& font, bool forceStrut) {
555 SkFontMetrics metrics;
556 font.getMetrics(&metrics);
557 #endif
558 fAscent = metrics.fAscent;
559 fDescent = metrics.fDescent;
560 fLeading = metrics.fLeading;
561 fRawAscent = metrics.fAscent;
562 fRawDescent = metrics.fDescent;
563 fRawLeading = metrics.fLeading;
564 fForceStrut = forceStrut;
565 }
566
567 void add(Run* run) {
568 if (fForceStrut) {
569 return;
570 }
571 fAscent = std::min(fAscent, run->correctAscent());
572 fDescent = std::max(fDescent, run->correctDescent());
573 fLeading = std::max(fLeading, run->correctLeading());
574
575 fRawAscent = std::min(fRawAscent, run->ascent());
576 fRawDescent = std::max(fRawDescent, run->descent());
577 fRawLeading = std::max(fRawLeading, run->leading());
578 }
579
580 void add(InternalLineMetrics other) {
581 fAscent = std::min(fAscent, other.fAscent);
582 fDescent = std::max(fDescent, other.fDescent);
583 fLeading = std::max(fLeading, other.fLeading);
584 fRawAscent = std::min(fRawAscent, other.fRawAscent);
585 fRawDescent = std::max(fRawDescent, other.fRawDescent);
586 fRawLeading = std::max(fRawLeading, other.fRawLeading);
587 }
588
589 void clean() {
590 fAscent = SK_ScalarMax;
591 fDescent = SK_ScalarMin;
592 fLeading = 0;
593 fRawAscent = SK_ScalarMax;
594 fRawDescent = SK_ScalarMin;
595 fRawLeading = 0;
596 }
597
598 bool isClean() {
599 return (fAscent == SK_ScalarMax &&
600 fDescent == SK_ScalarMin &&
601 fLeading == 0 &&
602 fRawAscent == SK_ScalarMax &&
603 fRawDescent == SK_ScalarMin &&
604 fRawLeading == 0);
605 }
606
607 SkScalar delta() const { return height() - ideographicBaseline(); }
608
609 void updateLineMetrics(InternalLineMetrics& metrics) {
610 if (metrics.fForceStrut) {
611 metrics.fAscent = fAscent;
612 metrics.fDescent = fDescent;
613 metrics.fLeading = fLeading;
614 metrics.fRawAscent = fRawAscent;
615 metrics.fRawDescent = fRawDescent;
616 metrics.fRawLeading = fRawLeading;
617 } else {
618 // This is another of those flutter changes. To be removed...
619 metrics.fAscent = std::min(metrics.fAscent, fAscent - fLeading / 2.0f);
620 metrics.fDescent = std::max(metrics.fDescent, fDescent + fLeading / 2.0f);
621 metrics.fRawAscent = std::min(metrics.fRawAscent, fRawAscent - fRawLeading / 2.0f);
622 metrics.fRawDescent = std::max(metrics.fRawDescent, fRawDescent + fRawLeading / 2.0f);
623 }
624 }
625
626 SkScalar runTop(const Run* run, LineMetricStyle ascentStyle) const {
627 return fLeading / 2 - fAscent +
628 (ascentStyle == LineMetricStyle::Typographic ? run->ascent() : run->correctAscent()) + delta();
629 }
630
631 SkScalar height() const {
632 return ::round((double)fDescent - fAscent + fLeading);
633 }
634
635 void update(SkScalar a, SkScalar d, SkScalar l) {
636 fAscent = a;
637 fDescent = d;
638 fLeading = l;
639 }
640
641 void updateRawData(SkScalar ra, SkScalar rd) {
642 fRawAscent = ra;
643 fRawDescent = rd;
644 }
645
646 SkScalar alphabeticBaseline() const { return fLeading / 2 - fAscent; }
647 SkScalar ideographicBaseline() const { return fDescent - fAscent + fLeading; }
648 SkScalar deltaBaselines() const { return fLeading / 2 + fDescent; }
649 SkScalar baseline() const { return fLeading / 2 - fAscent; }
650 SkScalar ascent() const { return fAscent; }
651 SkScalar descent() const { return fDescent; }
652 SkScalar leading() const { return fLeading; }
653 SkScalar rawAscent() const { return fRawAscent; }
654 SkScalar rawDescent() const { return fRawDescent; }
655 void setForceStrut(bool value) { fForceStrut = value; }
656 bool getForceStrut() const { return fForceStrut; }
657
658 private:
659
660 friend class ParagraphImpl;
661 friend class TextWrapper;
662 friend class TextLine;
663
664 SkScalar fAscent;
665 SkScalar fDescent;
666 SkScalar fLeading;
667
668 SkScalar fRawAscent;
669 SkScalar fRawDescent;
670 SkScalar fRawLeading;
671
672 bool fForceStrut;
673 };
674 } // namespace textlayout
675 } // namespace skia
676
677 #endif // Run_DEFINED
678