• 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     }
getAutoSpacings()153     const SkSTArray<PARAM_64, SkPoint, true>& getAutoSpacings() const {
154         return fAutoSpacings;
155     }
156     void addSpacesAtTheEnd(SkScalar space, Cluster* cluster);
157     SkScalar addSpacesEvenly(SkScalar space, Cluster* cluster);
158     SkScalar addSpacesEvenly(SkScalar space);
159     void shift(const Cluster* cluster, SkScalar offset);
160 
161 #ifdef OHOS_SUPPORT
162     void extendClusterWidth(Cluster* cluster, SkScalar space);
163 #endif
calculateHeight(LineMetricStyle ascentStyle,LineMetricStyle descentStyle)164     SkScalar calculateHeight(LineMetricStyle ascentStyle, LineMetricStyle descentStyle) const {
165         auto ascent = ascentStyle == LineMetricStyle::Typographic ? this->ascent()
166                                     : this->correctAscent();
167         auto descent = descentStyle == LineMetricStyle::Typographic ? this->descent()
168                                       : this->correctDescent();
169         return descent - ascent;
170     }
171     SkScalar calculateWidth(size_t start, size_t end, bool clip) const;
172 
173 #ifndef USE_SKIA_TXT
174     void copyTo(SkTextBlobBuilder& builder, size_t pos, size_t size) const;
175 #else
176     void copyTo(RSTextBlobBuilder& builder, size_t pos, size_t size) const;
177     void copyTo(RSTextBlobBuilder& builder,
178                 const RSPath* path,
179                 float hOffset,
180                 float vOffset,
181                 float fTextShift,
182                 size_t pos,
183                 size_t size) const;
184 #endif
185 
186     template<typename Visitor>
187     void iterateThroughClustersInTextOrder(Visitor visitor);
188 
189 #ifdef OHOS_SUPPORT
190     template<typename Visitor>
191     void iterateGlyphRangeInTextOrder(const GlyphRange& glyphRange, Visitor visitor);
192 #endif
193 
194     using ClusterVisitor = std::function<void(Cluster* cluster)>;
195     void iterateThroughClusters(const ClusterVisitor& visitor);
196 
197     std::tuple<bool, ClusterIndex, ClusterIndex> findLimitingClusters(TextRange text) const;
198     std::tuple<bool, TextIndex, TextIndex> findLimitingGlyphClusters(TextRange text) const;
199     std::tuple<bool, TextIndex, TextIndex> findLimitingGraphemes(TextRange text) const;
glyphs()200     SkSpan<const SkGlyphID> glyphs() const {
201         return SkSpan<const SkGlyphID>(fGlyphs.begin(), fGlyphs.size());
202     }
positions()203     SkSpan<const SkPoint> positions() const {
204         return SkSpan<const SkPoint>(fPositions.begin(), fPositions.size());
205     }
offsets()206     SkSpan<const SkPoint> offsets() const {
207         return SkSpan<const SkPoint>(fOffsets.begin(), fOffsets.size());
208     }
clusterIndexes()209     SkSpan<const uint32_t> clusterIndexes() const {
210         return SkSpan<const uint32_t>(fClusterIndexes.begin(), fClusterIndexes.size());
211     }
212 
commit()213     void commit() { }
214 
resetJustificationShifts()215     void resetJustificationShifts() {
216         fJustificationShifts.reset();
217     }
218 
resetAutoSpacing()219     void resetAutoSpacing() {
220         fAutoSpacings.reset();
221     }
222 
223     bool isResolved() const;
224 
getRoundRectType()225     RoundRectType getRoundRectType() const { return fRoundRectType; }
setRoundRectType(RoundRectType type)226     void setRoundRectType(RoundRectType type) { fRoundRectType = type; }
227 
getTopInGroup()228     SkScalar getTopInGroup() const { return fTopInGroup; }
setTopInGroup(SkScalar top)229     void setTopInGroup(SkScalar top) { fTopInGroup = top; }
230 
getBottomInGroup()231     SkScalar getBottomInGroup() const { return fBottomInGroup; }
setBottomInGroup(SkScalar bottom)232     void setBottomInGroup(SkScalar bottom) { fBottomInGroup = bottom; }
233 
getMaxRoundRectRadius()234     SkScalar getMaxRoundRectRadius() const { return fMaxRoundRectRadius; }
setMaxRoundRectRadius(SkScalar radius)235     void setMaxRoundRectRadius(SkScalar radius) { fMaxRoundRectRadius = radius; }
236 
getIndexInLine()237     size_t getIndexInLine() const { return indexInLine; }
setIndexInLine(size_t index)238     void setIndexInLine(size_t index) { indexInLine = index; }
239 
240 private:
241     friend class ParagraphImpl;
242     friend class TextLine;
243     friend class InternalLineMetrics;
244     friend class ParagraphCache;
245     friend class OneLineShaper;
246 
247     ParagraphImpl* fOwner;
248     TextRange fTextRange;
249     ClusterRange fClusterRange;
250 
251 #ifndef USE_SKIA_TXT
252     SkFont fFont;
253 #else
254     RSFont fFont;
255 #endif
256     size_t fPlaceholderIndex;
257     size_t fIndex;
258     SkVector fAdvance;
259     SkVector fOffset;
260     TextIndex fClusterStart;
261     SkShaper::RunHandler::Range fUtf8Range;
262 
263     // These fields are not modified after shaping completes and can safely be
264     // shared among copies of the run that are held by different paragraphs.
265     struct GlyphData {
266         SkSTArray<64, SkGlyphID, true> glyphs;
267         SkSTArray<64, SkPoint, true> positions;
268         SkSTArray<64, SkPoint, true> offsets;
269         SkSTArray<64, uint32_t, true> clusterIndexes;
270     };
271     std::shared_ptr<GlyphData> fGlyphData;
272     SkSTArray<64, SkGlyphID, true>& fGlyphs;
273     SkSTArray<64, SkPoint, true>& fPositions;
274     SkSTArray<64, SkPoint, true>& fOffsets;
275     SkSTArray<64, uint32_t, true>& fClusterIndexes;
276 
277     SkSTArray<64, SkPoint, true> fJustificationShifts; // For justification
278                                                                    // (current and prev shifts)
279     SkSTArray<PARAM_64, SkPoint, true> fAutoSpacings; // For auto spacing
280                                                                    // (current and prev spacings)
281     SkSTArray<PARAM_64, SkScalar, true> fHalfLetterspacings; // For letterspacing
282 
283 #ifndef USE_SKIA_TXT
284     SkFontMetrics fFontMetrics;
285 #else
286     RSFontMetrics fFontMetrics;
287 #endif
288     const SkScalar fHeightMultiplier;
289     const bool fUseHalfLeading;
290     const SkScalar fBaselineShift;
291     SkScalar fCorrectAscent;
292     SkScalar fCorrectDescent;
293     SkScalar fCorrectLeading;
294 
295     bool fEllipsis;
296     uint8_t fBidiLevel;
297 
298     RoundRectType fRoundRectType = RoundRectType::NONE;
299     SkScalar fTopInGroup = 0.0f;
300     SkScalar fBottomInGroup = 0.0f;
301     SkScalar fMaxRoundRectRadius = 0.0f;
302     size_t indexInLine;
303 #ifdef OHOS_SUPPORT
304     SkScalar fCompressionBaselineShift{ 0.0f };
305 #endif
306 };
307 
308 template<typename Visitor>
iterateThroughClustersInTextOrder(Visitor visitor)309 void Run::iterateThroughClustersInTextOrder(Visitor visitor) {
310     // Can't figure out how to do it with one code for both cases without 100 ifs
311     // Can't go through clusters because there are no cluster table yet
312     if (leftToRight()) {
313         size_t start = 0;
314         size_t cluster = this->clusterIndex(start);
315         for (size_t glyph = 1; glyph <= this->size(); ++glyph) {
316             auto nextCluster = this->clusterIndex(glyph);
317             if (nextCluster <= cluster) {
318                 continue;
319             }
320 
321             visitor(start,
322                     glyph,
323                     fClusterStart + cluster,
324                     fClusterStart + nextCluster,
325                     this->calculateWidth(start, glyph, glyph == size()),
326                     this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
327 
328             start = glyph;
329             cluster = nextCluster;
330         }
331     } else {
332         size_t glyph = this->size();
333         size_t cluster = this->fUtf8Range.begin();
334         for (int32_t start = this->size() - 1; start >= 0; --start) {
335             size_t nextCluster =
336                     start == 0 ? this->fUtf8Range.end() : this->clusterIndex(start - 1);
337             if (nextCluster <= cluster) {
338                 continue;
339             }
340 
341             visitor(start,
342                     glyph,
343                     fClusterStart + cluster,
344                     fClusterStart + nextCluster,
345                     this->calculateWidth(start, glyph, glyph == 0),
346                     this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
347 
348             glyph = start;
349             cluster = nextCluster;
350         }
351     }
352 }
353 
354 #ifdef OHOS_SUPPORT
355 template<typename Visitor>
iterateGlyphRangeInTextOrder(const GlyphRange & glyphRange,Visitor visitor)356 void Run::iterateGlyphRangeInTextOrder(const GlyphRange& glyphRange, Visitor visitor) {
357     if (glyphRange.start >= glyphRange.end || glyphRange.end > size()) {
358         return;
359     }
360     if (leftToRight()) {
361         size_t start = glyphRange.start;
362         size_t cluster = this->clusterIndex(start);
363         for (size_t glyph = glyphRange.start + 1; glyph <= glyphRange.end; ++glyph) {
364             auto nextCluster = this->clusterIndex(glyph);
365             if (nextCluster <= cluster) {
366                 continue;
367             }
368 
369             visitor(start, glyph, fClusterStart + cluster, fClusterStart + nextCluster);
370             start = glyph;
371             cluster = nextCluster;
372         }
373     } else {
374         size_t glyph = glyphRange.end;
375         size_t cluster = this->clusterIndex(glyphRange.end - 1);
376         int32_t glyphStart = std::max((int32_t)glyphRange.start, 0);
377         for (int32_t start = glyphRange.end - 1; start >= glyphStart; --start) {
378             size_t nextCluster = start == 0 ? this->fUtf8Range.end() : this->clusterIndex(start - 1);
379             if (nextCluster <= cluster) {
380                 continue;
381             }
382 
383             visitor(start, glyph, fClusterStart + cluster, fClusterStart + nextCluster);
384             glyph = start;
385             cluster = nextCluster;
386         }
387     }
388 }
389 #endif
390 
391 class Cluster {
392 public:
393 
394 #ifdef OHOS_SUPPORT
395     enum AutoSpacingFlag {
396         NoFlag = 0,
397         CJK,
398         Western,
399         Copyright
400     };
401 #endif
402 
403     enum BreakType {
404         None,
405         GraphemeBreak,  // calculated for all clusters (UBRK_CHARACTER)
406         SoftLineBreak,  // calculated for all clusters (UBRK_LINE & UBRK_CHARACTER)
407         HardLineBreak,  // calculated for all clusters (UBRK_LINE)
408     };
409 
Cluster()410     Cluster()
411             : fOwner(nullptr)
412             , fRunIndex(EMPTY_RUN)
413             , fTextRange(EMPTY_TEXT)
414             , fGraphemeRange(EMPTY_RANGE)
415             , fStart(0)
416             , fEnd()
417             , fWidth()
418             , fHeight()
419             , fHalfLetterSpacing(0.0) {}
420 
421     Cluster(ParagraphImpl* owner,
422             RunIndex runIndex,
423             size_t start,
424             size_t end,
425             SkSpan<const char> text,
426             SkScalar width,
427             SkScalar height);
428 
Cluster(TextRange textRange)429     Cluster(TextRange textRange) : fTextRange(textRange), fGraphemeRange(EMPTY_RANGE) { }
430 
431     Cluster(const Cluster&) = default;
432     ~Cluster() = default;
433 
434     SkScalar sizeToChar(TextIndex ch) const;
435     SkScalar sizeFromChar(TextIndex ch) const;
436 
437     size_t roundPos(SkScalar s) const;
438 
space(SkScalar shift)439     void space(SkScalar shift) {
440         fWidth += shift;
441     }
442 
getOwner()443     ParagraphImpl* getOwner() const { return fOwner; }
setOwner(ParagraphImpl * owner)444     void setOwner(ParagraphImpl* owner) { fOwner = owner; }
445 
isWhitespaceBreak()446     bool isWhitespaceBreak() const { return fIsWhiteSpaceBreak; }
isIntraWordBreak()447     bool isIntraWordBreak() const { return fIsIntraWordBreak; }
isHardBreak()448     bool isHardBreak() const { return fIsHardBreak; }
isIdeographic()449     bool isIdeographic() const { return fIsIdeographic; }
isWordBreak()450     bool isWordBreak() const { return isWhitespaceBreak() || isHardBreak() || isSoftBreak() || run().isPlaceholder(); }
451 #ifdef OHOS_SUPPORT
isTabulation()452     bool isTabulation() const { return fIsTabulation; }
isPunctuation()453     bool isPunctuation() const { return fIsPunctuation; }
isEllipsis()454     bool isEllipsis() const { return fIsEllipsis; }
needAutoSpacing()455     bool needAutoSpacing() const { return fNeedAutoSpacing; }
enableHyphenBreak()456     void enableHyphenBreak() { fHyphenBreak = true; }
isHyphenBreak()457     bool isHyphenBreak() const { return fHyphenBreak; }
458 #endif
459 
460     bool isSoftBreak() const;
461     bool isGraphemeBreak() const;
canBreakLineAfter()462     bool canBreakLineAfter() const { return isHardBreak() || isSoftBreak(); }
startPos()463     size_t startPos() const { return fStart; }
endPos()464     size_t endPos() const { return fEnd; }
width()465     SkScalar width() const { return fWidth; }
height()466     SkScalar height() const { return fHeight; }
size()467     size_t size() const { return fEnd - fStart; }
468 
setHalfLetterSpacing(SkScalar halfLetterSpacing)469     void setHalfLetterSpacing(SkScalar halfLetterSpacing) { fHalfLetterSpacing = halfLetterSpacing; }
getHalfLetterSpacing()470     SkScalar getHalfLetterSpacing() const { return fHalfLetterSpacing; }
471 
textRange()472     TextRange textRange() const { return fTextRange; }
473 
runIndex()474     RunIndex runIndex() const { return fRunIndex; }
owner()475     ParagraphImpl* owner() const { return fOwner; }
476 
477     Run* runOrNull() const;
478     Run& run() const;
479 #ifndef USE_SKIA_TXT
480     SkFont font() const;
481 #else
482     RSFont font() const;
483 #endif
484 
485     SkScalar trimmedWidth(size_t pos) const;
486 
contains(TextIndex ch)487     bool contains(TextIndex ch) const { return ch >= fTextRange.start && ch < fTextRange.end; }
488 
belongs(TextRange text)489     bool belongs(TextRange text) const {
490         return fTextRange.start >= text.start && fTextRange.end <= text.end;
491     }
492 
startsIn(TextRange text)493     bool startsIn(TextRange text) const {
494         return fTextRange.start >= text.start && fTextRange.start < text.end;
495     }
496 
getFontSize()497     SkScalar getFontSize() const {
498         return font().GetSize();
499     }
500 
501 private:
502 
503     friend ParagraphImpl;
504 
505     ParagraphImpl* fOwner;
506     RunIndex fRunIndex;
507     TextRange fTextRange;
508     GraphemeRange fGraphemeRange;
509 
510     size_t fStart;
511     size_t fEnd;
512     SkScalar fWidth;
513     SkScalar fHeight;
514     SkScalar fHalfLetterSpacing;
515 
516     bool fIsWhiteSpaceBreak;
517     bool fIsIntraWordBreak;
518     bool fIsHardBreak;
519     bool fIsIdeographic;
520 #ifdef OHOS_SUPPORT
521     bool fIsTabulation;
522     bool fIsPunctuation{false};
523     bool fIsEllipsis{false};
524     bool fNeedAutoSpacing; // depend on last cluster flag
525     bool fHyphenBreak{false};
526 #endif
527 };
528 
529 class InternalLineMetrics {
530 public:
531 
InternalLineMetrics()532     InternalLineMetrics() {
533         clean();
534         fForceStrut = false;
535     }
536 
InternalLineMetrics(bool forceStrut)537     InternalLineMetrics(bool forceStrut) {
538         clean();
539         fForceStrut = forceStrut;
540     }
541 
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l)542     InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l) {
543         fAscent = a;
544         fDescent = d;
545         fLeading = l;
546         fRawAscent = a;
547         fRawDescent = d;
548         fRawLeading = l;
549         fForceStrut = false;
550     }
551 
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l,SkScalar ra,SkScalar rd,SkScalar rl)552     InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l, SkScalar ra, SkScalar rd, SkScalar rl) {
553         fAscent = a;
554         fDescent = d;
555         fLeading = l;
556         fRawAscent = ra;
557         fRawDescent = rd;
558         fRawLeading = rl;
559         fForceStrut = false;
560     }
561 
562 #ifdef OHOS_SUPPORT
563 #ifdef USE_SKIA_TXT
InternalLineMetrics(const RSFont & font,bool forceStrut)564     InternalLineMetrics(const RSFont& font, bool forceStrut) {
565         RSFontMetrics metrics;
566         auto compressFont = font;
567         scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
568         compressFont.GetMetrics(&metrics);
569 #else
570     InternalLineMetrics(const SkFont& font, bool forceStrut) {
571         SkFontMetrics metrics;
572         auto compressFont = font;
573         scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
574         compressFont.getMetrics(&metrics);
575 #endif
576         metricsIncludeFontPadding(&metrics, font);
577 #else
578     InternalLineMetrics(const SkFont& font, bool forceStrut) {
579         SkFontMetrics metrics;
580         font.getMetrics(&metrics);
581 #endif
582         fAscent = metrics.fAscent;
583         fDescent = metrics.fDescent;
584         fLeading = metrics.fLeading;
585         fRawAscent = metrics.fAscent;
586         fRawDescent = metrics.fDescent;
587         fRawLeading = metrics.fLeading;
588         fForceStrut = forceStrut;
589     }
590 
591     void add(Run* run) {
592         if (fForceStrut) {
593             return;
594         }
595         fAscent = std::min(fAscent, run->correctAscent());
596         fDescent = std::max(fDescent, run->correctDescent());
597         fLeading = std::max(fLeading, run->correctLeading());
598 
599         fRawAscent = std::min(fRawAscent, run->ascent());
600         fRawDescent = std::max(fRawDescent, run->descent());
601         fRawLeading = std::max(fRawLeading, run->leading());
602     }
603 
604     void add(InternalLineMetrics other) {
605         fAscent = std::min(fAscent, other.fAscent);
606         fDescent = std::max(fDescent, other.fDescent);
607         fLeading = std::max(fLeading, other.fLeading);
608         fRawAscent = std::min(fRawAscent, other.fRawAscent);
609         fRawDescent = std::max(fRawDescent, other.fRawDescent);
610         fRawLeading = std::max(fRawLeading, other.fRawLeading);
611     }
612 
613     void clean() {
614         fAscent = SK_ScalarMax;
615         fDescent = SK_ScalarMin;
616         fLeading = 0;
617         fRawAscent = SK_ScalarMax;
618         fRawDescent = SK_ScalarMin;
619         fRawLeading = 0;
620     }
621 
622     bool isClean() {
623         return (fAscent == SK_ScalarMax &&
624                 fDescent == SK_ScalarMin &&
625                 fLeading == 0 &&
626                 fRawAscent == SK_ScalarMax &&
627                 fRawDescent == SK_ScalarMin &&
628                 fRawLeading == 0);
629     }
630 
631     SkScalar delta() const { return height() - ideographicBaseline(); }
632 
633     void updateLineMetrics(InternalLineMetrics& metrics) {
634         if (metrics.fForceStrut) {
635             metrics.fAscent = fAscent;
636             metrics.fDescent = fDescent;
637             metrics.fLeading = fLeading;
638             metrics.fRawAscent = fRawAscent;
639             metrics.fRawDescent = fRawDescent;
640             metrics.fRawLeading = fRawLeading;
641         } else {
642             // This is another of those flutter changes. To be removed...
643             metrics.fAscent = std::min(metrics.fAscent, fAscent - fLeading / 2.0f);
644             metrics.fDescent = std::max(metrics.fDescent, fDescent + fLeading / 2.0f);
645             metrics.fRawAscent = std::min(metrics.fRawAscent, fRawAscent - fRawLeading / 2.0f);
646             metrics.fRawDescent = std::max(metrics.fRawDescent, fRawDescent + fRawLeading / 2.0f);
647         }
648     }
649 
650     SkScalar runTop(const Run* run, LineMetricStyle ascentStyle) const {
651         return fLeading / 2 - fAscent +
652           (ascentStyle == LineMetricStyle::Typographic ? run->ascent() : run->correctAscent()) + delta();
653     }
654 
655     SkScalar height() const {
656         return ::round((double)fDescent - fAscent + fLeading);
657     }
658 
659     void update(SkScalar a, SkScalar d, SkScalar l) {
660         fAscent = a;
661         fDescent = d;
662         fLeading = l;
663     }
664 
665     void updateRawData(SkScalar ra, SkScalar rd) {
666         fRawAscent = ra;
667         fRawDescent = rd;
668     }
669 
670     SkScalar alphabeticBaseline() const { return fLeading / 2 - fAscent; }
671     SkScalar ideographicBaseline() const { return fDescent - fAscent + fLeading; }
672     SkScalar deltaBaselines() const { return fLeading / 2 + fDescent; }
673     SkScalar baseline() const { return fLeading / 2 - fAscent; }
674     SkScalar ascent() const { return fAscent; }
675     SkScalar descent() const { return fDescent; }
676     SkScalar leading() const { return fLeading; }
677     SkScalar rawAscent() const { return fRawAscent; }
678     SkScalar rawDescent() const { return fRawDescent; }
679     void setForceStrut(bool value) { fForceStrut = value; }
680     bool getForceStrut() const { return fForceStrut; }
681 
682 private:
683 
684     friend class ParagraphImpl;
685     friend class TextWrapper;
686     friend class TextLine;
687 
688     SkScalar fAscent;
689     SkScalar fDescent;
690     SkScalar fLeading;
691 
692     SkScalar fRawAscent;
693     SkScalar fRawDescent;
694     SkScalar fRawLeading;
695 
696     bool fForceStrut;
697 };
698 }  // namespace textlayout
699 }  // namespace skia
700 
701 #endif  // Run_DEFINED
702