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