Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit cbf4536

Browse files
authored
Engine/LibTxt/dart:ui impl of TextHeightBehavior (#15087)
1 parent 222770c commit cbf4536

File tree

10 files changed

+422
-22
lines changed

10 files changed

+422
-22
lines changed

lib/ui/text.dart

Lines changed: 115 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,94 @@ enum TextDecorationStyle {
429429
wavy
430430
}
431431

432+
/// {@template flutter.dart:ui.textHeightBehavior}
433+
/// Defines how the paragraph will apply [TextStyle.height] to the ascent of the
434+
/// first line and descent of the last line.
435+
///
436+
/// Each boolean value represents whether the [TextStyle.height] modifier will
437+
/// be applied to the corresponding metric. By default, all properties are true,
438+
/// and [TextStyle.height] is applied as normal. When set to false, the font's
439+
/// default ascent will be used.
440+
/// {@endtemplate}
441+
class TextHeightBehavior {
442+
443+
/// Creates a new TextHeightBehavior object.
444+
///
445+
/// * applyHeightToFirstAscent: When true, the [TextStyle.height] modifier
446+
/// will be applied to the ascent of the first line. When false, the font's
447+
/// default ascent will be used.
448+
/// * applyHeightToLastDescent: When true, the [TextStyle.height] modifier
449+
/// will be applied to the descent of the last line. When false, the font's
450+
/// default descent will be used.
451+
///
452+
/// All properties default to true (height modifications applied as normal).
453+
const TextHeightBehavior({
454+
this.applyHeightToFirstAscent = true,
455+
this.applyHeightToLastDescent = true,
456+
});
457+
458+
/// Creates a new TextHeightBehavior object from an encoded form.
459+
///
460+
/// See [encode] for the creation of the encoded form.
461+
const TextHeightBehavior.fromEncoded(int encoded) : applyHeightToFirstAscent = (encoded & 0x1) == 0,
462+
applyHeightToLastDescent = (encoded & 0x2) == 0;
463+
464+
465+
/// Whether to apply the [TextStyle.height] modifier to the ascent of the first
466+
/// line in the paragraph.
467+
///
468+
/// When true, the [TextStyle.height] modifier will be applied to to the ascent
469+
/// of the first line. When false, the font's default ascent will be used and
470+
/// the [TextStyle.height] will have no effect on the ascent of the first line.
471+
///
472+
/// This property only has effect if a non-null [TextStyle.height] is specified.
473+
///
474+
/// Defaults to true (height modifications applied as normal).
475+
final bool applyHeightToFirstAscent;
476+
477+
/// Whether to apply the [TextStyle.height] modifier to the descent of the last
478+
/// line in the paragraph.
479+
///
480+
/// When true, the [TextStyle.height] modifier will be applied to to the descent
481+
/// of the last line. When false, the font's default descent will be used and
482+
/// the [TextStyle.height] will have no effect on the descent of the last line.
483+
///
484+
/// This property only has effect if a non-null [TextStyle.height] is specified.
485+
///
486+
/// Defaults to true (height modifications applied as normal).
487+
final bool applyHeightToLastDescent;
488+
489+
/// Returns an encoded int representation of this object.
490+
int encode() {
491+
return (applyHeightToFirstAscent ? 0 : 1 << 0) | (applyHeightToLastDescent ? 0 : 1 << 1);
492+
}
493+
494+
@override
495+
bool operator ==(dynamic other) {
496+
if (other.runtimeType != runtimeType)
497+
return false;
498+
return other is TextHeightBehavior
499+
&& other.applyHeightToFirstAscent == applyHeightToFirstAscent
500+
&& other.applyHeightToLastDescent == applyHeightToLastDescent;
501+
}
502+
503+
@override
504+
int get hashCode {
505+
return hashValues(
506+
applyHeightToFirstAscent,
507+
applyHeightToLastDescent,
508+
);
509+
}
510+
511+
@override
512+
String toString() {
513+
return 'TextHeightBehavior('
514+
'applyHeightToFirstAscent: $applyHeightToFirstAscent, '
515+
'applyHeightToLastDescent: $applyHeightToLastDescent'
516+
')';
517+
}
518+
}
519+
432520
/// Determines if lists [a] and [b] are deep equivalent.
433521
///
434522
/// Returns true if the lists are both null, or if they are both non-null, have
@@ -746,20 +834,23 @@ class TextStyle {
746834
//
747835
// - Element 5: The value of |maxLines|.
748836
//
837+
// - Element 6: The encoded value of |textHeightBehavior|.
838+
//
749839
Int32List _encodeParagraphStyle(
750840
TextAlign textAlign,
751841
TextDirection textDirection,
752842
int maxLines,
753843
String fontFamily,
754844
double fontSize,
755845
double height,
846+
TextHeightBehavior textHeightBehavior,
756847
FontWeight fontWeight,
757848
FontStyle fontStyle,
758849
StrutStyle strutStyle,
759850
String ellipsis,
760851
Locale locale,
761852
) {
762-
final Int32List result = Int32List(6); // also update paragraph_builder.cc
853+
final Int32List result = Int32List(7); // also update paragraph_builder.cc
763854
if (textAlign != null) {
764855
result[0] |= 1 << 1;
765856
result[1] = textAlign.index;
@@ -780,28 +871,32 @@ Int32List _encodeParagraphStyle(
780871
result[0] |= 1 << 5;
781872
result[5] = maxLines;
782873
}
783-
if (fontFamily != null) {
874+
if (textHeightBehavior != null) {
784875
result[0] |= 1 << 6;
876+
result[6] = textHeightBehavior.encode();
877+
}
878+
if (fontFamily != null) {
879+
result[0] |= 1 << 7;
785880
// Passed separately to native.
786881
}
787882
if (fontSize != null) {
788-
result[0] |= 1 << 7;
883+
result[0] |= 1 << 8;
789884
// Passed separately to native.
790885
}
791886
if (height != null) {
792-
result[0] |= 1 << 8;
887+
result[0] |= 1 << 9;
793888
// Passed separately to native.
794889
}
795890
if (strutStyle != null) {
796-
result[0] |= 1 << 9;
891+
result[0] |= 1 << 10;
797892
// Passed separately to native.
798893
}
799894
if (ellipsis != null) {
800-
result[0] |= 1 << 10;
895+
result[0] |= 1 << 11;
801896
// Passed separately to native.
802897
}
803898
if (locale != null) {
804-
result[0] |= 1 << 11;
899+
result[0] |= 1 << 12;
805900
// Passed separately to native.
806901
}
807902
return result;
@@ -842,6 +937,9 @@ class ParagraphStyle {
842937
/// the line height to take the height as defined by the font, which may not
843938
/// be exactly the height of the `fontSize`.
844939
///
940+
/// * `textHeightBehavior`: Specifies how the `height` multiplier is
941+
/// applied to ascent of the first line and the descent of the last line.
942+
///
845943
/// * `fontWeight`: The typeface thickness to use when painting the text
846944
/// (e.g., bold).
847945
///
@@ -869,6 +967,7 @@ class ParagraphStyle {
869967
String fontFamily,
870968
double fontSize,
871969
double height,
970+
TextHeightBehavior textHeightBehavior,
872971
FontWeight fontWeight,
873972
FontStyle fontStyle,
874973
StrutStyle strutStyle,
@@ -881,6 +980,7 @@ class ParagraphStyle {
881980
fontFamily,
882981
fontSize,
883982
height,
983+
textHeightBehavior,
884984
fontWeight,
885985
fontStyle,
886986
strutStyle,
@@ -929,11 +1029,14 @@ class ParagraphStyle {
9291029
'fontWeight: ${ _encoded[0] & 0x008 == 0x008 ? FontWeight.values[_encoded[3]] : "unspecified"}, '
9301030
'fontStyle: ${ _encoded[0] & 0x010 == 0x010 ? FontStyle.values[_encoded[4]] : "unspecified"}, '
9311031
'maxLines: ${ _encoded[0] & 0x020 == 0x020 ? _encoded[5] : "unspecified"}, '
932-
'fontFamily: ${ _encoded[0] & 0x040 == 0x040 ? _fontFamily : "unspecified"}, '
933-
'fontSize: ${ _encoded[0] & 0x080 == 0x080 ? _fontSize : "unspecified"}, '
934-
'height: ${ _encoded[0] & 0x100 == 0x100 ? "${_height}x" : "unspecified"}, '
935-
'ellipsis: ${ _encoded[0] & 0x200 == 0x200 ? "\"$_ellipsis\"" : "unspecified"}, '
936-
'locale: ${ _encoded[0] & 0x400 == 0x400 ? _locale : "unspecified"}'
1032+
'textHeightBehavior: ${
1033+
_encoded[0] & 0x040 == 0x040 ?
1034+
TextHeightBehavior.fromEncoded(_encoded[6]).toString() : "unspecified"}, '
1035+
'fontFamily: ${ _encoded[0] & 0x080 == 0x080 ? _fontFamily : "unspecified"}, '
1036+
'fontSize: ${ _encoded[0] & 0x100 == 0x100 ? _fontSize : "unspecified"}, '
1037+
'height: ${ _encoded[0] & 0x200 == 0x200 ? "${_height}x" : "unspecified"}, '
1038+
'ellipsis: ${ _encoded[0] & 0x400 == 0x400 ? "\"$_ellipsis\"" : "unspecified"}, '
1039+
'locale: ${ _encoded[0] & 0x800 == 0x800 ? _locale : "unspecified"}'
9371040
')';
9381041
}
9391042
}

lib/ui/text/paragraph_builder.cc

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,13 @@ const int psTextDirectionIndex = 2;
7575
const int psFontWeightIndex = 3;
7676
const int psFontStyleIndex = 4;
7777
const int psMaxLinesIndex = 5;
78-
const int psFontFamilyIndex = 6;
79-
const int psFontSizeIndex = 7;
80-
const int psHeightIndex = 8;
81-
const int psStrutStyleIndex = 9;
82-
const int psEllipsisIndex = 10;
83-
const int psLocaleIndex = 11;
78+
const int psTextHeightBehaviorIndex = 6;
79+
const int psFontFamilyIndex = 7;
80+
const int psFontSizeIndex = 8;
81+
const int psHeightIndex = 9;
82+
const int psStrutStyleIndex = 10;
83+
const int psEllipsisIndex = 11;
84+
const int psLocaleIndex = 12;
8485

8586
const int psTextAlignMask = 1 << psTextAlignIndex;
8687
const int psTextDirectionMask = 1 << psTextDirectionIndex;
@@ -90,6 +91,7 @@ const int psMaxLinesMask = 1 << psMaxLinesIndex;
9091
const int psFontFamilyMask = 1 << psFontFamilyIndex;
9192
const int psFontSizeMask = 1 << psFontSizeIndex;
9293
const int psHeightMask = 1 << psHeightIndex;
94+
const int psTextHeightBehaviorMask = 1 << psTextHeightBehaviorIndex;
9395
const int psStrutStyleMask = 1 << psStrutStyleIndex;
9496
const int psEllipsisMask = 1 << psEllipsisIndex;
9597
const int psLocaleMask = 1 << psLocaleIndex;
@@ -265,6 +267,10 @@ ParagraphBuilder::ParagraphBuilder(
265267
style.has_height_override = true;
266268
}
267269

270+
if (mask & psTextHeightBehaviorMask) {
271+
style.text_height_behavior = encoded[psTextHeightBehaviorIndex];
272+
}
273+
268274
if (mask & psStrutStyleMask) {
269275
decodeStrut(strutData, strutFontFamilies, style);
270276
}

lib/web_ui/lib/src/engine/compositor/text.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class SkParagraphStyle implements ui.ParagraphStyle {
2525
String fontFamily,
2626
double fontSize,
2727
double height,
28+
ui.TextHeightBehavior textHeightBehavior,
2829
ui.FontWeight fontWeight,
2930
ui.FontStyle fontStyle,
3031
ui.StrutStyle strutStyle,
@@ -38,6 +39,7 @@ class SkParagraphStyle implements ui.ParagraphStyle {
3839
fontFamily,
3940
fontSize,
4041
height,
42+
textHeightBehavior,
4143
fontWeight,
4244
fontStyle,
4345
ellipsis,
@@ -85,6 +87,7 @@ class SkParagraphStyle implements ui.ParagraphStyle {
8587
String fontFamily,
8688
double fontSize,
8789
double height,
90+
ui.TextHeightBehavior textHeightBehavior,
8891
ui.FontWeight fontWeight,
8992
ui.FontStyle fontStyle,
9093
String ellipsis,
@@ -129,6 +132,10 @@ class SkParagraphStyle implements ui.ParagraphStyle {
129132
skParagraphStyle['heightMultiplier'] = height;
130133
}
131134

135+
if (textHeightBehavior != null) {
136+
skParagraphStyle['textHeightBehavior'] = textHeightBehavior.encode();
137+
}
138+
132139
if (maxLines != null) {
133140
skParagraphStyle['maxLines'] = maxLines;
134141
}

lib/web_ui/lib/src/engine/text/paragraph.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ class EngineParagraphStyle implements ui.ParagraphStyle {
457457
String fontFamily,
458458
double fontSize,
459459
double height,
460+
ui.TextHeightBehavior textHeightBehavior,
460461
ui.FontWeight fontWeight,
461462
ui.FontStyle fontStyle,
462463
ui.StrutStyle strutStyle,
@@ -470,6 +471,7 @@ class EngineParagraphStyle implements ui.ParagraphStyle {
470471
_fontFamily = fontFamily,
471472
_fontSize = fontSize,
472473
_height = height,
474+
_textHeightBehavior = textHeightBehavior,
473475
// TODO(b/128317744): add support for strut style.
474476
_strutStyle = strutStyle,
475477
_ellipsis = ellipsis,
@@ -483,6 +485,7 @@ class EngineParagraphStyle implements ui.ParagraphStyle {
483485
final String _fontFamily;
484486
final double _fontSize;
485487
final double _height;
488+
final ui.TextHeightBehavior _textHeightBehavior;
486489
final EngineStrutStyle _strutStyle;
487490
final String _ellipsis;
488491
final ui.Locale _locale;
@@ -536,6 +539,7 @@ class EngineParagraphStyle implements ui.ParagraphStyle {
536539
_fontFamily == typedOther._fontFamily ||
537540
_fontSize == typedOther._fontSize ||
538541
_height == typedOther._height ||
542+
_textHeightBehavior == typedOther._textHeightBehavior ||
539543
_ellipsis == typedOther._ellipsis ||
540544
_locale == typedOther._locale;
541545
}
@@ -556,6 +560,7 @@ class EngineParagraphStyle implements ui.ParagraphStyle {
556560
'fontFamily: ${_fontFamily ?? "unspecified"}, '
557561
'fontSize: ${_fontSize != null ? _fontSize.toStringAsFixed(1) : "unspecified"}, '
558562
'height: ${_height != null ? "${_height.toStringAsFixed(1)}x" : "unspecified"}, '
563+
'textHeightBehavior: ${_textHeightBehavior ?? "unspecified"}, '
559564
'ellipsis: ${_ellipsis != null ? "\"$_ellipsis\"" : "unspecified"}, '
560565
'locale: ${_locale ?? "unspecified"}'
561566
')';

0 commit comments

Comments
 (0)