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