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

Commit ef8353b

Browse files
Reland "TextStyle level leadingDistribution (#24025)" reverted in #24665 (#24668)
1 parent 179ea0b commit ef8353b

File tree

11 files changed

+949
-187
lines changed

11 files changed

+949
-187
lines changed

lib/ui/text.dart

Lines changed: 140 additions & 56 deletions
Large diffs are not rendered by default.

lib/ui/text/paragraph_builder.cc

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,18 @@ const int tsTextDecorationStyleIndex = 4;
3939
const int tsFontWeightIndex = 5;
4040
const int tsFontStyleIndex = 6;
4141
const int tsTextBaselineIndex = 7;
42-
const int tsTextDecorationThicknessIndex = 8;
43-
const int tsFontFamilyIndex = 9;
44-
const int tsFontSizeIndex = 10;
45-
const int tsLetterSpacingIndex = 11;
46-
const int tsWordSpacingIndex = 12;
47-
const int tsHeightIndex = 13;
48-
const int tsLocaleIndex = 14;
49-
const int tsBackgroundIndex = 15;
50-
const int tsForegroundIndex = 16;
51-
const int tsTextShadowsIndex = 17;
52-
const int tsFontFeaturesIndex = 18;
42+
const int tsLeadingDistributionIndex = 8;
43+
const int tsTextDecorationThicknessIndex = 9;
44+
const int tsFontFamilyIndex = 10;
45+
const int tsFontSizeIndex = 11;
46+
const int tsLetterSpacingIndex = 12;
47+
const int tsWordSpacingIndex = 13;
48+
const int tsHeightIndex = 14;
49+
const int tsLocaleIndex = 15;
50+
const int tsBackgroundIndex = 16;
51+
const int tsForegroundIndex = 17;
52+
const int tsTextShadowsIndex = 18;
53+
const int tsFontFeaturesIndex = 19;
5354

5455
const int tsColorMask = 1 << tsColorIndex;
5556
const int tsTextDecorationMask = 1 << tsTextDecorationIndex;
@@ -59,6 +60,7 @@ const int tsTextDecorationThicknessMask = 1 << tsTextDecorationThicknessIndex;
5960
const int tsFontWeightMask = 1 << tsFontWeightIndex;
6061
const int tsFontStyleMask = 1 << tsFontStyleIndex;
6162
const int tsTextBaselineMask = 1 << tsTextBaselineIndex;
63+
const int tsLeadingDistributionMask = 1 << tsLeadingDistributionIndex;
6264
const int tsFontFamilyMask = 1 << tsFontFamilyIndex;
6365
const int tsFontSizeMask = 1 << tsFontSizeIndex;
6466
const int tsLetterSpacingMask = 1 << tsLetterSpacingIndex;
@@ -116,20 +118,20 @@ constexpr uint32_t kFontFeatureTagLength = 4;
116118
const int sFontWeightIndex = 0;
117119
const int sFontStyleIndex = 1;
118120
const int sFontFamilyIndex = 2;
119-
const int sFontSizeIndex = 3;
120-
const int sHeightIndex = 4;
121-
const int sLeadingIndex = 5;
122-
const int sForceStrutHeightIndex = 6;
123-
const int sForceStrutHeightValueIndex = 7;
121+
const int sLeadingDistributionIndex = 3;
122+
const int sFontSizeIndex = 4;
123+
const int sHeightIndex = 5;
124+
const int sLeadingIndex = 6;
125+
const int sForceStrutHeightIndex = 7;
124126

125127
const int sFontWeightMask = 1 << sFontWeightIndex;
126128
const int sFontStyleMask = 1 << sFontStyleIndex;
127129
const int sFontFamilyMask = 1 << sFontFamilyIndex;
130+
const int sLeadingDistributionMask = 1 << sLeadingDistributionIndex;
128131
const int sFontSizeMask = 1 << sFontSizeIndex;
129132
const int sHeightMask = 1 << sHeightIndex;
130133
const int sLeadingMask = 1 << sLeadingIndex;
131134
const int sForceStrutHeightMask = 1 << sForceStrutHeightIndex;
132-
const int sForceStrutHeightValueMask = 1 << sForceStrutHeightValueIndex;
133135

134136
} // namespace
135137

@@ -199,6 +201,10 @@ void decodeStrut(Dart_Handle strut_data,
199201
paragraph_style.strut_font_style =
200202
static_cast<txt::FontStyle>(uint8_data[byte_count++]);
201203
}
204+
if (mask & sLeadingDistributionMask) {
205+
paragraph_style.strut_has_leading_distribution_override = true;
206+
paragraph_style.strut_half_leading = uint8_data[byte_count++];
207+
}
202208

203209
std::vector<float> float_data;
204210
float_data.resize((byte_data.length_in_bytes() - byte_count) / 4);
@@ -216,10 +222,10 @@ void decodeStrut(Dart_Handle strut_data,
216222
if (mask & sLeadingMask) {
217223
paragraph_style.strut_leading = float_data[float_count++];
218224
}
219-
if (mask & sForceStrutHeightMask) {
220-
paragraph_style.force_strut_height =
221-
(mask & sForceStrutHeightValueMask) != 0;
222-
}
225+
226+
// The boolean is stored as the last bit in the bitmask, as null
227+
// and false have the same behavior.
228+
paragraph_style.force_strut_height = mask & sForceStrutHeightMask;
223229

224230
if (mask & sFontFamilyMask) {
225231
paragraph_style.strut_font_families = strut_font_families;
@@ -375,7 +381,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded,
375381
Dart_Handle foreground_data,
376382
Dart_Handle shadows_data,
377383
Dart_Handle font_features_data) {
378-
FML_DCHECK(encoded.num_elements() == 8);
384+
FML_DCHECK(encoded.num_elements() == 9);
379385

380386
int32_t mask = encoded[0];
381387

@@ -412,6 +418,11 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded,
412418
// property wasn't wired up either.
413419
}
414420

421+
style.has_leading_distribution_override = mask & tsLeadingDistributionMask;
422+
if (mask & tsLeadingDistributionMask) {
423+
style.half_leading = encoded[tsLeadingDistributionIndex];
424+
}
425+
415426
if (mask & (tsFontWeightMask | tsFontStyleMask | tsFontSizeMask |
416427
tsLetterSpacingMask | tsWordSpacingMask)) {
417428
if (mask & tsFontWeightMask) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,8 @@ class EngineStrutStyle implements ui.StrutStyle {
12111211
List<String>? fontFamilyFallback,
12121212
double? fontSize,
12131213
double? height,
1214+
//TODO(LongCatIsLooong): implement leadingDistribution.
1215+
ui.TextLeadingDistribution? leadingDistribution,
12141216
double? leading,
12151217
ui.FontWeight? fontWeight,
12161218
ui.FontStyle? fontStyle,
@@ -1219,6 +1221,7 @@ class EngineStrutStyle implements ui.StrutStyle {
12191221
_fontFamilyFallback = fontFamilyFallback,
12201222
_fontSize = fontSize,
12211223
_height = height,
1224+
_leadingDistribution = leadingDistribution,
12221225
_leading = leading,
12231226
_fontWeight = fontWeight,
12241227
_fontStyle = fontStyle,
@@ -1232,6 +1235,7 @@ class EngineStrutStyle implements ui.StrutStyle {
12321235
final ui.FontWeight? _fontWeight;
12331236
final ui.FontStyle? _fontStyle;
12341237
final bool? _forceStrutHeight;
1238+
final ui.TextLeadingDistribution? _leadingDistribution;
12351239

12361240
@override
12371241
bool operator ==(Object other) {
@@ -1246,6 +1250,7 @@ class EngineStrutStyle implements ui.StrutStyle {
12461250
&& other._fontSize == _fontSize
12471251
&& other._height == _height
12481252
&& other._leading == _leading
1253+
&& other._leadingDistribution == _leadingDistribution
12491254
&& other._fontWeight == _fontWeight
12501255
&& other._fontStyle == _fontStyle
12511256
&& other._forceStrutHeight == _forceStrutHeight
@@ -1259,6 +1264,7 @@ class EngineStrutStyle implements ui.StrutStyle {
12591264
_fontSize,
12601265
_height,
12611266
_leading,
1267+
_leadingDistribution,
12621268
_fontWeight,
12631269
_fontStyle,
12641270
_forceStrutHeight,

lib/web_ui/lib/src/ui/text.dart

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,18 +204,29 @@ enum TextDecorationStyle {
204204
wavy
205205
}
206206

207+
enum TextLeadingDistribution {
208+
proportional,
209+
even,
210+
}
211+
207212
class TextHeightBehavior {
208213
const TextHeightBehavior({
209214
this.applyHeightToFirstAscent = true,
210215
this.applyHeightToLastDescent = true,
216+
this.leadingDistribution = TextLeadingDistribution.proportional,
211217
});
212-
const TextHeightBehavior.fromEncoded(int encoded)
213-
: applyHeightToFirstAscent = (encoded & 0x1) == 0,
214-
applyHeightToLastDescent = (encoded & 0x2) == 0;
218+
TextHeightBehavior.fromEncoded(int encoded)
219+
: applyHeightToFirstAscent = (encoded & 0x1) == 0,
220+
applyHeightToLastDescent = (encoded & 0x2) == 0,
221+
leadingDistribution = TextLeadingDistribution.values[encoded >> 2];
215222
final bool applyHeightToFirstAscent;
216223
final bool applyHeightToLastDescent;
224+
final TextLeadingDistribution leadingDistribution;
225+
217226
int encode() {
218-
return (applyHeightToFirstAscent ? 0 : 1 << 0) | (applyHeightToLastDescent ? 0 : 1 << 1);
227+
return (applyHeightToFirstAscent ? 0 : 1 << 0)
228+
| (applyHeightToLastDescent ? 0 : 1 << 1)
229+
| (leadingDistribution.index << 2);
219230
}
220231

221232
@override
@@ -224,7 +235,8 @@ class TextHeightBehavior {
224235
return false;
225236
return other is TextHeightBehavior
226237
&& other.applyHeightToFirstAscent == applyHeightToFirstAscent
227-
&& other.applyHeightToLastDescent == applyHeightToLastDescent;
238+
&& other.applyHeightToLastDescent == applyHeightToLastDescent
239+
&& other.leadingDistribution == leadingDistribution;
228240
}
229241

230242
@override
@@ -239,7 +251,8 @@ class TextHeightBehavior {
239251
String toString() {
240252
return 'TextHeightBehavior('
241253
'applyHeightToFirstAscent: $applyHeightToFirstAscent, '
242-
'applyHeightToLastDescent: $applyHeightToLastDescent'
254+
'applyHeightToLastDescent: $applyHeightToLastDescent, '
255+
'leadingDistribution: $leadingDistribution'
243256
')';
244257
}
245258
}
@@ -260,6 +273,7 @@ abstract class TextStyle {
260273
double? letterSpacing,
261274
double? wordSpacing,
262275
double? height,
276+
TextLeadingDistribution? leadingDistribution,
263277
Locale? locale,
264278
Paint? background,
265279
Paint? foreground,
@@ -370,6 +384,7 @@ abstract class StrutStyle {
370384
List<String>? fontFamilyFallback,
371385
double? fontSize,
372386
double? height,
387+
TextLeadingDistribution? leadingDistribution,
373388
double? leading,
374389
FontWeight? fontWeight,
375390
FontStyle? fontStyle,

testing/dart/text_test.dart

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,37 @@ void main() {
4242
});
4343
});
4444

45+
group('TextStyle', () {
46+
final TextStyle ts0 = TextStyle(fontWeight: FontWeight.w700, fontSize: 12.0, height: 123.0);
47+
final TextStyle ts1 = TextStyle(color: const Color(0xFF00FF00), fontWeight: FontWeight.w800, fontSize: 10.0, height: 100.0);
48+
final TextStyle ts2 = TextStyle(fontFamily: 'test');
49+
final TextStyle ts3 = TextStyle(fontFamily: 'foo', fontFamilyFallback: <String>['Roboto', 'test']);
50+
final TextStyle ts4 = TextStyle(leadingDistribution: TextLeadingDistribution.even);
51+
52+
test('toString works', () {
53+
expect(
54+
ts0.toString(),
55+
equals('TextStyle(color: unspecified, decoration: unspecified, decorationColor: unspecified, decorationStyle: unspecified, decorationThickness: unspecified, fontWeight: FontWeight.w700, fontStyle: unspecified, textBaseline: unspecified, fontFamily: unspecified, fontFamilyFallback: unspecified, fontSize: 12.0, letterSpacing: unspecified, wordSpacing: unspecified, height: 123.0x, leadingDistribution: unspecified, locale: unspecified, background: unspecified, foreground: unspecified, shadows: unspecified, fontFeatures: unspecified)'),
56+
);
57+
expect(
58+
ts1.toString(),
59+
equals('TextStyle(color: Color(0xff00ff00), decoration: unspecified, decorationColor: unspecified, decorationStyle: unspecified, decorationThickness: unspecified, fontWeight: FontWeight.w800, fontStyle: unspecified, textBaseline: unspecified, fontFamily: unspecified, fontFamilyFallback: unspecified, fontSize: 10.0, letterSpacing: unspecified, wordSpacing: unspecified, height: 100.0x, leadingDistribution: unspecified, locale: unspecified, background: unspecified, foreground: unspecified, shadows: unspecified, fontFeatures: unspecified)'),
60+
);
61+
expect(
62+
ts2.toString(),
63+
equals('TextStyle(color: unspecified, decoration: unspecified, decorationColor: unspecified, decorationStyle: unspecified, decorationThickness: unspecified, fontWeight: unspecified, fontStyle: unspecified, textBaseline: unspecified, fontFamily: test, fontFamilyFallback: unspecified, fontSize: unspecified, letterSpacing: unspecified, wordSpacing: unspecified, height: unspecified, leadingDistribution: unspecified, locale: unspecified, background: unspecified, foreground: unspecified, shadows: unspecified, fontFeatures: unspecified)'),
64+
);
65+
expect(
66+
ts3.toString(),
67+
equals('TextStyle(color: unspecified, decoration: unspecified, decorationColor: unspecified, decorationStyle: unspecified, decorationThickness: unspecified, fontWeight: unspecified, fontStyle: unspecified, textBaseline: unspecified, fontFamily: foo, fontFamilyFallback: [Roboto, test], fontSize: unspecified, letterSpacing: unspecified, wordSpacing: unspecified, height: unspecified, leadingDistribution: unspecified, locale: unspecified, background: unspecified, foreground: unspecified, shadows: unspecified, fontFeatures: unspecified)'),
68+
);
69+
expect(
70+
ts4.toString(),
71+
equals('TextStyle(color: unspecified, decoration: unspecified, decorationColor: unspecified, decorationStyle: unspecified, decorationThickness: unspecified, fontWeight: unspecified, fontStyle: unspecified, textBaseline: unspecified, fontFamily: unspecified, fontFamilyFallback: unspecified, fontSize: unspecified, letterSpacing: unspecified, wordSpacing: unspecified, height: unspecified, leadingDistribution: TextLeadingDistribution.even, locale: unspecified, background: unspecified, foreground: unspecified, shadows: unspecified, fontFeatures: unspecified)'),
72+
);
73+
});
74+
});
75+
4576
group('TextHeightBehavior', () {
4677
const TextHeightBehavior behavior0 = TextHeightBehavior();
4778
const TextHeightBehavior behavior1 = TextHeightBehavior(
@@ -54,6 +85,10 @@ void main() {
5485
const TextHeightBehavior behavior3 = TextHeightBehavior(
5586
applyHeightToLastDescent: false
5687
);
88+
const TextHeightBehavior behavior4 = TextHeightBehavior(
89+
applyHeightToLastDescent: false,
90+
leadingDistribution: TextLeadingDistribution.even,
91+
);
5792

5893
test('default constructor works', () {
5994
expect(behavior0.applyHeightToFirstAscent, equals(true));
@@ -67,27 +102,33 @@ void main() {
67102

68103
expect(behavior3.applyHeightToFirstAscent, equals(true));
69104
expect(behavior3.applyHeightToLastDescent, equals(false));
105+
106+
expect(behavior4.applyHeightToLastDescent, equals(false));
107+
expect(behavior4.leadingDistribution, equals(TextLeadingDistribution.even));
70108
});
71109

72110
test('encode works', () {
73111
expect(behavior0.encode(), equals(0));
74112
expect(behavior1.encode(), equals(3));
75113
expect(behavior2.encode(), equals(1));
76114
expect(behavior3.encode(), equals(2));
115+
expect(behavior4.encode(), equals(6));
77116
});
78117

79118
test('decode works', () {
80-
expect(const TextHeightBehavior.fromEncoded(0), equals(behavior0));
81-
expect(const TextHeightBehavior.fromEncoded(3), equals(behavior1));
82-
expect(const TextHeightBehavior.fromEncoded(1), equals(behavior2));
83-
expect(const TextHeightBehavior.fromEncoded(2), equals(behavior3));
119+
expect(TextHeightBehavior.fromEncoded(0), equals(behavior0));
120+
expect(TextHeightBehavior.fromEncoded(3), equals(behavior1));
121+
expect(TextHeightBehavior.fromEncoded(1), equals(behavior2));
122+
expect(TextHeightBehavior.fromEncoded(2), equals(behavior3));
123+
expect(TextHeightBehavior.fromEncoded(6), equals(behavior4));
84124
});
85125

86126
test('toString works', () {
87-
expect(behavior0.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: true, applyHeightToLastDescent: true)'));
88-
expect(behavior1.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: false, applyHeightToLastDescent: false)'));
89-
expect(behavior2.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: false, applyHeightToLastDescent: true)'));
90-
expect(behavior3.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: true, applyHeightToLastDescent: false)'));
127+
expect(behavior0.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: true, applyHeightToLastDescent: true, leadingDistribution: TextLeadingDistribution.proportional)'));
128+
expect(behavior1.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: false, applyHeightToLastDescent: false, leadingDistribution: TextLeadingDistribution.proportional)'));
129+
expect(behavior2.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: false, applyHeightToLastDescent: true, leadingDistribution: TextLeadingDistribution.proportional)'));
130+
expect(behavior3.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: true, applyHeightToLastDescent: false, leadingDistribution: TextLeadingDistribution.proportional)'));
131+
expect(behavior4.toString(), equals('TextHeightBehavior(applyHeightToFirstAscent: true, applyHeightToLastDescent: false, leadingDistribution: TextLeadingDistribution.even)'));
91132
});
92133
});
93134

third_party/txt/src/txt/paragraph_style.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,18 @@ enum class TextDirection {
4141
ltr,
4242
};
4343

44-
// Allows disabling height adjustments to first line's ascent and the
45-
// last line's descent. If disabled, the line will use the default font
46-
// metric provided ascent/descent and ParagraphStyle.height will not take
47-
// effect.
44+
// Adjusts the leading over and under text.
45+
//
46+
// kDisableFirstAscent and kDisableLastDescent allow disabling height
47+
// adjustments to first line's ascent and the last line's descent. If disabled,
48+
// the line will use the default font metric provided ascent/descent and
49+
// ParagraphStyle.height or TextStyle.height will not take effect.
50+
//
51+
// kEvenLeading determines how the leading is distributed over and under the
52+
// text. When true, half of the leading is added to the top of the text and the
53+
// other half is added to the bottom of the text. Otherwise, instead of
54+
// distributing the space evenly, it's distributed proportionally to the font's
55+
// ascent/descent ratio.
4856
//
4957
// The default behavior is kAll where height adjustments are enabled for all
5058
// lines.
@@ -58,6 +66,7 @@ enum TextHeightBehavior {
5866
kDisableFirstAscent = 0x1,
5967
kDisableLastDescent = 0x2,
6068
kDisableAll = 0x1 | 0x2,
69+
kEvenLeading = 0x1 << 2,
6170
};
6271

6372
class ParagraphStyle {
@@ -69,8 +78,8 @@ class ParagraphStyle {
6978
std::string font_family = "";
7079
double font_size = 14;
7180
double height = 1;
72-
size_t text_height_behavior = TextHeightBehavior::kAll;
7381
bool has_height_override = false;
82+
size_t text_height_behavior = TextHeightBehavior::kAll;
7483

7584
// Strut properties. strut_enabled must be set to true for the rest of the
7685
// properties to take effect.
@@ -82,6 +91,8 @@ class ParagraphStyle {
8291
double strut_font_size = 14;
8392
double strut_height = 1;
8493
bool strut_has_height_override = false;
94+
bool strut_half_leading = false;
95+
bool strut_has_leading_distribution_override = false;
8596
double strut_leading = -1; // Negative to use font's default leading. [0,inf)
8697
// to use custom leading as a ratio of font size.
8798
bool force_strut_height = false;

0 commit comments

Comments
 (0)