xref: /aosp_15_r20/external/skia/modules/skparagraph/src/Run.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 class SkTextBlobBuilder;
24 
25 namespace skia {
26 namespace textlayout {
27 
28 class Cluster;
29 class InternalLineMetrics;
30 class ParagraphImpl;
31 
32 typedef size_t RunIndex;
33 const size_t EMPTY_RUN = EMPTY_INDEX;
34 
35 typedef size_t ClusterIndex;
36 typedef SkRange<size_t> ClusterRange;
37 const size_t EMPTY_CLUSTER = EMPTY_INDEX;
38 const SkRange<size_t> EMPTY_CLUSTERS = EMPTY_RANGE;
39 
40 typedef size_t GraphemeIndex;
41 typedef SkRange<GraphemeIndex> GraphemeRange;
42 
43 typedef size_t GlyphIndex;
44 typedef SkRange<GlyphIndex> GlyphRange;
45 
46 // LTR: [start: end) where start <= end
47 // RTL: [end: start) where start >= end
48 class DirText {
DirText(bool dir,size_t s,size_t e)49     DirText(bool dir, size_t s, size_t e) : start(s), end(e) { }
isLeftToRight()50     bool isLeftToRight() const { return start <= end; }
51     size_t start;
52     size_t end;
53 };
54 
55 class Run {
56 public:
57     Run(ParagraphImpl* owner,
58         const SkShaper::RunHandler::RunInfo& info,
59         size_t firstChar,
60         SkScalar heightMultiplier,
61         bool useHalfLeading,
62         SkScalar baselineShift,
63         size_t index,
64         SkScalar shiftX);
65     Run(const Run&) = default;
66     Run& operator=(const Run&) = delete;
67     Run(Run&&) = default;
68     Run& operator=(Run&&) = delete;
69     ~Run() = default;
70 
setOwner(ParagraphImpl * owner)71     void setOwner(ParagraphImpl* owner) { fOwner = owner; }
72 
73     SkShaper::RunHandler::Buffer newRunBuffer();
74 
posX(size_t index)75     SkScalar posX(size_t index) const { return fPositions[index].fX; }
addX(size_t index,SkScalar shift)76     void addX(size_t index, SkScalar shift) { fPositions[index].fX += shift; }
posY(size_t index)77     SkScalar posY(size_t index) const { return fPositions[index].fY; }
size()78     size_t size() const { return fGlyphs.size(); }
setWidth(SkScalar width)79     void setWidth(SkScalar width) { fAdvance.fX = width; }
setHeight(SkScalar height)80     void setHeight(SkScalar height) { fAdvance.fY = height; }
shift(SkScalar shiftX,SkScalar shiftY)81     void shift(SkScalar shiftX, SkScalar shiftY) {
82         fOffset.fX += shiftX;
83         fOffset.fY += shiftY;
84     }
advance()85     SkVector advance() const {
86         return SkVector::Make(fAdvance.fX, fFontMetrics.fDescent - fFontMetrics.fAscent + fFontMetrics.fLeading);
87     }
offset()88     SkVector offset() const { return fOffset; }
ascent()89     SkScalar ascent() const { return fFontMetrics.fAscent + fBaselineShift; }
descent()90     SkScalar descent() const { return fFontMetrics.fDescent + fBaselineShift; }
leading()91     SkScalar leading() const { return fFontMetrics.fLeading; }
correctAscent()92     SkScalar correctAscent() const { return fCorrectAscent + fBaselineShift; }
correctDescent()93     SkScalar correctDescent() const { return fCorrectDescent + fBaselineShift; }
correctLeading()94     SkScalar correctLeading() const { return fCorrectLeading; }
font()95     const SkFont& font() const { return fFont; }
leftToRight()96     bool leftToRight() const { return fBidiLevel % 2 == 0; }
getTextDirection()97     TextDirection getTextDirection() const { return leftToRight() ? TextDirection::kLtr : TextDirection::kRtl; }
index()98     size_t index() const { return fIndex; }
heightMultiplier()99     SkScalar heightMultiplier() const { return fHeightMultiplier; }
useHalfLeading()100     bool useHalfLeading() const { return fUseHalfLeading; }
baselineShift()101     SkScalar baselineShift() const { return fBaselineShift; }
102     PlaceholderStyle* placeholderStyle() const;
isPlaceholder()103     bool isPlaceholder() const { return fPlaceholderIndex != std::numeric_limits<size_t>::max(); }
clusterIndex(size_t pos)104     size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }
globalClusterIndex(size_t pos)105     size_t globalClusterIndex(size_t pos) const { return fClusterStart + fClusterIndexes[pos]; }
106     SkScalar positionX(size_t pos) const;
107 
textRange()108     TextRange textRange() const { return fTextRange; }
clusterRange()109     ClusterRange clusterRange() const { return fClusterRange; }
110 
owner()111     ParagraphImpl* owner() const { return fOwner; }
112 
isEllipsis()113     bool isEllipsis() const { return fEllipsis; }
114 
115     void calculateMetrics();
116     void updateMetrics(InternalLineMetrics* endlineMetrics);
117 
setClusterRange(size_t from,size_t to)118     void setClusterRange(size_t from, size_t to) { fClusterRange = ClusterRange(from, to); }
clip()119     SkRect clip() const {
120         return SkRect::MakeXYWH(fOffset.fX, fOffset.fY, fAdvance.fX, fAdvance.fY);
121     }
122 
123     void addSpacesAtTheEnd(SkScalar space, Cluster* cluster);
124     SkScalar addSpacesEvenly(SkScalar space, Cluster* cluster);
125     SkScalar addSpacesEvenly(SkScalar space);
126     void shift(const Cluster* cluster, SkScalar offset);
127     void extend(const Cluster* cluster, SkScalar offset);
128 
calculateHeight(LineMetricStyle ascentStyle,LineMetricStyle descentStyle)129     SkScalar calculateHeight(LineMetricStyle ascentStyle, LineMetricStyle descentStyle) const {
130         auto ascent = ascentStyle == LineMetricStyle::Typographic ? this->ascent()
131                                     : this->correctAscent();
132         auto descent = descentStyle == LineMetricStyle::Typographic ? this->descent()
133                                       : this->correctDescent();
134         return descent - ascent;
135     }
136     SkScalar calculateWidth(size_t start, size_t end, bool clip) const;
137 
138     void copyTo(SkTextBlobBuilder& builder, size_t pos, size_t size) const;
139 
140     template<typename Visitor>
141     void iterateThroughClustersInTextOrder(Visitor visitor);
142 
143     using ClusterVisitor = std::function<void(Cluster* cluster)>;
144     void iterateThroughClusters(const ClusterVisitor& visitor);
145 
146     std::tuple<bool, ClusterIndex, ClusterIndex> findLimitingClusters(TextRange text) const;
147     std::tuple<bool, TextIndex, TextIndex> findLimitingGlyphClusters(TextRange text) const;
148     std::tuple<bool, TextIndex, TextIndex> findLimitingGraphemes(TextRange text) const;
glyphs()149     SkSpan<const SkGlyphID> glyphs() const {
150         return SkSpan<const SkGlyphID>(fGlyphs.begin(), fGlyphs.size());
151     }
positions()152     SkSpan<const SkPoint> positions() const {
153         return SkSpan<const SkPoint>(fPositions.begin(), fPositions.size());
154     }
offsets()155     SkSpan<const SkPoint> offsets() const {
156         return SkSpan<const SkPoint>(fOffsets.begin(), fOffsets.size());
157     }
clusterIndexes()158     SkSpan<const uint32_t> clusterIndexes() const {
159         return SkSpan<const uint32_t>(fClusterIndexes.begin(), fClusterIndexes.size());
160     }
161 
commit()162     void commit() { }
163 
resetJustificationShifts()164     void resetJustificationShifts() {
165         fJustificationShifts.clear();
166     }
167 
168     bool isResolved() const;
169 private:
170     friend class ParagraphImpl;
171     friend class TextLine;
172     friend class InternalLineMetrics;
173     friend class ParagraphCache;
174     friend class OneLineShaper;
175 
176     ParagraphImpl* fOwner;
177     TextRange fTextRange;
178     ClusterRange fClusterRange;
179 
180     SkFont fFont;
181     size_t fPlaceholderIndex;
182     size_t fIndex;
183     SkVector fAdvance;
184     SkVector fOffset;
185     TextIndex fClusterStart;
186     SkShaper::RunHandler::Range fUtf8Range;
187 
188     // These fields are not modified after shaping completes and can safely be
189     // shared among copies of the run that are held by different paragraphs.
190     struct GlyphData {
191         skia_private::STArray<64, SkGlyphID, true> glyphs;
192         skia_private::STArray<64, SkPoint, true> positions;
193         skia_private::STArray<64, SkPoint, true> offsets;
194         skia_private::STArray<64, uint32_t, true> clusterIndexes;
195     };
196     std::shared_ptr<GlyphData> fGlyphData;
197     skia_private::STArray<64, SkGlyphID, true>& fGlyphs;
198     skia_private::STArray<64, SkPoint, true>& fPositions;
199     skia_private::STArray<64, SkPoint, true>& fOffsets;
200     skia_private::STArray<64, uint32_t, true>& fClusterIndexes;
201 
202     skia_private::STArray<64, SkPoint, true> fJustificationShifts; // For justification
203                                                                    // (current and prev shifts)
204 
205     SkFontMetrics fFontMetrics;
206     const SkScalar fHeightMultiplier;
207     const bool fUseHalfLeading;
208     const SkScalar fBaselineShift;
209     SkScalar fCorrectAscent;
210     SkScalar fCorrectDescent;
211     SkScalar fCorrectLeading;
212 
213     bool fEllipsis;
214     uint8_t fBidiLevel;
215 };
216 
217 template<typename Visitor>
iterateThroughClustersInTextOrder(Visitor visitor)218 void Run::iterateThroughClustersInTextOrder(Visitor visitor) {
219     // Can't figure out how to do it with one code for both cases without 100 ifs
220     // Can't go through clusters because there are no cluster table yet
221     if (leftToRight()) {
222         size_t start = 0;
223         size_t cluster = this->clusterIndex(start);
224         for (size_t glyph = 1; glyph <= this->size(); ++glyph) {
225             auto nextCluster = this->clusterIndex(glyph);
226             if (nextCluster <= cluster) {
227                 continue;
228             }
229 
230             visitor(start,
231                     glyph,
232                     fClusterStart + cluster,
233                     fClusterStart + nextCluster,
234                     this->calculateWidth(start, glyph, glyph == size()),
235                     this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
236 
237             start = glyph;
238             cluster = nextCluster;
239         }
240     } else {
241         size_t glyph = this->size();
242         size_t cluster = this->fUtf8Range.begin();
243         for (int32_t start = this->size() - 1; start >= 0; --start) {
244             size_t nextCluster =
245                     start == 0 ? this->fUtf8Range.end() : this->clusterIndex(start - 1);
246             if (nextCluster <= cluster) {
247                 continue;
248             }
249 
250             visitor(start,
251                     glyph,
252                     fClusterStart + cluster,
253                     fClusterStart + nextCluster,
254                     this->calculateWidth(start, glyph, glyph == 0),
255                     this->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS));
256 
257             glyph = start;
258             cluster = nextCluster;
259         }
260     }
261 }
262 
263 class Cluster {
264 public:
265     enum BreakType {
266         None,
267         GraphemeBreak,  // calculated for all clusters (UBRK_CHARACTER)
268         SoftLineBreak,  // calculated for all clusters (UBRK_LINE & UBRK_CHARACTER)
269         HardLineBreak,  // calculated for all clusters (UBRK_LINE)
270     };
271 
Cluster()272     Cluster()
273             : fOwner(nullptr)
274             , fRunIndex(EMPTY_RUN)
275             , fTextRange(EMPTY_TEXT)
276             , fGraphemeRange(EMPTY_RANGE)
277             , fStart(0)
278             , fEnd()
279             , fWidth()
280             , fHeight()
281             , fHalfLetterSpacing(0.0) {}
282 
283     Cluster(ParagraphImpl* owner,
284             RunIndex runIndex,
285             size_t start,
286             size_t end,
287             SkSpan<const char> text,
288             SkScalar width,
289             SkScalar height);
290 
Cluster(TextRange textRange)291     Cluster(TextRange textRange) : fTextRange(textRange), fGraphemeRange(EMPTY_RANGE) { }
292 
293     Cluster(const Cluster&) = default;
294     ~Cluster() = default;
295 
296     SkScalar sizeToChar(TextIndex ch) const;
297     SkScalar sizeFromChar(TextIndex ch) const;
298 
299     size_t roundPos(SkScalar s) const;
300 
space(SkScalar shift)301     void space(SkScalar shift) {
302         fWidth += shift;
303     }
304 
getOwner()305     ParagraphImpl* getOwner() const { return fOwner; }
setOwner(ParagraphImpl * owner)306     void setOwner(ParagraphImpl* owner) { fOwner = owner; }
307 
isWhitespaceBreak()308     bool isWhitespaceBreak() const { return fIsWhiteSpaceBreak; }
isIntraWordBreak()309     bool isIntraWordBreak() const { return fIsIntraWordBreak; }
isHardBreak()310     bool isHardBreak() const { return fIsHardBreak; }
isIdeographic()311     bool isIdeographic() const { return fIsIdeographic; }
312 
313     bool isSoftBreak() const;
314     bool isGraphemeBreak() const;
canBreakLineAfter()315     bool canBreakLineAfter() const { return isHardBreak() || isSoftBreak(); }
startPos()316     size_t startPos() const { return fStart; }
endPos()317     size_t endPos() const { return fEnd; }
width()318     SkScalar width() const { return fWidth; }
height()319     SkScalar height() const { return fHeight; }
size()320     size_t size() const { return fEnd - fStart; }
321 
setHalfLetterSpacing(SkScalar halfLetterSpacing)322     void setHalfLetterSpacing(SkScalar halfLetterSpacing) { fHalfLetterSpacing = halfLetterSpacing; }
getHalfLetterSpacing()323     SkScalar getHalfLetterSpacing() const { return fHalfLetterSpacing; }
324 
textRange()325     TextRange textRange() const { return fTextRange; }
326 
runIndex()327     RunIndex runIndex() const { return fRunIndex; }
owner()328     ParagraphImpl* owner() const { return fOwner; }
329 
330     Run* runOrNull() const;
331     Run& run() const;
332     SkFont font() const;
333 
334     SkScalar trimmedWidth(size_t pos) const;
335 
contains(TextIndex ch)336     bool contains(TextIndex ch) const { return ch >= fTextRange.start && ch < fTextRange.end; }
337 
belongs(TextRange text)338     bool belongs(TextRange text) const {
339         return fTextRange.start >= text.start && fTextRange.end <= text.end;
340     }
341 
startsIn(TextRange text)342     bool startsIn(TextRange text) const {
343         return fTextRange.start >= text.start && fTextRange.start < text.end;
344     }
345 
346 private:
347 
348     friend ParagraphImpl;
349 
350     ParagraphImpl* fOwner;
351     RunIndex fRunIndex;
352     TextRange fTextRange;
353     GraphemeRange fGraphemeRange;
354 
355     size_t fStart;
356     size_t fEnd;
357     SkScalar fWidth;
358     SkScalar fHeight;
359     SkScalar fHalfLetterSpacing;
360 
361     bool fIsWhiteSpaceBreak;
362     bool fIsIntraWordBreak;
363     bool fIsHardBreak;
364     bool fIsIdeographic;
365 };
366 
367 class InternalLineMetrics {
368 public:
369 
InternalLineMetrics()370     InternalLineMetrics() {
371         clean();
372         fForceStrut = false;
373     }
374 
InternalLineMetrics(bool forceStrut)375     InternalLineMetrics(bool forceStrut) {
376         clean();
377         fForceStrut = forceStrut;
378     }
379 
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l)380     InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l) {
381         fAscent = a;
382         fDescent = d;
383         fLeading = l;
384         fRawAscent = a;
385         fRawDescent = d;
386         fRawLeading = l;
387         fForceStrut = false;
388     }
389 
InternalLineMetrics(SkScalar a,SkScalar d,SkScalar l,SkScalar ra,SkScalar rd,SkScalar rl)390     InternalLineMetrics(SkScalar a, SkScalar d, SkScalar l, SkScalar ra, SkScalar rd, SkScalar rl) {
391         fAscent = a;
392         fDescent = d;
393         fLeading = l;
394         fRawAscent = ra;
395         fRawDescent = rd;
396         fRawLeading = rl;
397         fForceStrut = false;
398     }
399 
InternalLineMetrics(const SkFont & font,bool forceStrut)400     InternalLineMetrics(const SkFont& font, bool forceStrut) {
401         SkFontMetrics metrics;
402         font.getMetrics(&metrics);
403         fAscent = metrics.fAscent;
404         fDescent = metrics.fDescent;
405         fLeading = metrics.fLeading;
406         fRawAscent = metrics.fAscent;
407         fRawDescent = metrics.fDescent;
408         fRawLeading = metrics.fLeading;
409         fForceStrut = forceStrut;
410     }
411 
add(Run * run)412     void add(Run* run) {
413         if (fForceStrut) {
414             return;
415         }
416         fAscent = std::min(fAscent, run->correctAscent());
417         fDescent = std::max(fDescent, run->correctDescent());
418         fLeading = std::max(fLeading, run->correctLeading());
419 
420         fRawAscent = std::min(fRawAscent, run->ascent());
421         fRawDescent = std::max(fRawDescent, run->descent());
422         fRawLeading = std::max(fRawLeading, run->leading());
423     }
424 
add(InternalLineMetrics other)425     void add(InternalLineMetrics other) {
426         fAscent = std::min(fAscent, other.fAscent);
427         fDescent = std::max(fDescent, other.fDescent);
428         fLeading = std::max(fLeading, other.fLeading);
429         fRawAscent = std::min(fRawAscent, other.fRawAscent);
430         fRawDescent = std::max(fRawDescent, other.fRawDescent);
431         fRawLeading = std::max(fRawLeading, other.fRawLeading);
432     }
433 
clean()434     void clean() {
435         fAscent = SK_ScalarMax;
436         fDescent = SK_ScalarMin;
437         fLeading = 0;
438         fRawAscent = SK_ScalarMax;
439         fRawDescent = SK_ScalarMin;
440         fRawLeading = 0;
441     }
442 
isClean()443     bool isClean() {
444         return (fAscent == SK_ScalarMax &&
445                 fDescent == SK_ScalarMin &&
446                 fLeading == 0 &&
447                 fRawAscent == SK_ScalarMax &&
448                 fRawDescent == SK_ScalarMin &&
449                 fRawLeading == 0);
450     }
451 
delta()452     SkScalar delta() const { return height() - ideographicBaseline(); }
453 
updateLineMetrics(InternalLineMetrics & metrics)454     void updateLineMetrics(InternalLineMetrics& metrics) {
455         if (metrics.fForceStrut) {
456             metrics.fAscent = fAscent;
457             metrics.fDescent = fDescent;
458             metrics.fLeading = fLeading;
459             metrics.fRawAscent = fRawAscent;
460             metrics.fRawDescent = fRawDescent;
461             metrics.fRawLeading = fRawLeading;
462         } else {
463             // This is another of those flutter changes. To be removed...
464             metrics.fAscent = std::min(metrics.fAscent, fAscent - fLeading / 2.0f);
465             metrics.fDescent = std::max(metrics.fDescent, fDescent + fLeading / 2.0f);
466             metrics.fRawAscent = std::min(metrics.fRawAscent, fRawAscent - fRawLeading / 2.0f);
467             metrics.fRawDescent = std::max(metrics.fRawDescent, fRawDescent + fRawLeading / 2.0f);
468         }
469     }
470 
runTop(const Run * run,LineMetricStyle ascentStyle)471     SkScalar runTop(const Run* run, LineMetricStyle ascentStyle) const {
472         return fLeading / 2 - fAscent +
473           (ascentStyle == LineMetricStyle::Typographic ? run->ascent() : run->correctAscent()) + delta();
474     }
475 
height()476     SkScalar height() const {
477         return ::round((double)fDescent - fAscent + fLeading);
478     }
479 
update(SkScalar a,SkScalar d,SkScalar l)480     void update(SkScalar a, SkScalar d, SkScalar l) {
481         fAscent = a;
482         fDescent = d;
483         fLeading = l;
484     }
485 
updateRawData(SkScalar ra,SkScalar rd)486     void updateRawData(SkScalar ra, SkScalar rd) {
487         fRawAscent = ra;
488         fRawDescent = rd;
489     }
490 
alphabeticBaseline()491     SkScalar alphabeticBaseline() const { return fLeading / 2 - fAscent; }
ideographicBaseline()492     SkScalar ideographicBaseline() const { return fDescent - fAscent + fLeading; }
deltaBaselines()493     SkScalar deltaBaselines() const { return fLeading / 2 + fDescent; }
baseline()494     SkScalar baseline() const { return fLeading / 2 - fAscent; }
ascent()495     SkScalar ascent() const { return fAscent; }
descent()496     SkScalar descent() const { return fDescent; }
leading()497     SkScalar leading() const { return fLeading; }
rawAscent()498     SkScalar rawAscent() const { return fRawAscent; }
rawDescent()499     SkScalar rawDescent() const { return fRawDescent; }
setForceStrut(bool value)500     void setForceStrut(bool value) { fForceStrut = value; }
getForceStrut()501     bool getForceStrut() const { return fForceStrut; }
502 
503 private:
504 
505     friend class ParagraphImpl;
506     friend class TextWrapper;
507     friend class TextLine;
508 
509     SkScalar fAscent;
510     SkScalar fDescent;
511     SkScalar fLeading;
512 
513     SkScalar fRawAscent;
514     SkScalar fRawDescent;
515     SkScalar fRawLeading;
516 
517     bool fForceStrut;
518 };
519 }  // namespace textlayout
520 }  // namespace skia
521 
522 #endif  // Run_DEFINED
523