diff --git a/engine/src/flutter/lib/ui/text.dart b/engine/src/flutter/lib/ui/text.dart index 16fbfea439..f9740446da 100644 --- a/engine/src/flutter/lib/ui/text.dart +++ b/engine/src/flutter/lib/ui/text.dart @@ -81,7 +81,8 @@ class FontWeight { } } -/// Whether to align text horizontally. +/// Whether and how to align text horizontally. +// The order of this enum must match the order of the values in RenderStyleConstants.h's ETextAlign. enum TextAlign { /// Align the text on the left edge of the container. left, @@ -95,9 +96,22 @@ enum TextAlign { /// Stretch lines of text that end with a soft line break to fill the width of /// the container. /// - /// Lines that end with hard line breaks are left-aligned. - // TODO(ianh): for rtl, this should presumably change to start-aligned. + /// Lines that end with hard line breaks are aligned towards the [start] edge. justify, + + /// Align the text on the leading edge of the container. + /// + /// For left-to-right text ([TextDirection.ltr]), this is the left edge. + /// + /// For right-to-left text ([TextDirection.rtr]), this is the right edge. + start, + + /// Align the text on the trailing edge of the container. + /// + /// For left-to-right text ([TextDirection.ltr]), this is the right edge. + /// + /// For right-to-left text ([TextDirection.rtr]), this is the left edge. + end, } /// A horizontal line used for aligning text. @@ -106,7 +120,7 @@ enum TextBaseline { alphabetic, // The horizontal line used to align ideographic characters. - ideographic + ideographic, } /// A linear decoration to draw near the text. @@ -385,6 +399,7 @@ class TextStyle { // - Element 4: The value of |maxLines|. // Int32List _encodeParagraphStyle(TextAlign textAlign, + TextDirection textDirection, FontWeight fontWeight, FontStyle fontStyle, int maxLines, @@ -397,34 +412,38 @@ Int32List _encodeParagraphStyle(TextAlign textAlign, result[0] |= 1 << 1; result[1] = textAlign.index; } - if (fontWeight != null) { + if (textDirection != null) { result[0] |= 1 << 2; - result[2] = fontWeight.index; + result[2] = textDirection.index; + } + if (fontWeight != null) { + result[0] |= 1 << 3; + result[3] = fontWeight.index; } if (fontStyle != null) { - result[0] |= 1 << 3; - result[3] = fontStyle.index; + result[0] |= 1 << 4; + result[4] = fontStyle.index; } if (maxLines != null) { - result[0] |= 1 << 4; - result[4] = maxLines; + result[0] |= 1 << 5; + result[5] = maxLines; } if (fontFamily != null) { - result[0] |= 1 << 5; - // Passed separately to native. - } - if (fontSize != null) { result[0] |= 1 << 6; // Passed separately to native. } - if (lineHeight != null) { + if (fontSize != null) { result[0] |= 1 << 7; // Passed separately to native. } - if (ellipsis != null) { + if (lineHeight != null) { result[0] |= 1 << 8; // Passed separately to native. } + if (ellipsis != null) { + result[0] |= 1 << 9; + // Passed separately to native. + } return result; } @@ -439,6 +458,11 @@ class ParagraphStyle { /// the ellipsis has been added. // See: https://github.com/flutter/flutter/issues/9819 /// + /// * `textDirection`: The directionality of the text, left-to-right (e.g. + /// Norwegian) or right-to-left (e.g. Hebrew). This controls the overall + /// directionality of the paragraph, as well as the meaning of + /// [TextAlign.start] and [TextAlign.end] in the `textAlign` field. + /// /// * `fontWeight`: The typeface thickness to use when painting the text /// (e.g., bold). /// @@ -471,6 +495,7 @@ class ParagraphStyle { /// considered equivalent and turn off this behavior. ParagraphStyle({ TextAlign textAlign, + TextDirection textDirection, FontWeight fontWeight, FontStyle fontStyle, int maxLines, @@ -479,6 +504,7 @@ class ParagraphStyle { double lineHeight, String ellipsis, }) : _encoded = _encodeParagraphStyle(textAlign, + textDirection, fontWeight, fontStyle, maxLines, @@ -500,10 +526,10 @@ class ParagraphStyle { bool operator ==(dynamic other) { if (identical(this, other)) return true; - if (other is! ParagraphStyle) + if (other.runtimeType != runtimeType) return false; final ParagraphStyle typedOther = other; - if ( _fontFamily != typedOther._fontFamily || + if (_fontFamily != typedOther._fontFamily || _fontSize != typedOther._fontSize || _lineHeight != typedOther._lineHeight || _ellipsis != typedOther._ellipsis) @@ -515,23 +541,25 @@ class ParagraphStyle { return true; } - int get hashCode => hashValues(hashList(_encoded), _lineHeight, _ellipsis); + int get hashCode => hashValues(hashList(_encoded), _fontFamily, _fontSize, _lineHeight, _ellipsis); String toString() { - return 'ParagraphStyle(' - 'textAlign: ${ _encoded[0] & 0x02 == 0x02 ? TextAlign.values[_encoded[1]] : "unspecified"}, ' - 'fontWeight: ${ _encoded[0] & 0x04 == 0x04 ? FontWeight.values[_encoded[2]] : "unspecified"}, ' - 'fontStyle: ${ _encoded[0] & 0x08 == 0x08 ? FontStyle.values[_encoded[3]] : "unspecified"}, ' - 'maxLines: ${ _encoded[0] & 0x10 == 0x10 ? _encoded[4] : "unspecified"}, ' - 'fontFamily: ${ _encoded[0] & 0x20 == 0x20 ? _fontFamily : "unspecified"}, ' - 'fontSize: ${ _encoded[0] & 0x40 == 0x40 ? _fontSize : "unspecified"}, ' - 'lineHeight: ${ _encoded[0] & 0x80 == 0x80 ? "${_lineHeight}x" : "unspecified"}, ' - 'ellipsis: ${ _encoded[0] & 0x100 == 0x100 ? "\"$_ellipsis\"" : "unspecified"}' + return '$runtimeType(' + 'textAlign: ${ _encoded[0] & 0x002 == 0x002 ? TextAlign.values[_encoded[1]] : "unspecified"}, ' + 'textDirection: ${ _encoded[0] & 0x004 == 0x004 ? TextDirection.values[_encoded[2]] : "unspecified"}, ' + 'fontWeight: ${ _encoded[0] & 0x008 == 0x008 ? FontWeight.values[_encoded[3]] : "unspecified"}, ' + 'fontStyle: ${ _encoded[0] & 0x010 == 0x010 ? FontStyle.values[_encoded[4]] : "unspecified"}, ' + 'maxLines: ${ _encoded[0] & 0x020 == 0x020 ? _encoded[5] : "unspecified"}, ' + 'fontFamily: ${ _encoded[0] & 0x040 == 0x040 ? _fontFamily : "unspecified"}, ' + 'fontSize: ${ _encoded[0] & 0x080 == 0x080 ? _fontSize : "unspecified"}, ' + 'lineHeight: ${ _encoded[0] & 0x100 == 0x100 ? "${_lineHeight}x" : "unspecified"}, ' + 'ellipsis: ${ _encoded[0] & 0x200 == 0x200 ? "\"$_ellipsis\"" : "unspecified"}' ')'; } } /// A direction in which text flows. +// The order of this enum must match the order of the values in TextDirection.h's TextDirection. enum TextDirection { /// The text flows from right to left (e.g. Arabic, Hebrew). rtl, @@ -547,7 +575,7 @@ class TextBox { this.top, this.right, this.bottom, - this.direction + this.direction, ); TextBox._( @@ -555,7 +583,7 @@ class TextBox { this.top, this.right, this.bottom, - int directionIndex + int directionIndex, ) : direction = TextDirection.values[directionIndex]; /// The left edge of the text box, irrespective of direction. @@ -589,7 +617,7 @@ class TextBox { bool operator ==(dynamic other) { if (identical(this, other)) return true; - if (other is! TextBox) + if (other.runtimeType != runtimeType) return false; final TextBox typedOther = other; return typedOther.left == left @@ -622,7 +650,7 @@ enum TextAffinity { /// /// For example, if the offset of the text position is a line break, the /// position represents the start of the second line. - downstream + downstream, } /// A visual position in a string of text. @@ -675,7 +703,7 @@ class ParagraphConstraints { final double width; bool operator ==(dynamic other) { - if (other is! ParagraphConstraints) + if (other.runtimeType != runtimeType) return false; final ParagraphConstraints typedOther = other; return typedOther.width == width; @@ -683,7 +711,7 @@ class ParagraphConstraints { int get hashCode => width.hashCode; - String toString() => 'ParagraphConstraints(width: $width)'; + String toString() => '$runtimeType(width: $width)'; } /// A paragraph of text. diff --git a/engine/src/flutter/lib/ui/text/paragraph_builder.cc b/engine/src/flutter/lib/ui/text/paragraph_builder.cc index f25331869b..cfb9034130 100644 --- a/engine/src/flutter/lib/ui/text/paragraph_builder.cc +++ b/engine/src/flutter/lib/ui/text/paragraph_builder.cc @@ -51,15 +51,17 @@ const int tsHeightMask = 1 << tsHeightIndex; // ParagraphStyle const int psTextAlignIndex = 1; -const int psFontWeightIndex = 2; -const int psFontStyleIndex = 3; -const int psMaxLinesIndex = 4; -const int psFontFamilyIndex = 5; -const int psFontSizeIndex = 6; -const int psLineHeightIndex = 7; -const int psEllipsisIndex = 8; +const int psTextDirectionIndex = 2; +const int psFontWeightIndex = 3; +const int psFontStyleIndex = 4; +const int psMaxLinesIndex = 5; +const int psFontFamilyIndex = 6; +const int psFontSizeIndex = 7; +const int psLineHeightIndex = 8; +const int psEllipsisIndex = 9; const int psTextAlignMask = 1 << psTextAlignIndex; +const int psTextDirectionMask = 1 << psTextDirectionIndex; const int psFontWeightMask = 1 << psFontWeightIndex; const int psFontStyleMask = 1 << psFontStyleIndex; const int psMaxLinesMask = 1 << psMaxLinesIndex; @@ -113,6 +115,9 @@ PassRefPtr decodeParagraphStyle( if (mask & psTextAlignMask) style->setTextAlign(static_cast(encoded[psTextAlignIndex])); + if (mask & psTextDirectionMask) + style->setDirection(static_cast(encoded[psTextDirectionIndex])); + if (mask & (psFontWeightMask | psFontStyleMask | psFontFamilyMask | psFontSizeMask)) { FontDescription fontDescription = style->fontDescription();