• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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