• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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