Thanks to visit codestin.com
Credit goes to github.com

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

Commit 9c6e539

Browse files
Reland #43118 "Add a flag to ParagraphBuilder for rounding hack migration" (#43647)
real diff: aedc37a [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 7b7abd1 commit 9c6e539

File tree

12 files changed

+154
-11
lines changed

12 files changed

+154
-11
lines changed

lib/ui/dart_ui.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ typedef CanvasPath Path;
7878
V(Gradient::Create, 1) \
7979
V(ImageFilter::Create, 1) \
8080
V(ImageShader::Create, 1) \
81-
V(ParagraphBuilder::Create, 9) \
81+
V(ParagraphBuilder::Create, 10) \
8282
V(PathMeasure::Create, 3) \
8383
V(Path::Create, 1) \
8484
V(PictureRecorder::Create, 1) \

lib/ui/text.dart

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2798,7 +2798,7 @@ abstract class Paragraph {
27982798
/// This only returns a valid value if asserts are enabled, and must not be
27992799
/// used otherwise.
28002800
bool get debugDisposed;
2801-
}
2801+
}
28022802

28032803
@pragma('vm:entry-point')
28042804
base class _NativeParagraph extends NativeFieldWrapperClass1 implements Paragraph {
@@ -3015,6 +3015,28 @@ abstract class ParagraphBuilder {
30153015
/// [Paragraph].
30163016
factory ParagraphBuilder(ParagraphStyle style) = _NativeParagraphBuilder;
30173017

3018+
/// Whether the rounding hack enabled by default in SkParagraph and TextPainter
3019+
/// is disabled.
3020+
///
3021+
/// Do not rely on this getter as it exists for migration purposes only and
3022+
/// will soon be removed.
3023+
static bool get shouldDisableRoundingHack {
3024+
return const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
3025+
|| _roundingHackDisabledInDebugMode;
3026+
}
3027+
static bool _roundingHackDisabledInDebugMode = false;
3028+
3029+
/// Only works in debug mode. Do not call this method as it is for migration
3030+
/// purposes only and will soon be removed.
3031+
static void setDisableRoundingHack(bool disableRoundingHack) {
3032+
// bool.hasEnvironment does not work in internal tests so an additional flag
3033+
// is needed for tests.
3034+
assert(() {
3035+
_roundingHackDisabledInDebugMode = disableRoundingHack;
3036+
return true;
3037+
}());
3038+
}
3039+
30183040
/// The number of placeholders currently in the paragraph.
30193041
int get placeholderCount;
30203042

@@ -3132,11 +3154,12 @@ base class _NativeParagraphBuilder extends NativeFieldWrapperClass1 implements P
31323154
style._fontSize ?? 0,
31333155
style._height ?? 0,
31343156
style._ellipsis ?? '',
3135-
_encodeLocale(style._locale)
3157+
_encodeLocale(style._locale),
3158+
!ParagraphBuilder.shouldDisableRoundingHack,
31363159
);
31373160
}
31383161

3139-
@Native<Void Function(Handle, Handle, Handle, Handle, Handle, Double, Double, Handle, Handle)>(symbol: 'ParagraphBuilder::Create')
3162+
@Native<Void Function(Handle, Handle, Handle, Handle, Handle, Double, Double, Handle, Handle, Bool)>(symbol: 'ParagraphBuilder::Create')
31403163
external void _constructor(
31413164
Int32List encoded,
31423165
ByteData? strutData,
@@ -3145,7 +3168,8 @@ base class _NativeParagraphBuilder extends NativeFieldWrapperClass1 implements P
31453168
double fontSize,
31463169
double height,
31473170
String ellipsis,
3148-
String locale);
3171+
String locale,
3172+
bool applyRoundingHack);
31493173

31503174
@override
31513175
int get placeholderCount => _placeholderCount;

lib/ui/text/paragraph_builder.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,12 @@ void ParagraphBuilder::Create(Dart_Handle wrapper,
151151
double fontSize,
152152
double height,
153153
const std::u16string& ellipsis,
154-
const std::string& locale) {
154+
const std::string& locale,
155+
bool applyRoundingHack) {
155156
UIDartState::ThrowIfUIOperationsProhibited();
156157
auto res = fml::MakeRefCounted<ParagraphBuilder>(
157158
encoded_handle, strutData, fontFamily, strutFontFamilies, fontSize,
158-
height, ellipsis, locale);
159+
height, ellipsis, locale, applyRoundingHack);
159160
res->AssociateWithDartWrapper(wrapper);
160161
}
161162

@@ -230,7 +231,8 @@ ParagraphBuilder::ParagraphBuilder(
230231
double fontSize,
231232
double height,
232233
const std::u16string& ellipsis,
233-
const std::string& locale) {
234+
const std::string& locale,
235+
bool applyRoundingHack) {
234236
int32_t mask = 0;
235237
txt::ParagraphStyle style;
236238
{
@@ -291,6 +293,7 @@ ParagraphBuilder::ParagraphBuilder(
291293
if (mask & kPSLocaleMask) {
292294
style.locale = locale;
293295
}
296+
style.apply_rounding_hack = applyRoundingHack;
294297

295298
FontCollection& font_collection = UIDartState::Current()
296299
->platform_configuration()

lib/ui/text/paragraph_builder.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class ParagraphBuilder : public RefCountedDartWrappable<ParagraphBuilder> {
3030
double fontSize,
3131
double height,
3232
const std::u16string& ellipsis,
33-
const std::string& locale);
33+
const std::string& locale,
34+
bool applyRoundingHack);
3435

3536
~ParagraphBuilder() override;
3637

@@ -76,7 +77,8 @@ class ParagraphBuilder : public RefCountedDartWrappable<ParagraphBuilder> {
7677
double fontSize,
7778
double height,
7879
const std::u16string& ellipsis,
79-
const std::string& locale);
80+
const std::string& locale,
81+
bool applyRoundingHack);
8082

8183
std::unique_ptr<txt::ParagraphBuilder> m_paragraphBuilder;
8284
};

lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2722,6 +2722,8 @@ extension SkParagraphStylePropertiesExtension on SkParagraphStyleProperties {
27222722
@JS('replaceTabCharacters')
27232723
external set _replaceTabCharacters(JSBoolean? bool);
27242724
set replaceTabCharacters(bool? bool) => _replaceTabCharacters = bool?.toJS;
2725+
2726+
external set applyRoundingHack(bool applyRoundingHack);
27252727
}
27262728

27272729
@JS()

lib/web_ui/lib/src/engine/canvaskit/renderer.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ class CanvasKitRenderer implements Renderer {
328328
strutStyle: strutStyle,
329329
ellipsis: ellipsis,
330330
locale: locale,
331+
applyRoundingHack: !ui.ParagraphBuilder.shouldDisableRoundingHack,
331332
);
332333

333334
@override

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class CkParagraphStyle implements ui.ParagraphStyle {
3333
ui.StrutStyle? strutStyle,
3434
String? ellipsis,
3535
ui.Locale? locale,
36+
bool applyRoundingHack = true,
3637
}) : skParagraphStyle = toSkParagraphStyle(
3738
textAlign,
3839
textDirection,
@@ -46,6 +47,7 @@ class CkParagraphStyle implements ui.ParagraphStyle {
4647
strutStyle,
4748
ellipsis,
4849
locale,
50+
applyRoundingHack,
4951
),
5052
_fontFamily = _effectiveFontFamily(fontFamily),
5153
_fontSize = fontSize,
@@ -145,6 +147,7 @@ class CkParagraphStyle implements ui.ParagraphStyle {
145147
ui.StrutStyle? strutStyle,
146148
String? ellipsis,
147149
ui.Locale? locale,
150+
bool applyRoundingHack,
148151
) {
149152
final SkParagraphStyleProperties properties = SkParagraphStyleProperties();
150153

@@ -181,6 +184,7 @@ class CkParagraphStyle implements ui.ParagraphStyle {
181184
properties.replaceTabCharacters = true;
182185
properties.textStyle = toSkTextStyleProperties(
183186
fontFamily, fontSize, height, fontWeight, fontStyle);
187+
properties.applyRoundingHack = applyRoundingHack;
184188

185189
return canvasKit.ParagraphStyle(properties);
186190
}

lib/web_ui/lib/text.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,19 @@ abstract class Paragraph {
685685
abstract class ParagraphBuilder {
686686
factory ParagraphBuilder(ParagraphStyle style) =>
687687
engine.renderer.createParagraphBuilder(style);
688+
689+
static bool get shouldDisableRoundingHack {
690+
return const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
691+
|| _roundingHackDisabledInDebugMode;
692+
}
693+
static bool _roundingHackDisabledInDebugMode = false;
694+
static void setDisableRoundingHack(bool disableRoundingHack) {
695+
assert(() {
696+
_roundingHackDisabledInDebugMode = disableRoundingHack;
697+
return true;
698+
}());
699+
}
700+
688701
void pushStyle(TextStyle style);
689702
void pop();
690703
void addText(String text);

lib/web_ui/test/canvaskit/text_test.dart

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,51 @@ void testMain() {
123123
}
124124
});
125125
});
126+
127+
test('applyRoundingHack works', () {
128+
bool assertsEnabled = false;
129+
assert(() {
130+
assertsEnabled = true;
131+
return true;
132+
}());
133+
if (!assertsEnabled){
134+
return;
135+
}
136+
137+
const double fontSize = 1.25;
138+
const String text = '12345';
139+
assert((fontSize * text.length).truncate() != fontSize * text.length);
140+
final bool roundingHackWasDisabled = ui.ParagraphBuilder.shouldDisableRoundingHack;
141+
ui.ParagraphBuilder.setDisableRoundingHack(true);
142+
final ui.ParagraphBuilder builder = ui.ParagraphBuilder(
143+
ui.ParagraphStyle(fontSize: fontSize, fontFamily: 'FlutterTest'),
144+
);
145+
builder.addText(text);
146+
final ui.Paragraph paragraph = builder.build()
147+
..layout(const ui.ParagraphConstraints(width: text.length * fontSize));
148+
149+
expect(paragraph.maxIntrinsicWidth, text.length * fontSize);
150+
switch (paragraph.computeLineMetrics()) {
151+
case [ui.LineMetrics(width: final double width)]:
152+
expect(width, text.length * fontSize);
153+
case final List<ui.LineMetrics> metrics:
154+
expect(metrics, hasLength(1));
155+
}
156+
ui.ParagraphBuilder.setDisableRoundingHack(roundingHackWasDisabled);
157+
});
158+
159+
test('rounding hack applied by default', () {
160+
const double fontSize = 1.25;
161+
const String text = '12345';
162+
assert((fontSize * text.length).truncate() != fontSize * text.length);
163+
expect(ui.ParagraphBuilder.shouldDisableRoundingHack, isFalse);
164+
final ui.ParagraphBuilder builder = ui.ParagraphBuilder(ui.ParagraphStyle(fontSize: fontSize, fontFamily: 'FlutterTest'));
165+
builder.addText(text);
166+
final ui.Paragraph paragraph = builder.build()
167+
..layout(const ui.ParagraphConstraints(width: text.length * fontSize));
168+
expect(paragraph.computeLineMetrics().length, greaterThan(1));
169+
});
170+
126171
// TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520
127172
}, skip: isSafari || isFirefox);
128-
129173
}

testing/dart/paragraph_test.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,45 @@ void main() {
233233
expect(callback, throwsStateError);
234234
}
235235
});
236+
237+
test('disableRoundingHack works in tests', () {
238+
bool assertsEnabled = false;
239+
assert(() {
240+
assertsEnabled = true;
241+
return true;
242+
}());
243+
if (!assertsEnabled){
244+
return;
245+
}
246+
const double fontSize = 1.25;
247+
const String text = '12345';
248+
assert((fontSize * text.length).truncate() != fontSize * text.length);
249+
final bool roundingHackWasDisabled = ParagraphBuilder.shouldDisableRoundingHack;
250+
ParagraphBuilder.setDisableRoundingHack(true);
251+
final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle(fontSize: fontSize));
252+
builder.addText(text);
253+
final Paragraph paragraph = builder.build()
254+
..layout(const ParagraphConstraints(width: text.length * fontSize));
255+
256+
expect(paragraph.maxIntrinsicWidth, text.length * fontSize);
257+
switch (paragraph.computeLineMetrics()) {
258+
case [LineMetrics(width: final double width)]:
259+
expect(width, text.length * fontSize);
260+
case final List<LineMetrics> metrics:
261+
expect(metrics, hasLength(1));
262+
}
263+
ParagraphBuilder.setDisableRoundingHack(roundingHackWasDisabled);
264+
});
265+
266+
test('rounding hack applied by default', () {
267+
const double fontSize = 1.25;
268+
const String text = '12345';
269+
assert((fontSize * text.length).truncate() != fontSize * text.length);
270+
expect(ParagraphBuilder.shouldDisableRoundingHack, isFalse);
271+
final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle(fontSize: fontSize));
272+
builder.addText(text);
273+
final Paragraph paragraph = builder.build()
274+
..layout(const ParagraphConstraints(width: text.length * fontSize));
275+
expect(paragraph.computeLineMetrics().length, greaterThan(1));
276+
});
236277
}

third_party/txt/src/skia/paragraph_builder_skia.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ skt::ParagraphStyle ParagraphBuilderSkia::TxtToSkia(const ParagraphStyle& txt) {
138138

139139
skia.turnHintingOff();
140140
skia.setReplaceTabCharacters(true);
141+
skia.setApplyRoundingHack(txt.apply_rounding_hack);
141142

142143
return skia;
143144
}

third_party/txt/src/txt/paragraph_style.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ class ParagraphStyle {
9595
std::u16string ellipsis;
9696
std::string locale;
9797

98+
// Temporary flag that indicates whether the Paragraph should report its
99+
// metrics with rounding hacks applied.
100+
//
101+
// This flag currently defaults to true and will be flipped to false once the
102+
// migration is complete.
103+
// TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/31707
104+
bool apply_rounding_hack = true;
105+
98106
TextStyle GetTextStyle() const;
99107

100108
bool unlimited_lines() const;

0 commit comments

Comments
 (0)