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// Synced 2019-05-30T14:20:57.833907. 5 6part of ui; 7 8/// Whether to slant the glyphs in the font 9enum FontStyle { 10 /// Use the upright glyphs 11 normal, 12 13 /// Use glyphs designed for slanting 14 italic, 15} 16 17/// Where to vertically align the placeholder relative to the surrounding text. 18/// 19/// Used by [ParagraphBuilder.addPlaceholder]. 20enum PlaceholderAlignment { 21 /// Match the baseline of the placeholder with the baseline. 22 /// 23 /// The [TextBaseline] to use must be specified and non-null when using this 24 /// alignment mode. 25 baseline, 26 27 /// Align the bottom edge of the placeholder with the baseline such that the 28 /// placeholder sits on top of the baseline. 29 /// 30 /// The [TextBaseline] to use must be specified and non-null when using this 31 /// alignment mode. 32 aboveBaseline, 33 34 /// Align the top edge of the placeholder with the baseline specified 35 /// such that the placeholder hangs below the baseline. 36 /// 37 /// The [TextBaseline] to use must be specified and non-null when using this 38 /// alignment mode. 39 belowBaseline, 40 41 /// Align the top edge of the placeholder with the top edge of the font. 42 /// 43 /// When the placeholder is very tall, the extra space will hang from 44 /// the top and extend through the bottom of the line. 45 top, 46 47 /// Align the bottom edge of the placeholder with the top edge of the font. 48 /// 49 /// When the placeholder is very tall, the extra space will rise from the 50 /// bottom and extend through the top of the line. 51 bottom, 52 53 /// Align the middle of the placeholder with the middle of the text. 54 /// 55 /// When the placeholder is very tall, the extra space will grow equally 56 /// from the top and bottom of the line. 57 middle, 58} 59 60/// The thickness of the glyphs used to draw the text 61class FontWeight { 62 const FontWeight._(this.index); 63 64 /// The encoded integer value of this font weight. 65 final int index; 66 67 /// Thin, the least thick 68 static const FontWeight w100 = FontWeight._(0); 69 70 /// Extra-light 71 static const FontWeight w200 = FontWeight._(1); 72 73 /// Light 74 static const FontWeight w300 = FontWeight._(2); 75 76 /// Normal / regular / plain 77 static const FontWeight w400 = FontWeight._(3); 78 79 /// Medium 80 static const FontWeight w500 = FontWeight._(4); 81 82 /// Semi-bold 83 static const FontWeight w600 = FontWeight._(5); 84 85 /// Bold 86 static const FontWeight w700 = FontWeight._(6); 87 88 /// Extra-bold 89 static const FontWeight w800 = FontWeight._(7); 90 91 /// Black, the most thick 92 static const FontWeight w900 = FontWeight._(8); 93 94 /// The default font weight. 95 static const FontWeight normal = w400; 96 97 /// A commonly used font weight that is heavier than normal. 98 static const FontWeight bold = w700; 99 100 /// A list of all the font weights. 101 static const List<FontWeight> values = <FontWeight>[ 102 w100, 103 w200, 104 w300, 105 w400, 106 w500, 107 w600, 108 w700, 109 w800, 110 w900 111 ]; 112 113 /// Linearly interpolates between two font weights. 114 /// 115 /// Rather than using fractional weights, the interpolation rounds to the 116 /// nearest weight. 117 /// 118 /// Any null values for `a` or `b` are interpreted as equivalent to [normal] 119 /// (also known as [w400]). 120 /// 121 /// The `t` argument represents position on the timeline, with 0.0 meaning 122 /// that the interpolation has not started, returning `a` (or something 123 /// equivalent to `a`), 1.0 meaning that the interpolation has finished, 124 /// returning `b` (or something equivalent to `b`), and values in between 125 /// meaning that the interpolation is at the relevant point on the timeline 126 /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and 127 /// 1.0, so negative values and values greater than 1.0 are valid (and can 128 /// easily be generated by curves such as [Curves.elasticInOut]). The result 129 /// is clamped to the range [w100]–[w900]. 130 /// 131 /// Values for `t` are usually obtained from an [Animation<double>], such as 132 /// an [AnimationController]. 133 static FontWeight lerp(FontWeight a, FontWeight b, double t) { 134 assert(t != null); 135 return values[ 136 lerpDouble(a?.index ?? normal.index, b?.index ?? normal.index, t) 137 .round() 138 .clamp(0, 8)]; 139 } 140 141 @override 142 String toString() { 143 return const <int, String>{ 144 0: 'FontWeight.w100', 145 1: 'FontWeight.w200', 146 2: 'FontWeight.w300', 147 3: 'FontWeight.w400', 148 4: 'FontWeight.w500', 149 5: 'FontWeight.w600', 150 6: 'FontWeight.w700', 151 7: 'FontWeight.w800', 152 8: 'FontWeight.w900', 153 }[index]; 154 } 155} 156 157/// A feature tag and value that affect the selection of glyphs in a font. 158class FontFeature { 159 /// Creates a [FontFeature] object, which can be added to a [TextStyle] to 160 /// change how the engine selects glyphs when rendering text. 161 /// 162 /// `feature` is the four-character tag that identifies the feature. 163 /// These tags are specified by font formats such as OpenType. 164 /// 165 /// `value` is the value that the feature will be set to. The behavior 166 /// of the value depends on the specific feature. Many features are 167 /// flags whose value can be 1 (when enabled) or 0 (when disabled). 168 /// 169 /// See <https://docs.microsoft.com/en-us/typography/opentype/spec/featuretags> 170 const FontFeature(this.feature, [this.value = 1]) 171 : assert(feature != null), 172 assert(feature.length == 4), 173 assert(value != null), 174 assert(value >= 0); 175 176 /// Create a [FontFeature] object that enables the feature with the given tag. 177 const FontFeature.enable(String feature) : this(feature, 1); 178 179 /// Create a [FontFeature] object that disables the feature with the given tag. 180 const FontFeature.disable(String feature) : this(feature, 0); 181 182 /// Randomize the alternate forms used in text. 183 /// 184 /// For example, this can be used with suitably-prepared handwriting fonts to 185 /// vary the forms used for each character, so that, for instance, the word 186 /// "cross-section" would be rendered with two different "c"s, two different "o"s, 187 /// and three different "s"s. 188 /// 189 /// See also: 190 /// 191 /// * <https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#rand> 192 const FontFeature.randomize() 193 : feature = 'rand', 194 value = 1; 195 196 /// Select a stylistic set. 197 /// 198 /// Fonts may have up to 20 stylistic sets, numbered 1 through 20. 199 /// 200 /// See also: 201 /// 202 /// * <https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx> 203 factory FontFeature.stylisticSet(int value) { 204 assert(value >= 1); 205 assert(value <= 20); 206 return FontFeature('ss${value.toString().padLeft(2, "0")}'); 207 } 208 209 /// Use the slashed zero. 210 /// 211 /// Some fonts contain both a circular zero and a zero with a slash. This 212 /// enables the use of the latter form. 213 /// 214 /// This is overridden by [FontFeature.oldstyleFigures]. 215 /// 216 /// See also: 217 /// 218 /// * <https://docs.microsoft.com/en-us/typography/opentype/spec/features_uz#zero> 219 const FontFeature.slashedZero() 220 : feature = 'zero', 221 value = 1; 222 223 /// Use oldstyle figures. 224 /// 225 /// Some fonts have variants of the figures (e.g. the digit 9) that, when 226 /// this feature is enabled, render with descenders under the baseline instead 227 /// of being entirely above the baseline. 228 /// 229 /// This overrides [FontFeature.slashedZero]. 230 /// 231 /// See also: 232 /// 233 /// * <https://docs.microsoft.com/en-us/typography/opentype/spec/features_ko#onum> 234 const FontFeature.oldstyleFigures() 235 : feature = 'onum', 236 value = 1; 237 238 /// Use proportional (varying width) figures. 239 /// 240 /// For fonts that have both proportional and tabular (monospace) figures, 241 /// this enables the proportional figures. 242 /// 243 /// This is mutually exclusive with [FontFeature.tabularFigures]. 244 /// 245 /// The default behavior varies from font to font. 246 /// 247 /// See also: 248 /// 249 /// * <https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#pnum> 250 const FontFeature.proportionalFigures() 251 : feature = 'pnum', 252 value = 1; 253 254 /// Use tabular (monospace) figures. 255 /// 256 /// For fonts that have both proportional (varying width) and tabular figures, 257 /// this enables the tabular figures. 258 /// 259 /// This is mutually exclusive with [FontFeature.proportionalFigures]. 260 /// 261 /// The default behavior varies from font to font. 262 /// 263 /// See also: 264 /// 265 /// * <https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tnum> 266 const FontFeature.tabularFigures() 267 : feature = 'tnum', 268 value = 1; 269 270 /// The tag that identifies the effect of this feature. Must consist of 4 271 /// ASCII characters (typically lowercase letters). 272 /// 273 /// See <https://docs.microsoft.com/en-us/typography/opentype/spec/featuretags> 274 final String feature; 275 276 /// The value assigned to this feature. 277 /// 278 /// Must be a positive integer. Many features are Boolean values that accept 279 /// values of either 0 (feature is disabled) or 1 (feature is enabled). 280 final int value; 281 282 @override 283 bool operator ==(dynamic other) { 284 if (identical(this, other)) { 285 return true; 286 } 287 if (other.runtimeType != runtimeType) { 288 return false; 289 } 290 final FontFeature typedOther = other; 291 return feature == typedOther.feature && value == typedOther.value; 292 } 293 294 @override 295 int get hashCode => hashValues(feature, value); 296 297 @override 298 String toString() => 'FontFeature($feature, $value)'; 299} 300 301/// Whether and how to align text horizontally. 302// The order of this enum must match the order of the values in RenderStyleConstants.h's ETextAlign. 303enum TextAlign { 304 /// Align the text on the left edge of the container. 305 left, 306 307 /// Align the text on the right edge of the container. 308 right, 309 310 /// Align the text in the center of the container. 311 center, 312 313 /// Stretch lines of text that end with a soft line break to fill the width of 314 /// the container. 315 /// 316 /// Lines that end with hard line breaks are aligned towards the [start] edge. 317 justify, 318 319 /// Align the text on the leading edge of the container. 320 /// 321 /// For left-to-right text ([TextDirection.ltr]), this is the left edge. 322 /// 323 /// For right-to-left text ([TextDirection.rtl]), this is the right edge. 324 start, 325 326 /// Align the text on the trailing edge of the container. 327 /// 328 /// For left-to-right text ([TextDirection.ltr]), this is the right edge. 329 /// 330 /// For right-to-left text ([TextDirection.rtl]), this is the left edge. 331 end, 332} 333 334/// A horizontal line used for aligning text. 335enum TextBaseline { 336 /// The horizontal line used to align the bottom of glyphs for alphabetic characters. 337 alphabetic, 338 339 /// The horizontal line used to align ideographic characters. 340 ideographic, 341} 342 343/// A linear decoration to draw near the text. 344class TextDecoration { 345 const TextDecoration._(this._mask); 346 347 /// Creates a decoration that paints the union of all the given decorations. 348 factory TextDecoration.combine(List<TextDecoration> decorations) { 349 int mask = 0; 350 for (TextDecoration decoration in decorations) { 351 mask |= decoration._mask; 352 } 353 return TextDecoration._(mask); 354 } 355 356 final int _mask; 357 358 /// Whether this decoration will paint at least as much decoration as the given decoration. 359 bool contains(TextDecoration other) { 360 return (_mask | other._mask) == _mask; 361 } 362 363 /// Do not draw a decoration 364 static const TextDecoration none = TextDecoration._(0x0); 365 366 /// Draw a line underneath each line of text 367 static const TextDecoration underline = TextDecoration._(0x1); 368 369 /// Draw a line above each line of text 370 static const TextDecoration overline = TextDecoration._(0x2); 371 372 /// Draw a line through each line of text 373 static const TextDecoration lineThrough = TextDecoration._(0x4); 374 375 @override 376 bool operator ==(dynamic other) { 377 if (other is! TextDecoration) { 378 return false; 379 } 380 final TextDecoration typedOther = other; 381 return _mask == typedOther._mask; 382 } 383 384 @override 385 int get hashCode => _mask.hashCode; 386 387 @override 388 String toString() { 389 if (_mask == 0) { 390 return 'TextDecoration.none'; 391 } 392 final List<String> values = <String>[]; 393 if (_mask & underline._mask != 0) { 394 values.add('underline'); 395 } 396 if (_mask & overline._mask != 0) { 397 values.add('overline'); 398 } 399 if (_mask & lineThrough._mask != 0) { 400 values.add('lineThrough'); 401 } 402 if (values.length == 1) { 403 return 'TextDecoration.${values[0]}'; 404 } 405 return 'TextDecoration.combine([${values.join(", ")}])'; 406 } 407} 408 409/// The style in which to draw a text decoration 410enum TextDecorationStyle { 411 /// Draw a solid line 412 solid, 413 414 /// Draw two lines 415 double, 416 417 /// Draw a dotted line 418 dotted, 419 420 /// Draw a dashed line 421 dashed, 422 423 /// Draw a sinusoidal line 424 wavy 425} 426 427/// An opaque object that determines the size, position, and rendering of text. 428abstract class TextStyle { 429 /// Creates a new TextStyle object. 430 /// 431 /// * `color`: The color to use when painting the text. If this is specified, `foreground` must be null. 432 /// * `decoration`: The decorations to paint near the text (e.g., an underline). 433 /// * `decorationColor`: The color in which to paint the text decorations. 434 /// * `decorationStyle`: The style in which to paint the text decorations (e.g., dashed). 435 /// * `fontWeight`: The typeface thickness to use when painting the text (e.g., bold). 436 /// * `fontStyle`: The typeface variant to use when drawing the letters (e.g., italics). 437 /// * `fontFamily`: The name of the font to use when painting the text (e.g., Roboto). If a `fontFamilyFallback` is 438 /// provided and `fontFamily` is not, then the first font family in `fontFamilyFallback` will take the postion of 439 /// the preferred font family. When a higher priority font cannot be found or does not contain a glyph, a lower 440 /// priority font will be used. 441 /// * `fontFamilyFallback`: An ordered list of the names of the fonts to fallback on when a glyph cannot 442 /// be found in a higher priority font. When the `fontFamily` is null, the first font family in this list 443 /// is used as the preferred font. Internally, the 'fontFamily` is concatenated to the front of this list. 444 /// When no font family is provided through 'fontFamilyFallback' (null or empty) or `fontFamily`, then the 445 /// platform default font will be used. 446 /// * `fontSize`: The size of glyphs (in logical pixels) to use when painting the text. 447 /// * `letterSpacing`: The amount of space (in logical pixels) to add between each letter. 448 /// * `wordSpacing`: The amount of space (in logical pixels) to add at each sequence of white-space (i.e. between each word). 449 /// * `textBaseline`: The common baseline that should be aligned between this text span and its parent text span, or, for the root text spans, with the line box. 450 /// * `height`: The height of this text span, as a multiple of the font size. 451 /// * `locale`: The locale used to select region-specific glyphs. 452 /// * `background`: The paint drawn as a background for the text. 453 /// * `foreground`: The paint used to draw the text. If this is specified, `color` must be null. 454 factory TextStyle({ 455 Color color, 456 TextDecoration decoration, 457 Color decorationColor, 458 TextDecorationStyle decorationStyle, 459 double decorationThickness, 460 FontWeight fontWeight, 461 FontStyle fontStyle, 462 TextBaseline textBaseline, 463 String fontFamily, 464 List<String> fontFamilyFallback, 465 double fontSize, 466 double letterSpacing, 467 double wordSpacing, 468 double height, 469 Locale locale, 470 Paint background, 471 Paint foreground, 472 List<Shadow> shadows, 473 List<FontFeature> fontFeatures, 474 }) = engine.EngineTextStyle; 475 476 int get hashCode; 477 478 bool operator ==(dynamic other); 479 480 String toString(); 481} 482 483/// An opaque object that determines the configuration used by 484/// [ParagraphBuilder] to position lines within a [Paragraph] of text. 485abstract class ParagraphStyle { 486 /// Creates a new ParagraphStyle object. 487 /// 488 /// * `textAlign`: The alignment of the text within the lines of the 489 /// paragraph. If the last line is ellipsized (see `ellipsis` below), the 490 /// alignment is applied to that line after it has been truncated but before 491 /// the ellipsis has been added. 492 // See: https://github.com/flutter/flutter/issues/9819 493 /// 494 /// * `textDirection`: The directionality of the text, left-to-right (e.g. 495 /// Norwegian) or right-to-left (e.g. Hebrew). This controls the overall 496 /// directionality of the paragraph, as well as the meaning of 497 /// [TextAlign.start] and [TextAlign.end] in the `textAlign` field. 498 /// 499 /// * `maxLines`: The maximum number of lines painted. Lines beyond this 500 /// number are silently dropped. For example, if `maxLines` is 1, then only 501 /// one line is rendered. If `maxLines` is null, but `ellipsis` is not null, 502 /// then lines after the first one that overflows the width constraints are 503 /// dropped. The width constraints are those set in the 504 /// [ParagraphConstraints] object passed to the [Paragraph.layout] method. 505 /// 506 /// * `fontFamily`: The name of the font to use when painting the text (e.g., 507 /// Roboto). 508 /// 509 /// * `fontSize`: The size of glyphs (in logical pixels) to use when painting 510 /// the text. 511 /// 512 /// * `height`: The minimum height of the line boxes, as a multiple of the 513 /// font size. The lines of the paragraph will be at least 514 /// `(height + leading) * fontSize` tall when fontSize 515 /// is not null. When fontSize is null, there is no minimum line height. Tall 516 /// glyphs due to baseline alignment or large [TextStyle.fontSize] may cause 517 /// the actual line height after layout to be taller than specified here. 518 /// [fontSize] must be provided for this property to take effect. 519 /// 520 /// * `fontWeight`: The typeface thickness to use when painting the text 521 /// (e.g., bold). 522 /// 523 /// * `fontStyle`: The typeface variant to use when drawing the letters (e.g., 524 /// italics). 525 /// 526 /// * `strutStyle`: The properties of the strut. Strut defines a set of minimum 527 /// vertical line height related metrics and can be used to obtain more 528 /// advanced line spacing behavior. 529 /// 530 /// * `ellipsis`: String used to ellipsize overflowing text. If `maxLines` is 531 /// not null, then the `ellipsis`, if any, is applied to the last rendered 532 /// line, if that line overflows the width constraints. If `maxLines` is 533 /// null, then the `ellipsis` is applied to the first line that overflows 534 /// the width constraints, and subsequent lines are dropped. The width 535 /// constraints are those set in the [ParagraphConstraints] object passed to 536 /// the [Paragraph.layout] method. The empty string and the null value are 537 /// considered equivalent and turn off this behavior. 538 /// 539 /// * `locale`: The locale used to select region-specific glyphs. 540 factory ParagraphStyle({ 541 TextAlign textAlign, 542 TextDirection textDirection, 543 int maxLines, 544 String fontFamily, 545 double fontSize, 546 double height, 547 FontWeight fontWeight, 548 FontStyle fontStyle, 549 StrutStyle strutStyle, 550 String ellipsis, 551 Locale locale, 552 }) = engine.EngineParagraphStyle; 553 554 bool operator ==(dynamic other); 555 556 int get hashCode; 557 558 String toString(); 559} 560 561abstract class StrutStyle { 562 /// Creates a new StrutStyle object. 563 /// 564 /// * `fontFamily`: The name of the font to use when painting the text (e.g., 565 /// Roboto). 566 /// 567 /// * `fontFamilyFallback`: An ordered list of font family names that will be searched for when 568 /// the font in `fontFamily` cannot be found. 569 /// 570 /// * `fontSize`: The size of glyphs (in logical pixels) to use when painting 571 /// the text. 572 /// 573 /// * `lineHeight`: The minimum height of the line boxes, as a multiple of the 574 /// font size. The lines of the paragraph will be at least 575 /// `(lineHeight + leading) * fontSize` tall when fontSize 576 /// is not null. When fontSize is null, there is no minimum line height. Tall 577 /// glyphs due to baseline alignment or large [TextStyle.fontSize] may cause 578 /// the actual line height after layout to be taller than specified here. 579 /// [fontSize] must be provided for this property to take effect. 580 /// 581 /// * `leading`: The minimum amount of leading between lines as a multiple of 582 /// the font size. [fontSize] must be provided for this property to take effect. 583 /// 584 /// * `fontWeight`: The typeface thickness to use when painting the text 585 /// (e.g., bold). 586 /// 587 /// * `fontStyle`: The typeface variant to use when drawing the letters (e.g., 588 /// italics). 589 /// 590 /// * `forceStrutHeight`: When true, the paragraph will force all lines to be exactly 591 /// `(lineHeight + leading) * fontSize` tall from baseline to baseline. 592 /// [TextStyle] is no longer able to influence the line height, and any tall 593 /// glyphs may overlap with lines above. If a [fontFamily] is specified, the 594 /// total ascent of the first line will be the min of the `Ascent + half-leading` 595 /// of the [fontFamily] and `(lineHeight + leading) * fontSize`. Otherwise, it 596 /// will be determined by the Ascent + half-leading of the first text. 597 factory StrutStyle({ 598 String fontFamily, 599 List<String> fontFamilyFallback, 600 double fontSize, 601 double height, 602 double leading, 603 FontWeight fontWeight, 604 FontStyle fontStyle, 605 bool forceStrutHeight, 606 }) = engine.EngineStrutStyle; 607 608 int get hashCode; 609 610 bool operator ==(dynamic other); 611} 612 613/// A direction in which text flows. 614/// 615/// Some languages are written from the left to the right (for example, English, 616/// Tamil, or Chinese), while others are written from the right to the left (for 617/// example Aramaic, Hebrew, or Urdu). Some are also written in a mixture, for 618/// example Arabic is mostly written right-to-left, with numerals written 619/// left-to-right. 620/// 621/// The text direction must be provided to APIs that render text or lay out 622/// boxes horizontally, so that they can determine which direction to start in: 623/// either right-to-left, [TextDirection.rtl]; or left-to-right, 624/// [TextDirection.ltr]. 625/// 626/// ## Design discussion 627/// 628/// Flutter is designed to address the needs of applications written in any of 629/// the world's currently-used languages, whether they use a right-to-left or 630/// left-to-right writing direction. Flutter does not support other writing 631/// modes, such as vertical text or boustrophedon text, as these are rarely used 632/// in computer programs. 633/// 634/// It is common when developing user interface frameworks to pick a default 635/// text direction — typically left-to-right, the direction most familiar to the 636/// engineers working on the framework — because this simplifies the development 637/// of applications on the platform. Unfortunately, this frequently results in 638/// the platform having unexpected left-to-right biases or assumptions, as 639/// engineers will typically miss places where they need to support 640/// right-to-left text. This then results in bugs that only manifest in 641/// right-to-left environments. 642/// 643/// In an effort to minimize the extent to which Flutter experiences this 644/// category of issues, the lowest levels of the Flutter framework do not have a 645/// default text reading direction. Any time a reading direction is necessary, 646/// for example when text is to be displayed, or when a 647/// writing-direction-dependent value is to be interpreted, the reading 648/// direction must be explicitly specified. Where possible, such as in `switch` 649/// statements, the right-to-left case is listed first, to avoid the impression 650/// that it is an afterthought. 651/// 652/// At the higher levels (specifically starting at the widgets library), an 653/// ambient [Directionality] is introduced, which provides a default. Thus, for 654/// instance, a [Text] widget in the scope of a [MaterialApp] widget does not 655/// need to be given an explicit writing direction. The [Directionality.of] 656/// static method can be used to obtain the ambient text direction for a 657/// particular [BuildContext]. 658/// 659/// ### Known left-to-right biases in Flutter 660/// 661/// Despite the design intent described above, certain left-to-right biases have 662/// nonetheless crept into Flutter's design. These include: 663/// 664/// * The [Canvas] origin is at the top left, and the x-axis increases in a 665/// left-to-right direction. 666/// 667/// * The default localization in the widgets and material libraries is 668/// American English, which is left-to-right. 669/// 670/// ### Visual properties vs directional properties 671/// 672/// Many classes in the Flutter framework are offered in two versions, a 673/// visually-oriented variant, and a text-direction-dependent variant. For 674/// example, [EdgeInsets] is described in terms of top, left, right, and bottom, 675/// while [EdgeInsetsDirectional] is described in terms of top, start, end, and 676/// bottom, where start and end correspond to right and left in right-to-left 677/// text and left and right in left-to-right text. 678/// 679/// There are distinct use cases for each of these variants. 680/// 681/// Text-direction-dependent variants are useful when developing user interfaces 682/// that should "flip" with the text direction. For example, a paragraph of text 683/// in English will typically be left-aligned and a quote will be indented from 684/// the left, while in Arabic it will be right-aligned and indented from the 685/// right. Both of these cases are described by the direction-dependent 686/// [TextAlign.start] and [EdgeInsetsDirectional.start]. 687/// 688/// In contrast, the visual variants are useful when the text direction is known 689/// and not affected by the reading direction. For example, an application 690/// giving driving directions might show a "turn left" arrow on the left and a 691/// "turn right" arrow on the right — and would do so whether the application 692/// was localized to French (left-to-right) or Hebrew (right-to-left). 693/// 694/// In practice, it is also expected that many developers will only be 695/// targeting one language, and in that case it may be simpler to think in 696/// visual terms. 697// The order of this enum must match the order of the values in TextDirection.h's TextDirection. 698enum TextDirection { 699 /// The text flows from right to left (e.g. Arabic, Hebrew). 700 rtl, 701 702 /// The text flows from left to right (e.g., English, French). 703 ltr, 704} 705 706/// A rectangle enclosing a run of text. 707/// 708/// This is similar to [Rect] but includes an inherent [TextDirection]. 709class TextBox { 710 /// Creates an object that describes a box containing text. 711 const TextBox.fromLTRBD( 712 this.left, 713 this.top, 714 this.right, 715 this.bottom, 716 this.direction, 717 ); 718 719 TextBox._( 720 this.left, 721 this.top, 722 this.right, 723 this.bottom, 724 int directionIndex, 725 ) : direction = TextDirection.values[directionIndex]; 726 727 /// The left edge of the text box, irrespective of direction. 728 /// 729 /// To get the leading edge (which may depend on the [direction]), consider [start]. 730 final double left; 731 732 /// The top edge of the text box. 733 final double top; 734 735 /// The right edge of the text box, irrespective of direction. 736 /// 737 /// To get the trailing edge (which may depend on the [direction]), consider [end]. 738 final double right; 739 740 /// The bottom edge of the text box. 741 final double bottom; 742 743 /// The direction in which text inside this box flows. 744 final TextDirection direction; 745 746 /// Returns a rect of the same size as this box. 747 Rect toRect() => Rect.fromLTRB(left, top, right, bottom); 748 749 /// The [left] edge of the box for left-to-right text; the [right] edge of the box for right-to-left text. 750 /// 751 /// See also: 752 /// 753 /// * [direction], which specifies the text direction. 754 double get start { 755 return (direction == TextDirection.ltr) ? left : right; 756 } 757 758 /// The [right] edge of the box for left-to-right text; the [left] edge of the box for right-to-left text. 759 /// 760 /// See also: 761 /// 762 /// * [direction], which specifies the text direction. 763 double get end { 764 return (direction == TextDirection.ltr) ? right : left; 765 } 766 767 @override 768 bool operator ==(dynamic other) { 769 if (identical(this, other)) { 770 return true; 771 } 772 if (other.runtimeType != runtimeType) { 773 return false; 774 } 775 final TextBox typedOther = other; 776 return typedOther.left == left && 777 typedOther.top == top && 778 typedOther.right == right && 779 typedOther.bottom == bottom && 780 typedOther.direction == direction; 781 } 782 783 @override 784 int get hashCode => hashValues(left, top, right, bottom, direction); 785 786 @override 787 String toString() { 788 if (engine.assertionsEnabled) { 789 return 'TextBox.fromLTRBD(${left.toStringAsFixed(1)}, ${top.toStringAsFixed(1)}, ${right.toStringAsFixed(1)}, ${bottom.toStringAsFixed(1)}, $direction)'; 790 } 791 return super.toString(); 792 } 793} 794 795/// A way to disambiguate a [TextPosition] when its offset could match two 796/// different locations in the rendered string. 797/// 798/// For example, at an offset where the rendered text wraps, there are two 799/// visual positions that the offset could represent: one prior to the line 800/// break (at the end of the first line) and one after the line break (at the 801/// start of the second line). A text affinity disambiguates between these two 802/// cases. 803/// 804/// This affects only line breaks caused by wrapping, not explicit newline 805/// characters. For newline characters, the position is fully specified by the 806/// offset alone, and there is no ambiguity. 807/// 808/// [TextAffinity] also affects bidirectional text at the interface between LTR 809/// and RTL text. Consider the following string, where the lowercase letters 810/// will be displayed as LTR and the uppercase letters RTL: "helloHELLO". When 811/// rendered, the string would appear visually as "helloOLLEH". An offset of 5 812/// would be ambiguous without a corresponding [TextAffinity]. Looking at the 813/// string in code, the offset represents the position just after the "o" and 814/// just before the "H". When rendered, this offset could be either in the 815/// middle of the string to the right of the "o" or at the end of the string to 816/// the right of the "H". 817enum TextAffinity { 818 /// The position has affinity for the upstream side of the text position, i.e. 819 /// in the direction of the beginning of the string. 820 /// 821 /// In the example of an offset at the place where text is wrapping, upstream 822 /// indicates the end of the first line. 823 /// 824 /// In the bidirectional text example "helloHELLO", an offset of 5 with 825 /// [TextAffinity] upstream would appear in the middle of the rendered text, 826 /// just to the right of the "o". See the definition of [TextAffinity] for the 827 /// full example. 828 upstream, 829 830 /// The position has affinity for the downstream side of the text position, 831 /// i.e. in the direction of the end of the string. 832 /// 833 /// In the example of an offset at the place where text is wrapping, 834 /// downstream indicates the beginning of the second line. 835 /// 836 /// In the bidirectional text example "helloHELLO", an offset of 5 with 837 /// [TextAffinity] downstream would appear at the end of the rendered text, 838 /// just to the right of the "H". See the definition of [TextAffinity] for the 839 /// full example. 840 downstream, 841} 842 843/// A position in a string of text. 844/// 845/// A TextPosition can be used to locate a position in a string in code (using 846/// the [offset] property), and it can also be used to locate the same position 847/// visually in a rendered string of text (using [offset] and, when needed to 848/// resolve ambiguity, [affinity]). 849/// 850/// The location of an offset in a rendered string is ambiguous in two cases. 851/// One happens when rendered text is forced to wrap. In this case, the offset 852/// where the wrap occurs could visually appear either at the end of the first 853/// line or the beginning of the second line. The second way is with 854/// bidirectional text. An offset at the interface between two different text 855/// directions could have one of two locations in the rendered text. 856/// 857/// See the documentation for [TextAffinity] for more information on how 858/// TextAffinity disambiguates situations like these. 859class TextPosition { 860 /// Creates an object representing a particular position in a string. 861 /// 862 /// The arguments must not be null (so the [offset] argument is required). 863 const TextPosition({ 864 this.offset, 865 this.affinity = TextAffinity.downstream, 866 }) : assert(offset != null), 867 assert(affinity != null); 868 869 /// The index of the character that immediately follows the position in the 870 /// string representation of the text. 871 /// 872 /// For example, given the string `'Hello'`, offset 0 represents the cursor 873 /// being before the `H`, while offset 5 represents the cursor being just 874 /// after the `o`. 875 final int offset; 876 877 /// Disambiguates cases where the position in the string given by [offset] 878 /// could represent two different visual positions in the rendered text. For 879 /// example, this can happen when text is forced to wrap, or when one string 880 /// of text is rendered with multiple text directions. 881 /// 882 /// See the documentation for [TextAffinity] for more information on how 883 /// TextAffinity disambiguates situations like these. 884 final TextAffinity affinity; 885 886 @override 887 bool operator ==(dynamic other) { 888 if (other.runtimeType != runtimeType) { 889 return false; 890 } 891 final TextPosition typedOther = other; 892 return typedOther.offset == offset && typedOther.affinity == affinity; 893 } 894 895 @override 896 int get hashCode => hashValues(offset, affinity); 897 898 @override 899 String toString() { 900 return '$runtimeType(offset: $offset, affinity: $affinity)'; 901 } 902} 903 904/// Layout constraints for [Paragraph] objects. 905/// 906/// Instances of this class are typically used with [Paragraph.layout]. 907/// 908/// The only constraint that can be specified is the [width]. See the discussion 909/// at [width] for more details. 910class ParagraphConstraints { 911 /// Creates constraints for laying out a pargraph. 912 /// 913 /// The [width] argument must not be null. 914 const ParagraphConstraints({ 915 this.width, 916 }) : assert(width != null); 917 918 /// The width the paragraph should use whey computing the positions of glyphs. 919 /// 920 /// If possible, the paragraph will select a soft line break prior to reaching 921 /// this width. If no soft line break is available, the paragraph will select 922 /// a hard line break prior to reaching this width. If that would force a line 923 /// break without any characters having been placed (i.e. if the next 924 /// character to be laid out does not fit within the given width constraint) 925 /// then the next character is allowed to overflow the width constraint and a 926 /// forced line break is placed after it (even if an explicit line break 927 /// follows). 928 /// 929 /// The width influences how ellipses are applied. See the discussion at [new 930 /// ParagraphStyle] for more details. 931 /// 932 /// This width is also used to position glyphs according to the [TextAlign] 933 /// alignment described in the [ParagraphStyle] used when building the 934 /// [Paragraph] with a [ParagraphBuilder]. 935 final double width; 936 937 @override 938 bool operator ==(dynamic other) { 939 if (other.runtimeType != runtimeType) { 940 return false; 941 } 942 final ParagraphConstraints typedOther = other; 943 return typedOther.width == width; 944 } 945 946 @override 947 int get hashCode => width.hashCode; 948 949 @override 950 String toString() => '$runtimeType(width: $width)'; 951} 952 953/// Defines various ways to vertically bound the boxes returned by 954/// [Paragraph.getBoxesForRange]. 955enum BoxHeightStyle { 956 /// Provide tight bounding boxes that fit heights per run. This style may result 957 /// in uneven bounding boxes that do not nicely connect with adjacent boxes. 958 tight, 959 960 /// The height of the boxes will be the maximum height of all runs in the 961 /// line. All boxes in the same line will be the same height. This does not 962 /// guarantee that the boxes will cover the entire vertical height of the line 963 /// when there is additional line spacing. 964 /// 965 /// See [RectHeightStyle.includeLineSpacingTop], [RectHeightStyle.includeLineSpacingMiddle], 966 /// and [RectHeightStyle.includeLineSpacingBottom] for styles that will cover 967 /// the entire line. 968 max, 969 970 /// Extends the top and bottom edge of the bounds to fully cover any line 971 /// spacing. 972 /// 973 /// The top and bottom of each box will cover half of the 974 /// space above and half of the space below the line. 975 /// 976 /// {@template flutter.dart:ui.boxHeightStyle.includeLineSpacing} 977 /// The top edge of each line should be the same as the bottom edge 978 /// of the line above. There should be no gaps in vertical coverage given any 979 /// amount of line spacing. Line spacing is not included above the first line 980 /// and below the last line due to no additional space present there. 981 /// {@endtemplate} 982 includeLineSpacingMiddle, 983 984 /// Extends the top edge of the bounds to fully cover any line spacing. 985 /// 986 /// The line spacing will be added to the top of the box. 987 /// 988 /// {@macro flutter.dart:ui.rectHeightStyle.includeLineSpacing} 989 includeLineSpacingTop, 990 991 /// Extends the bottom edge of the bounds to fully cover any line spacing. 992 /// 993 /// The line spacing will be added to the bottom of the box. 994 /// 995 /// {@macro flutter.dart:ui.boxHeightStyle.includeLineSpacing} 996 includeLineSpacingBottom, 997} 998 999/// Defines various ways to horizontally bound the boxes returned by 1000/// [Paragraph.getBoxesForRange]. 1001enum BoxWidthStyle { 1002 // Provide tight bounding boxes that fit widths to the runs of each line 1003 // independently. 1004 tight, 1005 1006 /// Adds up to two additional boxes as needed at the beginning and/or end 1007 /// of each line so that the widths of the boxes in line are the same width 1008 /// as the widest line in the paragraph. The additional boxes on each line 1009 /// are only added when the relevant box at the relevant edge of that line 1010 /// does not span the maximum width of the paragraph. 1011 max, 1012} 1013 1014/// A paragraph of text. 1015/// 1016/// A paragraph retains the size and position of each glyph in the text and can 1017/// be efficiently resized and painted. 1018/// 1019/// To create a [Paragraph] object, use a [ParagraphBuilder]. 1020/// 1021/// Paragraphs can be displayed on a [Canvas] using the [Canvas.drawParagraph] 1022/// method. 1023abstract class Paragraph { 1024 /// The amount of horizontal space this paragraph occupies. 1025 /// 1026 /// Valid only after [layout] has been called. 1027 double get width; 1028 1029 /// The amount of vertical space this paragraph occupies. 1030 /// 1031 /// Valid only after [layout] has been called. 1032 double get height; 1033 1034 /// The distance from the left edge of the leftmost glyph to the right edge of 1035 /// the rightmost glyph in the paragraph. 1036 /// 1037 /// Valid only after [layout] has been called. 1038 double get longestLine; 1039 1040 /// {@template dart.ui.paragraph.minIntrinsicWidth} 1041 /// The minimum width that this paragraph could be without failing to paint 1042 /// its contents within itself. 1043 /// {@endtemplate} 1044 /// 1045 /// Valid only after [layout] has been called. 1046 double get minIntrinsicWidth; 1047 1048 /// {@template dart.ui.paragraph.maxIntrinsicWidth} 1049 /// Returns the smallest width beyond which increasing the width never 1050 /// decreases the height. 1051 /// {@endtemplate} 1052 /// 1053 /// Valid only after [layout] has been called. 1054 double get maxIntrinsicWidth; 1055 1056 /// {@template dart.ui.paragraph.alphabeticBaseline} 1057 /// The distance from the top of the paragraph to the alphabetic 1058 /// baseline of the first line, in logical pixels. 1059 /// {@endtemplate} 1060 /// 1061 /// Valid only after [layout] has been called. 1062 double get alphabeticBaseline; 1063 1064 /// {@template dart.ui.paragraph.ideographicBaseline} 1065 /// The distance from the top of the paragraph to the ideographic 1066 /// baseline of the first line, in logical pixels. 1067 /// {@endtemplate} 1068 /// 1069 /// Valid only after [layout] has been called. 1070 double get ideographicBaseline; 1071 1072 /// True if there is more vertical content, but the text was truncated, either 1073 /// because we reached `maxLines` lines of text or because the `maxLines` was 1074 /// null, `ellipsis` was not null, and one of the lines exceeded the width 1075 /// constraint. 1076 /// 1077 /// See the discussion of the `maxLines` and `ellipsis` arguments at [new 1078 /// ParagraphStyle]. 1079 bool get didExceedMaxLines; 1080 1081 /// Computes the size and position of each glyph in the paragraph. 1082 /// 1083 /// The [ParagraphConstraints] control how wide the text is allowed to be. 1084 void layout(ParagraphConstraints constraints); 1085 1086 /// Returns a list of text boxes that enclose the given text range. 1087 /// 1088 /// The [boxHeightStyle] and [boxWidthStyle] parameters allow customization 1089 /// of how the boxes are bound vertically and horizontally. Both style 1090 /// parameters default to the tight option, which will provide close-fitting 1091 /// boxes and will not account for any line spacing. 1092 /// 1093 /// The [boxHeightStyle] and [boxWidthStyle] parameters must not be null. 1094 /// 1095 /// See [BoxHeightStyle] and [BoxWidthStyle] for full descriptions of each option. 1096 List<TextBox> getBoxesForRange(int start, int end, 1097 {BoxHeightStyle boxHeightStyle = BoxHeightStyle.tight, 1098 BoxWidthStyle boxWidthStyle = BoxWidthStyle.tight}); 1099 1100 /// Returns the text position closest to the given offset. 1101 /// 1102 /// It does so by performing a binary search to find where the tap occurred 1103 /// within the text. 1104 TextPosition getPositionForOffset(Offset offset); 1105 1106 /// Returns the [start, end] of the word at the given offset. Characters not 1107 /// part of a word, such as spaces, symbols, and punctuation, have word breaks 1108 /// on both sides. In such cases, this method will return [offset, offset+1]. 1109 /// Word boundaries are defined more precisely in Unicode Standard Annex #29 1110 /// http://www.unicode.org/reports/tr29/#Word_Boundaries 1111 List<int> getWordBoundary(int offset); 1112 1113 /// Returns a list of text boxes that enclose all placeholders in the paragraph. 1114 /// 1115 /// The order of the boxes are in the same order as passed in through [addPlaceholder]. 1116 /// 1117 /// Coordinates of the [TextBox] are relative to the upper-left corner of the paragraph, 1118 /// where positive y values indicate down. 1119 List<TextBox> getBoxesForPlaceholders(); 1120} 1121 1122/// Builds a [Paragraph] containing text with the given styling information. 1123/// 1124/// To set the paragraph's alignment, truncation, and ellipsising behavior, pass 1125/// an appropriately-configured [ParagraphStyle] object to the [new 1126/// ParagraphBuilder] constructor. 1127/// 1128/// Then, call combinations of [pushStyle], [addText], and [pop] to add styled 1129/// text to the object. 1130/// 1131/// Finally, call [build] to obtain the constructed [Paragraph] object. After 1132/// this point, the builder is no longer usable. 1133/// 1134/// After constructing a [Paragraph], call [Paragraph.layout] on it and then 1135/// paint it with [Canvas.drawParagraph]. 1136abstract class ParagraphBuilder { 1137 /// Creates a [ParagraphBuilder] object, which is used to create a 1138 /// [Paragraph]. 1139 factory ParagraphBuilder(ParagraphStyle style) => 1140 engine.EngineParagraphBuilder(style); 1141 1142 /// Applies the given style to the added text until [pop] is called. 1143 /// 1144 /// See [pop] for details. 1145 void pushStyle(TextStyle style); 1146 1147 /// Ends the effect of the most recent call to [pushStyle]. 1148 /// 1149 /// Internally, the paragraph builder maintains a stack of text styles. Text 1150 /// added to the paragraph is affected by all the styles in the stack. Calling 1151 /// [pop] removes the topmost style in the stack, leaving the remaining styles 1152 /// in effect. 1153 void pop(); 1154 1155 /// Adds the given text to the paragraph. 1156 /// 1157 /// The text will be styled according to the current stack of text styles. 1158 void addText(String text); 1159 1160 /// Applies the given paragraph style and returns a [Paragraph] containing the 1161 /// added text and associated styling. 1162 /// 1163 /// After calling this function, the paragraph builder object is invalid and 1164 /// cannot be used further. 1165 Paragraph build(); 1166 1167 /// The number of placeholders currently in the paragraph. 1168 int get placeholderCount; 1169 1170 /// The scales of the placeholders in the paragraph. 1171 List<double> get placeholderScales; 1172 1173 /// Adds an inline placeholder space to the paragraph. 1174 /// 1175 /// The paragraph will contain a rectangular space with no text of the dimensions 1176 /// specified. 1177 /// 1178 /// The `width` and `height` parameters specify the size of the placeholder rectangle. 1179 /// 1180 /// The `alignment` parameter specifies how the placeholder rectangle will be vertically 1181 /// aligned with the surrounding text. When [PlaceholderAlignment.baseline], 1182 /// [PlaceholderAlignment.aboveBaseline], and [PlaceholderAlignment.belowBaseline] 1183 /// alignment modes are used, the baseline needs to be set with the `baseline`. 1184 /// When using [PlaceholderAlignment.baseline], `baselineOffset` indicates the distance 1185 /// of the baseline down from the top of of the rectangle. The default `baselineOffset` 1186 /// is the `height`. 1187 /// 1188 /// Examples: 1189 /// 1190 /// * For a 30x50 placeholder with the bottom edge aligned with the bottom of the text, use: 1191 /// `addPlaceholder(30, 50, PlaceholderAlignment.bottom);` 1192 /// * For a 30x50 placeholder that is vertically centered around the text, use: 1193 /// `addPlaceholder(30, 50, PlaceholderAlignment.middle);`. 1194 /// * For a 30x50 placeholder that sits completely on top of the alphabetic baseline, use: 1195 /// `addPlaceholder(30, 50, PlaceholderAlignment.aboveBaseline, baseline: TextBaseline.alphabetic)`. 1196 /// * For a 30x50 placeholder with 40 pixels above and 10 pixels below the alphabetic baseline, use: 1197 /// `addPlaceholder(30, 50, PlaceholderAlignment.baseline, baseline: TextBaseline.alphabetic, baselineOffset: 40)`. 1198 /// 1199 /// Lines are permitted to break around each placeholder. 1200 /// 1201 /// Decorations will be drawn based on the font defined in the most recently 1202 /// pushed [TextStyle]. The decorations are drawn as if unicode text were present 1203 /// in the placeholder space, and will draw the same regardless of the height and 1204 /// alignment of the placeholder. To hide or manually adjust decorations to fit, 1205 /// a text style with the desired decoration behavior should be pushed before 1206 /// adding a placeholder. 1207 /// 1208 /// Any decorations drawn through a placeholder will exist on the same canvas/layer 1209 /// as the text. This means any content drawn on top of the space reserved by 1210 /// the placeholder will be drawn over the decoration, possibly obscuring the 1211 /// decoration. 1212 /// 1213 /// Placeholders are represented by a unicode 0xFFFC "object replacement character" 1214 /// in the text buffer. For each placeholder, one object replacement character is 1215 /// added on to the text buffer. 1216 void addPlaceholder( 1217 double width, 1218 double height, 1219 PlaceholderAlignment alignment, { 1220 double scale, 1221 double baselineOffset, 1222 TextBaseline baseline, 1223 }); 1224} 1225 1226/// Loads a font from a buffer and makes it available for rendering text. 1227/// 1228/// * `list`: A list of bytes containing the font file. 1229/// * `fontFamily`: The family name used to identify the font in text styles. 1230/// If this is not provided, then the family name will be extracted from the font file. 1231Future<void> loadFontFromList(Uint8List list, {String fontFamily}) { 1232 if (engine.assertionsEnabled) { 1233 throw UnsupportedError('loadFontFromList is not supported.'); 1234 } 1235 return Future<void>.value(null); 1236} 1237