Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Run.cpp
Go to the documentation of this file.
1// Copyright 2019 Google LLC.
12#include "src/base/SkUTF.h"
13
14namespace skia {
15namespace textlayout {
16
19 size_t firstChar,
20 SkScalar heightMultiplier,
21 bool useHalfLeading,
22 SkScalar baselineShift,
23 size_t index,
25 : fOwner(owner)
26 , fTextRange(firstChar + info.utf8Range.begin(), firstChar + info.utf8Range.end())
27 , fClusterRange(EMPTY_CLUSTERS)
28 , fFont(info.fFont)
29 , fClusterStart(firstChar)
30 , fGlyphData(std::make_shared<GlyphData>())
31 , fGlyphs(fGlyphData->glyphs)
32 , fPositions(fGlyphData->positions)
33 , fOffsets(fGlyphData->offsets)
34 , fClusterIndexes(fGlyphData->clusterIndexes)
35 , fHeightMultiplier(heightMultiplier)
36 , fUseHalfLeading(useHalfLeading)
37 , fBaselineShift(baselineShift)
38{
39 fBidiLevel = info.fBidiLevel;
40 fAdvance = info.fAdvance;
41 fIndex = index;
42 fUtf8Range = info.utf8Range;
43 fOffset = SkVector::Make(offsetX, 0);
44
45 fGlyphs.push_back_n(info.glyphCount);
46 fPositions.push_back_n(info.glyphCount + 1);
47 fOffsets.push_back_n(info.glyphCount + 1);
48 fClusterIndexes.push_back_n(info.glyphCount + 1);
49 info.fFont.getMetrics(&fFontMetrics);
50
51 this->calculateMetrics();
52
53 // To make edge cases easier:
54 fPositions[info.glyphCount] = fOffset + fAdvance;
55 fOffsets[info.glyphCount] = {0, 0};
56 fClusterIndexes[info.glyphCount] = this->leftToRight() ? info.utf8Range.end() : info.utf8Range.begin();
57 fEllipsis = false;
58 fPlaceholderIndex = std::numeric_limits<size_t>::max();
59}
60
62 fCorrectAscent = fFontMetrics.fAscent - fFontMetrics.fLeading * 0.5;
63 fCorrectDescent = fFontMetrics.fDescent + fFontMetrics.fLeading * 0.5;
64 fCorrectLeading = 0;
65 if (SkScalarNearlyZero(fHeightMultiplier)) {
66 return;
67 }
68 const auto runHeight = fHeightMultiplier * fFont.getSize();
69 const auto fontIntrinsicHeight = fCorrectDescent - fCorrectAscent;
70 if (fUseHalfLeading) {
71 const auto extraLeading = (runHeight - fontIntrinsicHeight) / 2;
72 fCorrectAscent -= extraLeading;
73 fCorrectDescent += extraLeading;
74 } else {
75 const auto multiplier = runHeight / fontIntrinsicHeight;
76 fCorrectAscent *= multiplier;
77 fCorrectDescent *= multiplier;
78 }
79 // If we shift the baseline we need to make sure the shifted text fits the line
80 fCorrectAscent += fBaselineShift;
81 fCorrectDescent += fBaselineShift;
82}
83
85 return {fGlyphs.data(), fPositions.data(), fOffsets.data(), fClusterIndexes.data(), fOffset};
86}
87
88void Run::copyTo(SkTextBlobBuilder& builder, size_t pos, size_t size) const {
89 SkASSERT(pos + size <= this->size());
90 const auto& blobBuffer = builder.allocRunPos(fFont, SkToInt(size));
91 sk_careful_memcpy(blobBuffer.glyphs, fGlyphs.data() + pos, size * sizeof(SkGlyphID));
92
93 for (size_t i = 0; i < size; ++i) {
94 auto point = fPositions[i + pos];
95 if (!fJustificationShifts.empty()) {
96 point.fX += fJustificationShifts[i + pos].fX;
97 }
98 point += fOffsets[i + pos];
99 blobBuffer.points()[i] = point;
100 }
101}
102
103// Find a cluster range from text range (within one run)
104// Cluster range is normalized ([start:end) start < end regardless of TextDirection
105// Boolean value in triple indicates whether the cluster range was found or not
106std::tuple<bool, ClusterIndex, ClusterIndex> Run::findLimitingClusters(TextRange text) const {
107 if (text.width() == 0) {
108 // Special Flutter case for "\n" and "...\n"
109 if (text.end > this->fTextRange.start) {
110 ClusterIndex index = fOwner->clusterIndex(text.end - 1);
111 return std::make_tuple(true, index, index);
112 } else {
113 return std::make_tuple(false, 0, 0);
114 }
115 }
116
118 bool found = true;
119 // Deal with the case when either start or end are not align with glyph cluster edge
120 // In such case we shift the text range to the right
121 // (cutting from the left and adding to the right)
122 if (leftToRight()) {
123 // LTR: [start:end)
124 found = clusterRange.start != fClusterRange.end;
125 clusterRange.start = fOwner->clusterIndex(text.start);
126 clusterRange.end = fOwner->clusterIndex(text.end - 1);
127 } else {
128 // RTL: (start:end]
129 clusterRange.start = fOwner->clusterIndex(text.end);
130 clusterRange.end = fOwner->clusterIndex(text.start + 1);
131 found = clusterRange.end != fClusterRange.start;
132 }
133
134 return std::make_tuple(
135 found,
138}
139
140std::tuple<bool, TextIndex, TextIndex> Run::findLimitingGlyphClusters(TextRange text) const {
143 return std::make_tuple(true, start, end);
144}
145
146// Adjust the text to grapheme edges so the first grapheme start is in the text and the last grapheme start is in the text
147// It actually means that the first grapheme is entirely in the text and the last grapheme does not have to be
148// 12345 234 2:2 -> 2,5 4:4
149std::tuple<bool, TextIndex, TextIndex> Run::findLimitingGraphemes(TextRange text) const {
152 return std::make_tuple(true, start, end);
153}
154
156
157 for (size_t index = 0; index < fClusterRange.width(); ++index) {
158 auto correctIndex = leftToRight() ? fClusterRange.start + index : fClusterRange.end - index - 1;
159 auto cluster = &fOwner->cluster(correctIndex);
160 visitor(cluster);
161 }
162}
163
165 // Increment the run width
166 fAdvance.fX += space;
167 // Increment the cluster width
168 cluster->space(space);
169}
170
172 SkScalar shift = 0;
173 for (size_t i = 0; i < this->size(); ++i) {
174 fPositions[i].fX += shift;
175 shift += space;
176 }
177 fPositions[this->size()].fX += shift;
178 fAdvance.fX += shift;
179 return shift;
180}
181
183 // Offset all the glyphs in the cluster
184 SkScalar shift = 0;
185 for (size_t i = cluster->startPos(); i < cluster->endPos(); ++i) {
186 fPositions[i].fX += shift;
187 shift += space;
188 }
189 if (this->size() == cluster->endPos()) {
190 // To make calculations easier
191 fPositions[cluster->endPos()].fX += shift;
192 }
193 // Increment the run width
194 fAdvance.fX += shift;
195 // Increment the cluster width
196 cluster->space(shift);
197 cluster->setHalfLetterSpacing(space / 2);
198
199 return shift;
200}
201
202void Run::shift(const Cluster* cluster, SkScalar offset) {
203 if (offset == 0) {
204 return;
205 }
206 for (size_t i = cluster->startPos(); i < cluster->endPos(); ++i) {
207 fPositions[i].fX += offset;
208 }
209 if (this->size() == cluster->endPos()) {
210 // To make calculations easier
211 fPositions[cluster->endPos()].fX += offset;
212 }
213}
214
215void Run::extend(const Cluster* cluster, SkScalar offset) {
216 // Extend the cluster at the end
217 fPositions[cluster->endPos()].fX += offset;
218}
219
221
223 auto placeholderStyle = this->placeholderStyle();
224 // Difference between the placeholder baseline and the line bottom
225 SkScalar baselineAdjustment = 0;
226 switch (placeholderStyle->fBaseline) {
228 break;
229
231 baselineAdjustment = endlineMetrics->deltaBaselines() / 2;
232 break;
233 }
234
237
238 fFontMetrics.fLeading = 0;
239 switch (placeholderStyle->fAlignment) {
241 fFontMetrics.fAscent = baselineAdjustment - offset;
242 fFontMetrics.fDescent = baselineAdjustment + height - offset;
243 break;
244
246 fFontMetrics.fAscent = baselineAdjustment - height;
247 fFontMetrics.fDescent = baselineAdjustment;
248 break;
249
251 fFontMetrics.fAscent = baselineAdjustment;
252 fFontMetrics.fDescent = baselineAdjustment + height;
253 break;
254
256 fFontMetrics.fDescent = height + fFontMetrics.fAscent;
257 break;
258
260 fFontMetrics.fAscent = fFontMetrics.fDescent - height;
261 break;
262
264 auto mid = (-fFontMetrics.fDescent - fFontMetrics.fAscent)/2.0;
265 fFontMetrics.fDescent = height/2.0 - mid;
266 fFontMetrics.fAscent = - height/2.0 - mid;
267 break;
268 }
269
270 this->calculateMetrics();
271
272 // Make sure the placeholder can fit the line
273 endlineMetrics->add(this);
274}
275
277 if (ch < fTextRange.start || ch >= fTextRange.end) {
278 return 0;
279 }
280 auto shift = ch - fTextRange.start;
281 auto ratio = shift * 1.0 / fTextRange.width();
282
283 return SkDoubleToScalar(fWidth * ratio);
284}
285
287 if (ch < fTextRange.start || ch >= fTextRange.end) {
288 return 0;
289 }
290 auto shift = fTextRange.end - ch - 1;
291 auto ratio = shift * 1.0 / fTextRange.width();
292
293 return SkDoubleToScalar(fWidth * ratio);
294}
295
297 auto ratio = (s * 1.0) / fWidth;
298 return sk_double_floor2int(ratio * size());
299}
300
302 // Find the width until the pos and return the min between trimmedWidth and the width(pos)
303 // We don't have to take in account cluster shift since it's the same for 0 and for pos
304 auto& run = fOwner->run(fRunIndex);
305 return std::min(run.positionX(pos) - run.positionX(fStart), fWidth);
306}
307
309 return posX(pos) + (fJustificationShifts.empty() ? 0 : fJustificationShifts[pos].fY);
310}
311
313 if (isPlaceholder()) {
314 return &fOwner->placeholders()[fPlaceholderIndex].fStyle;
315 } else {
316 return nullptr;
317 }
318}
319
320bool Run::isResolved() const {
321 for (auto& glyph :fGlyphs) {
322 if (glyph == 0) {
323 return false;
324 }
325 }
326 return true;
327}
328
330 if (fRunIndex >= fOwner->runs().size()) {
331 return nullptr;
332 }
333 return &fOwner->run(fRunIndex);
334}
335
337 SkASSERT(fRunIndex < fOwner->runs().size());
338 return fOwner->run(fRunIndex);
339}
340
342 SkASSERT(fRunIndex < fOwner->runs().size());
343 return fOwner->run(fRunIndex).font();
344}
345
350
354} // namespace textlayout
355} // namespace skia
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
uint16_t glyphs[5]
SkPoint pos
#define SkASSERT(cond)
Definition SkAssert.h:116
#define sk_double_floor2int(x)
static void * sk_careful_memcpy(void *dst, const void *src, size_t len)
Definition SkMalloc.h:125
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:101
#define SkDoubleToScalar(x)
Definition SkScalar.h:64
constexpr int SkToInt(S x)
Definition SkTo.h:29
uint16_t SkGlyphID
Definition SkTypes.h:179
SkScalar getSize() const
Definition SkFont.h:217
@ kGraphemeStart
Definition SkUnicode.h:82
@ kSoftLineBreakBefore
Definition SkUnicode.h:83
SkFont font() const
Definition Run.cpp:341
size_t startPos() const
Definition Run.h:316
SkScalar trimmedWidth(size_t pos) const
Definition Run.cpp:301
size_t roundPos(SkScalar s) const
Definition Run.cpp:296
SkScalar sizeFromChar(TextIndex ch) const
Definition Run.cpp:286
bool isSoftBreak() const
Definition Run.cpp:346
bool isGraphemeBreak() const
Definition Run.cpp:351
SkScalar sizeToChar(TextIndex ch) const
Definition Run.cpp:276
Run * runOrNull() const
Definition Run.cpp:329
size_t endPos() const
Definition Run.h:317
void space(SkScalar shift)
Definition Run.h:301
size_t size() const
Definition Run.h:320
void setHalfLetterSpacing(SkScalar halfLetterSpacing)
Definition Run.h:322
Run & run() const
Definition Run.cpp:336
SkScalar deltaBaselines() const
Definition Run.h:493
Run & run(RunIndex runIndex)
ClusterIndex clusterIndex(TextIndex textIndex)
bool codeUnitHasProperty(size_t index, SkUnicode::CodeUnitFlags property) const
TextIndex findNextGlyphClusterBoundary(TextIndex utf8) const
Cluster & cluster(ClusterIndex clusterIndex)
SkSpan< Placeholder > placeholders()
TextIndex findPreviousGlyphClusterBoundary(TextIndex utf8) const
TextIndex findPreviousGraphemeBoundary(TextIndex utf8) const
TextIndex findNextGraphemeBoundary(TextIndex utf8) const
void calculateMetrics()
Definition Run.cpp:61
size_t index() const
Definition Run.h:98
void updateMetrics(InternalLineMetrics *endlineMetrics)
Definition Run.cpp:220
void copyTo(SkTextBlobBuilder &builder, size_t pos, size_t size) const
Definition Run.cpp:88
ClusterRange clusterRange() const
Definition Run.h:109
bool isPlaceholder() const
Definition Run.h:103
SkShaper::RunHandler::Buffer newRunBuffer()
Definition Run.cpp:84
std::tuple< bool, TextIndex, TextIndex > findLimitingGlyphClusters(TextRange text) const
Definition Run.cpp:140
SkScalar positionX(size_t pos) const
Definition Run.cpp:308
void shift(SkScalar shiftX, SkScalar shiftY)
Definition Run.h:81
std::tuple< bool, TextIndex, TextIndex > findLimitingGraphemes(TextRange text) const
Definition Run.cpp:149
std::tuple< bool, ClusterIndex, ClusterIndex > findLimitingClusters(TextRange text) const
Definition Run.cpp:106
const SkFont & font() const
Definition Run.h:95
bool isResolved() const
Definition Run.cpp:320
SkVector offset() const
Definition Run.h:88
std::function< void(Cluster *cluster)> ClusterVisitor
Definition Run.h:143
Run(ParagraphImpl *owner, const SkShaper::RunHandler::RunInfo &info, size_t firstChar, SkScalar heightMultiplier, bool useHalfLeading, SkScalar baselineShift, size_t index, SkScalar shiftX)
Definition Run.cpp:17
void addSpacesAtTheEnd(SkScalar space, Cluster *cluster)
Definition Run.cpp:164
void extend(const Cluster *cluster, SkScalar offset)
Definition Run.cpp:215
void iterateThroughClusters(const ClusterVisitor &visitor)
Definition Run.cpp:155
PlaceholderStyle * placeholderStyle() const
Definition Run.cpp:312
SkScalar addSpacesEvenly(SkScalar space, Cluster *cluster)
Definition Run.cpp:182
size_t size() const
Definition Run.h:78
bool leftToRight() const
Definition Run.h:96
SkScalar posX(size_t index) const
Definition Run.h:75
T * push_back_n(int n)
Definition SkTArray.h:262
bool empty() const
Definition SkTArray.h:194
static const char * begin(const StringSlice &s)
Definition editor.cpp:252
float SkScalar
Definition extension.cpp:12
struct MyStruct s
glong glong end
std::u16string text
Definition run.py:1
const SkRange< size_t > EMPTY_CLUSTERS
Definition Run.h:38
@ kBaseline
Match the baseline of the placeholder with the baseline.
size_t ClusterIndex
Definition Run.h:35
Definition ref_ptr.h:256
SkScalar offsetX
int32_t height
Point offset
SkScalar fLeading
distance to add between lines, typically positive or zero
SkScalar fAscent
distance to reserve above baseline, typically negative
SkScalar fDescent
distance to reserve below baseline, typically positive
float fX
x-axis value
static constexpr SkPoint Make(float x, float y)
constexpr size_t end() const
Definition SkShaper.h:199
PlaceholderAlignment fAlignment
Definition TextStyle.h:138