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