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