Flutter Engine
The Flutter Engine
paragraph_builder.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/lib/ui/text/paragraph_builder.h"
6
7#include <cstring>
8
9#include "flutter/common/settings.h"
10#include "flutter/common/task_runners.h"
11#include "flutter/fml/logging.h"
12#include "flutter/fml/task_runner.h"
13#include "flutter/lib/ui/text/font_collection.h"
14#include "flutter/lib/ui/ui_dart_state.h"
15#include "flutter/lib/ui/window/platform_configuration.h"
16#include "flutter/third_party/txt/src/txt/font_style.h"
17#include "flutter/third_party/txt/src/txt/font_weight.h"
18#include "flutter/third_party/txt/src/txt/paragraph_style.h"
19#include "flutter/third_party/txt/src/txt/text_baseline.h"
20#include "flutter/third_party/txt/src/txt/text_decoration.h"
21#include "flutter/third_party/txt/src/txt/text_style.h"
22#include "third_party/icu/source/common/unicode/ustring.h"
29
30namespace flutter {
31namespace {
32
33const double kTextHeightNone = 0.0;
34
35// TextStyle
36
37const int kTSLeadingDistributionIndex = 0;
38const int kTSColorIndex = 1;
39const int kTSTextDecorationIndex = 2;
40const int kTSTextDecorationColorIndex = 3;
41const int kTSTextDecorationStyleIndex = 4;
42const int kTSFontWeightIndex = 5;
43const int kTSFontStyleIndex = 6;
44const int kTSTextBaselineIndex = 7;
45const int kTSTextDecorationThicknessIndex = 8;
46const int kTSFontFamilyIndex = 9;
47const int kTSFontSizeIndex = 10;
48const int kTSLetterSpacingIndex = 11;
49const int kTSWordSpacingIndex = 12;
50const int kTSHeightIndex = 13;
51const int kTSLocaleIndex = 14;
52const int kTSBackgroundIndex = 15;
53const int kTSForegroundIndex = 16;
54const int kTSTextShadowsIndex = 17;
55const int kTSFontFeaturesIndex = 18;
56const int kTSFontVariationsIndex = 19;
57
58const int kTSLeadingDistributionMask = 1 << kTSLeadingDistributionIndex;
59const int kTSColorMask = 1 << kTSColorIndex;
60const int kTSTextDecorationMask = 1 << kTSTextDecorationIndex;
61const int kTSTextDecorationColorMask = 1 << kTSTextDecorationColorIndex;
62const int kTSTextDecorationStyleMask = 1 << kTSTextDecorationStyleIndex;
63const int kTSTextDecorationThicknessMask = 1 << kTSTextDecorationThicknessIndex;
64const int kTSFontWeightMask = 1 << kTSFontWeightIndex;
65const int kTSFontStyleMask = 1 << kTSFontStyleIndex;
66const int kTSTextBaselineMask = 1 << kTSTextBaselineIndex;
67const int kTSFontFamilyMask = 1 << kTSFontFamilyIndex;
68const int kTSFontSizeMask = 1 << kTSFontSizeIndex;
69const int kTSLetterSpacingMask = 1 << kTSLetterSpacingIndex;
70const int kTSWordSpacingMask = 1 << kTSWordSpacingIndex;
71const int kTSHeightMask = 1 << kTSHeightIndex;
72const int kTSLocaleMask = 1 << kTSLocaleIndex;
73const int kTSBackgroundMask = 1 << kTSBackgroundIndex;
74const int kTSForegroundMask = 1 << kTSForegroundIndex;
75const int kTSTextShadowsMask = 1 << kTSTextShadowsIndex;
76const int kTSFontFeaturesMask = 1 << kTSFontFeaturesIndex;
77const int kTSFontVariationsMask = 1 << kTSFontVariationsIndex;
78
79// ParagraphStyle
80
81const int kPSTextAlignIndex = 1;
82const int kPSTextDirectionIndex = 2;
83const int kPSFontWeightIndex = 3;
84const int kPSFontStyleIndex = 4;
85const int kPSMaxLinesIndex = 5;
86const int kPSTextHeightBehaviorIndex = 6;
87const int kPSFontFamilyIndex = 7;
88const int kPSFontSizeIndex = 8;
89const int kPSHeightIndex = 9;
90const int kPSStrutStyleIndex = 10;
91const int kPSEllipsisIndex = 11;
92const int kPSLocaleIndex = 12;
93
94const int kPSTextAlignMask = 1 << kPSTextAlignIndex;
95const int kPSTextDirectionMask = 1 << kPSTextDirectionIndex;
96const int kPSFontWeightMask = 1 << kPSFontWeightIndex;
97const int kPSFontStyleMask = 1 << kPSFontStyleIndex;
98const int kPSMaxLinesMask = 1 << kPSMaxLinesIndex;
99const int kPSFontFamilyMask = 1 << kPSFontFamilyIndex;
100const int kPSFontSizeMask = 1 << kPSFontSizeIndex;
101const int kPSHeightMask = 1 << kPSHeightIndex;
102const int kPSTextHeightBehaviorMask = 1 << kPSTextHeightBehaviorIndex;
103const int kPSStrutStyleMask = 1 << kPSStrutStyleIndex;
104const int kPSEllipsisMask = 1 << kPSEllipsisIndex;
105const int kPSLocaleMask = 1 << kPSLocaleIndex;
106
107// TextShadows decoding
108
109constexpr uint32_t kColorDefault = 0xFF000000;
110constexpr uint32_t kBytesPerShadow = 16;
111constexpr uint32_t kShadowPropertiesCount = 4;
112constexpr uint32_t kColorOffset = 0;
113constexpr uint32_t kXOffset = 1;
114constexpr uint32_t kYOffset = 2;
115constexpr uint32_t kBlurOffset = 3;
116
117// FontFeature decoding
118constexpr uint32_t kBytesPerFontFeature = 8;
119constexpr uint32_t kFontFeatureTagLength = 4;
120
121// FontVariation decoding
122constexpr uint32_t kBytesPerFontVariation = 8;
123constexpr uint32_t kFontVariationTagLength = 4;
124
125// Strut decoding
126const int kSFontWeightIndex = 0;
127const int kSFontStyleIndex = 1;
128const int kSFontFamilyIndex = 2;
129const int kSLeadingDistributionIndex = 3;
130const int kSFontSizeIndex = 4;
131const int kSHeightIndex = 5;
132const int kSLeadingIndex = 6;
133const int kSForceStrutHeightIndex = 7;
134
135const int kSFontWeightMask = 1 << kSFontWeightIndex;
136const int kSFontStyleMask = 1 << kSFontStyleIndex;
137const int kSFontFamilyMask = 1 << kSFontFamilyIndex;
138const int kSLeadingDistributionMask = 1 << kSLeadingDistributionIndex;
139const int kSFontSizeMask = 1 << kSFontSizeIndex;
140const int kSHeightMask = 1 << kSHeightIndex;
141const int kSLeadingMask = 1 << kSLeadingIndex;
142const int kSForceStrutHeightMask = 1 << kSForceStrutHeightIndex;
143
144} // namespace
145
147
149 Dart_Handle encoded_handle,
150 Dart_Handle strutData,
151 const std::string& fontFamily,
152 const std::vector<std::string>& strutFontFamilies,
153 double fontSize,
154 double height,
155 const std::u16string& ellipsis,
156 const std::string& locale) {
158 auto res = fml::MakeRefCounted<ParagraphBuilder>(
159 encoded_handle, strutData, fontFamily, strutFontFamilies, fontSize,
160 height, ellipsis, locale);
161 res->AssociateWithDartWrapper(wrapper);
162}
163
164// returns true if there is a font family defined. Font family is the only
165// parameter passed directly.
166void decodeStrut(Dart_Handle strut_data,
167 const std::vector<std::string>& strut_font_families,
168 txt::ParagraphStyle& paragraph_style) { // NOLINT
169 if (strut_data == Dart_Null()) {
170 return;
171 }
172
173 tonic::DartByteData byte_data(strut_data);
174 if (byte_data.length_in_bytes() == 0) {
175 return;
176 }
177 paragraph_style.strut_enabled = true;
178
179 const uint8_t* uint8_data = static_cast<const uint8_t*>(byte_data.data());
180 uint8_t mask = uint8_data[0];
181
182 // Data is stored in order of increasing size, eg, 8 bit ints will be before
183 // any 32 bit ints. In addition, the order of decoding is the same order
184 // as it is encoded, and the order is used to maintain consistency.
185 size_t byte_count = 1;
186 if (mask & kSFontWeightMask) {
187 paragraph_style.strut_font_weight =
188 static_cast<txt::FontWeight>(uint8_data[byte_count++]);
189 }
190 if (mask & kSFontStyleMask) {
191 paragraph_style.strut_font_style =
192 static_cast<txt::FontStyle>(uint8_data[byte_count++]);
193 }
194
195 paragraph_style.strut_half_leading = mask & kSLeadingDistributionMask;
196
197 std::vector<float> float_data;
198 float_data.resize((byte_data.length_in_bytes() - byte_count) / 4);
199 memcpy(float_data.data(),
200 static_cast<const char*>(byte_data.data()) + byte_count,
201 byte_data.length_in_bytes() - byte_count);
202 size_t float_count = 0;
203 if (mask & kSFontSizeMask) {
204 paragraph_style.strut_font_size = float_data[float_count++];
205 }
206 if (mask & kSHeightMask) {
207 paragraph_style.strut_height = float_data[float_count++];
208 paragraph_style.strut_has_height_override = true;
209 }
210 if (mask & kSLeadingMask) {
211 paragraph_style.strut_leading = float_data[float_count++];
212 }
213
214 // The boolean is stored as the last bit in the bitmask, as null
215 // and false have the same behavior.
216 paragraph_style.force_strut_height = mask & kSForceStrutHeightMask;
217
218 if (mask & kSFontFamilyMask) {
219 paragraph_style.strut_font_families = strut_font_families;
220 } else {
221 // Provide an empty font name so that the platform default font will be
222 // used.
223 paragraph_style.strut_font_families.push_back("");
224 }
225}
226
227ParagraphBuilder::ParagraphBuilder(
228 Dart_Handle encoded_data,
229 Dart_Handle strutData,
230 const std::string& fontFamily,
231 const std::vector<std::string>& strutFontFamilies,
232 double fontSize,
233 double height,
234 const std::u16string& ellipsis,
235 const std::string& locale) {
236 int32_t mask = 0;
238 {
239 tonic::Int32List encoded(encoded_data);
240
241 mask = encoded[0];
242
243 if (mask & kPSTextAlignMask) {
244 style.text_align =
245 static_cast<txt::TextAlign>(encoded[kPSTextAlignIndex]);
246 }
247
248 if (mask & kPSTextDirectionMask) {
249 style.text_direction =
250 static_cast<txt::TextDirection>(encoded[kPSTextDirectionIndex]);
251 }
252
253 if (mask & kPSFontWeightMask) {
254 style.font_weight =
255 static_cast<txt::FontWeight>(encoded[kPSFontWeightIndex]);
256 }
257
258 if (mask & kPSFontStyleMask) {
259 style.font_style =
260 static_cast<txt::FontStyle>(encoded[kPSFontStyleIndex]);
261 }
262
263 if (mask & kPSFontFamilyMask) {
264 style.font_family = fontFamily;
265 }
266
267 if (mask & kPSFontSizeMask) {
268 style.font_size = fontSize;
269 }
270
271 if (mask & kPSHeightMask) {
272 style.height = height;
273 style.has_height_override = true;
274 }
275
276 if (mask & kPSTextHeightBehaviorMask) {
277 style.text_height_behavior = encoded[kPSTextHeightBehaviorIndex];
278 }
279
280 if (mask & kPSMaxLinesMask) {
281 style.max_lines = encoded[kPSMaxLinesIndex];
282 }
283 }
284
285 if (mask & kPSStrutStyleMask) {
286 decodeStrut(strutData, strutFontFamilies, style);
287 }
288
289 if (mask & kPSEllipsisMask) {
290 style.ellipsis = ellipsis;
291 }
292
293 if (mask & kPSLocaleMask) {
294 style.locale = locale;
295 }
296
297 FontCollection& font_collection = UIDartState::Current()
299 ->client()
301
302 auto impeller_enabled = UIDartState::Current()->IsImpellerEnabled();
303 m_paragraph_builder_ = txt::ParagraphBuilder::CreateSkiaBuilder(
304 style, font_collection.GetFontCollection(), impeller_enabled);
305}
306
308
310 Dart_Handle shadows_data,
311 std::vector<txt::TextShadow>& decoded_shadows) { // NOLINT
312 decoded_shadows.clear();
313
314 tonic::DartByteData byte_data(shadows_data);
315 FML_CHECK(byte_data.length_in_bytes() % kBytesPerShadow == 0);
316
317 const uint32_t* uint_data = static_cast<const uint32_t*>(byte_data.data());
318 const float* float_data = static_cast<const float*>(byte_data.data());
319
320 size_t shadow_count = byte_data.length_in_bytes() / kBytesPerShadow;
321 size_t shadow_count_offset = 0;
322 for (size_t shadow_index = 0; shadow_index < shadow_count; ++shadow_index) {
323 shadow_count_offset = shadow_index * kShadowPropertiesCount;
324 SkColor color =
325 uint_data[shadow_count_offset + kColorOffset] ^ kColorDefault;
326 decoded_shadows.emplace_back(
327 color,
328 SkPoint::Make(float_data[shadow_count_offset + kXOffset],
329 float_data[shadow_count_offset + kYOffset]),
330 float_data[shadow_count_offset + kBlurOffset]);
331 }
332}
333
334void decodeFontFeatures(Dart_Handle font_features_data,
335 txt::FontFeatures& font_features) { // NOLINT
336 tonic::DartByteData byte_data(font_features_data);
337 FML_CHECK(byte_data.length_in_bytes() % kBytesPerFontFeature == 0);
338
339 size_t feature_count = byte_data.length_in_bytes() / kBytesPerFontFeature;
340 for (size_t feature_index = 0; feature_index < feature_count;
341 ++feature_index) {
342 size_t feature_offset = feature_index * kBytesPerFontFeature;
343 const char* feature_bytes =
344 static_cast<const char*>(byte_data.data()) + feature_offset;
345 std::string tag(feature_bytes, kFontFeatureTagLength);
346 int32_t value = *(reinterpret_cast<const int32_t*>(feature_bytes +
347 kFontFeatureTagLength));
348 font_features.SetFeature(tag, value);
349 }
350}
351
352void decodeFontVariations(Dart_Handle font_variations_data,
353 txt::FontVariations& font_variations) { // NOLINT
354 tonic::DartByteData byte_data(font_variations_data);
355 FML_CHECK(byte_data.length_in_bytes() % kBytesPerFontVariation == 0);
356
357 size_t variation_count = byte_data.length_in_bytes() / kBytesPerFontVariation;
358 for (size_t variation_index = 0; variation_index < variation_count;
359 ++variation_index) {
360 size_t variation_offset = variation_index * kBytesPerFontVariation;
361 const char* variation_bytes =
362 static_cast<const char*>(byte_data.data()) + variation_offset;
363 std::string tag(variation_bytes, kFontVariationTagLength);
364 float value = *(reinterpret_cast<const float*>(variation_bytes +
365 kFontVariationTagLength));
366 font_variations.SetAxisValue(tag, value);
367 }
368}
369
370void ParagraphBuilder::pushStyle(const tonic::Int32List& encoded,
371 const std::vector<std::string>& fontFamilies,
372 double fontSize,
373 double letterSpacing,
374 double wordSpacing,
375 double height,
376 double decorationThickness,
377 const std::string& locale,
378 Dart_Handle background_objects,
379 Dart_Handle background_data,
380 Dart_Handle foreground_objects,
381 Dart_Handle foreground_data,
382 Dart_Handle shadows_data,
383 Dart_Handle font_features_data,
384 Dart_Handle font_variations_data) {
385 FML_DCHECK(encoded.num_elements() == 9);
386
387 int32_t mask = encoded[0];
388
389 // Set to use the properties of the previous style if the property is not
390 // explicitly given.
391 txt::TextStyle style = m_paragraph_builder_->PeekStyle();
392
393 style.half_leading = mask & kTSLeadingDistributionMask;
394 // Only change the style property from the previous value if a new explicitly
395 // set value is available
396 if (mask & kTSColorMask) {
397 style.color = encoded[kTSColorIndex];
398 }
399
400 if (mask & kTSTextDecorationMask) {
401 style.decoration =
402 static_cast<txt::TextDecoration>(encoded[kTSTextDecorationIndex]);
403 }
404
405 if (mask & kTSTextDecorationColorMask) {
406 style.decoration_color = encoded[kTSTextDecorationColorIndex];
407 }
408
409 if (mask & kTSTextDecorationStyleMask) {
410 style.decoration_style = static_cast<txt::TextDecorationStyle>(
411 encoded[kTSTextDecorationStyleIndex]);
412 }
413
414 if (mask & kTSTextDecorationThicknessMask) {
415 style.decoration_thickness_multiplier = decorationThickness;
416 }
417
418 if (mask & kTSTextBaselineMask) {
419 // TODO(abarth): Implement TextBaseline. The CSS version of this
420 // property wasn't wired up either.
421 }
422
423 if (mask & (kTSFontWeightMask | kTSFontStyleMask | kTSFontSizeMask |
424 kTSLetterSpacingMask | kTSWordSpacingMask)) {
425 if (mask & kTSFontWeightMask) {
426 style.font_weight =
427 static_cast<txt::FontWeight>(encoded[kTSFontWeightIndex]);
428 }
429
430 if (mask & kTSFontStyleMask) {
431 style.font_style =
432 static_cast<txt::FontStyle>(encoded[kTSFontStyleIndex]);
433 }
434
435 if (mask & kTSFontSizeMask) {
436 style.font_size = fontSize;
437 }
438
439 if (mask & kTSLetterSpacingMask) {
440 style.letter_spacing = letterSpacing;
441 }
442
443 if (mask & kTSWordSpacingMask) {
444 style.word_spacing = wordSpacing;
445 }
446 }
447
448 if (mask & kTSHeightMask) {
449 style.height = height;
451 }
452
453 if (mask & kTSLocaleMask) {
454 style.locale = locale;
455 }
456
457 if (mask & kTSBackgroundMask) {
458 Paint background(background_objects, background_data);
459 if (background.isNotNull()) {
460 DlPaint dl_paint;
461 background.toDlPaint(dl_paint);
462 style.background = dl_paint;
463 }
464 }
465
466 if (mask & kTSForegroundMask) {
467 Paint foreground(foreground_objects, foreground_data);
468 if (foreground.isNotNull()) {
469 DlPaint dl_paint;
470 foreground.toDlPaint(dl_paint);
471 style.foreground = dl_paint;
472 }
473 }
474
475 if (mask & kTSTextShadowsMask) {
476 decodeTextShadows(shadows_data, style.text_shadows);
477 }
478
479 if (mask & kTSFontFamilyMask) {
480 // The child style's font families override the parent's font families.
481 // If the child's fonts are not available, then the font collection will
482 // use the system fallback fonts (not the parent's fonts).
483 style.font_families = fontFamilies;
484 }
485
486 if (mask & kTSFontFeaturesMask) {
487 decodeFontFeatures(font_features_data, style.font_features);
488 }
489
490 if (mask & kTSFontVariationsMask) {
491 decodeFontVariations(font_variations_data, style.font_variations);
492 }
493
494 m_paragraph_builder_->PushStyle(style);
495}
496
498 m_paragraph_builder_->Pop();
499}
500
502 if (text.empty()) {
503 return Dart_Null();
504 }
505
506 // Use ICU to validate the UTF-16 input. Calling u_strToUTF8 with a null
507 // output buffer will return U_BUFFER_OVERFLOW_ERROR if the input is well
508 // formed.
509 const UChar* text_ptr = reinterpret_cast<const UChar*>(text.data());
510 UErrorCode error_code = U_ZERO_ERROR;
511 u_strToUTF8(nullptr, 0, nullptr, text_ptr, text.size(), &error_code);
512 if (error_code != U_BUFFER_OVERFLOW_ERROR) {
513 return tonic::ToDart("string is not well-formed UTF-16");
514 }
515
516 m_paragraph_builder_->AddText(text);
517
518 return Dart_Null();
519}
520
522 double height,
523 unsigned alignment,
524 double baseline_offset,
525 unsigned baseline) {
526 txt::PlaceholderRun placeholder_run(
527 width, height, static_cast<txt::PlaceholderAlignment>(alignment),
528 static_cast<txt::TextBaseline>(baseline), baseline_offset);
529
530 m_paragraph_builder_->AddPlaceholder(placeholder_run);
531}
532
533void ParagraphBuilder::build(Dart_Handle paragraph_handle) {
534 Paragraph::Create(paragraph_handle, m_paragraph_builder_->Build());
535 m_paragraph_builder_.reset();
537}
538
539} // namespace flutter
uint32_t SkColor
Definition: SkColor.h:37
void toDlPaint(DlPaint &paint) const
Definition: paint.cc:191
bool isNotNull() const
Definition: paint.h:26
static void Create(Dart_Handle wrapper, Dart_Handle encoded_handle, Dart_Handle strutData, const std::string &fontFamily, const std::vector< std::string > &strutFontFamilies, double fontSize, double height, const std::u16string &ellipsis, const std::string &locale)
void build(Dart_Handle paragraph_handle)
void pushStyle(const tonic::Int32List &encoded, const std::vector< std::string > &fontFamilies, double fontSize, double letterSpacing, double wordSpacing, double height, double decorationThickness, const std::string &locale, Dart_Handle background_objects, Dart_Handle background_data, Dart_Handle foreground_objects, Dart_Handle foreground_data, Dart_Handle shadows_data, Dart_Handle font_features_data, Dart_Handle font_variations_data)
void addPlaceholder(double width, double height, unsigned alignment, double baseline_offset, unsigned baseline)
Dart_Handle addText(const std::u16string &text)
static void Create(Dart_Handle paragraph_handle, std::unique_ptr< txt::Paragraph > txt_paragraph)
Definition: paragraph.h:20
virtual FontCollection & GetFontCollection()=0
Returns the current collection of fonts available on the platform.
PlatformConfigurationClient * client() const
Access to the platform configuration client (which typically is implemented by the RuntimeController)...
PlatformConfiguration * platform_configuration() const
bool IsImpellerEnabled() const
Whether Impeller is enabled for this application.
static UIDartState * Current()
static void ThrowIfUIOperationsProhibited()
const void * data() const
size_t length_in_bytes() const
void SetFeature(std::string tag, int value)
void SetAxisValue(std::string tag, float value)
static std::unique_ptr< ParagraphBuilder > CreateSkiaBuilder(const ParagraphStyle &style, std::shared_ptr< FontCollection > font_collection, const bool impeller_enabled)
Creates a |ParagraphBuilder| based on Skia's text layout module.
std::string font_family
std::u16string ellipsis
TextDirection text_direction
FontWeight strut_font_weight
FontStyle strut_font_style
std::vector< std::string > strut_font_families
std::vector< std::string > font_families
Definition: text_style.h:52
std::optional< flutter::DlPaint > foreground
Definition: text_style.h:60
TextDecorationStyle decoration_style
Definition: text_style.h:43
double height
Definition: text_style.h:56
FontStyle font_style
Definition: text_style.h:47
SkColor decoration_color
Definition: text_style.h:42
double word_spacing
Definition: text_style.h:55
FontFeatures font_features
Definition: text_style.h:64
FontVariations font_variations
Definition: text_style.h:65
bool has_height_override
Definition: text_style.h:57
bool half_leading
Definition: text_style.h:49
std::vector< TextShadow > text_shadows
Definition: text_style.h:63
double font_size
Definition: text_style.h:53
std::string locale
Definition: text_style.h:58
SkColor color
Definition: text_style.h:38
double decoration_thickness_multiplier
Definition: text_style.h:45
FontWeight font_weight
Definition: text_style.h:46
std::optional< flutter::DlPaint > background
Definition: text_style.h:59
double letter_spacing
Definition: text_style.h:54
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
DART_EXPORT Dart_Handle Dart_Null(void)
DlColor color
uint8_t value
#define FML_CHECK(condition)
Definition: logging.h:85
#define FML_DCHECK(condition)
Definition: logging.h:103
std::u16string text
IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, FlutterGpuTestClass)
constexpr uint32_t kColorDefault
Definition: paint.cc:48
void decodeStrut(Dart_Handle strut_data, const std::vector< std::string > &strut_font_families, txt::ParagraphStyle &paragraph_style)
void decodeFontVariations(Dart_Handle font_variations_data, txt::FontVariations &font_variations)
void decodeTextShadows(Dart_Handle shadows_data, std::vector< txt::TextShadow > &decoded_shadows)
void decodeFontFeatures(Dart_Handle font_features_data, txt::FontFeatures &font_features)
Dart_Handle ToDart(const T &object)
PlaceholderAlignment
Where to vertically align the placeholder relative to the surrounding text.
TextDecoration
FontWeight
Definition: font_weight.h:22
FontStyle
Definition: font_style.h:22
TextDecorationStyle
TextBaseline
Definition: text_baseline.h:22
int32_t height
int32_t width
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
const double kTextHeightNone
Definition: text_style.cpp:9