Reland #43118 "Add a flag to ParagraphBuilder for rounding hack migration" (flutter/engine#43647)
real diff: aedc37a3e0
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
@@ -78,7 +78,7 @@ typedef CanvasPath Path;
|
||||
V(Gradient::Create, 1) \
|
||||
V(ImageFilter::Create, 1) \
|
||||
V(ImageShader::Create, 1) \
|
||||
V(ParagraphBuilder::Create, 9) \
|
||||
V(ParagraphBuilder::Create, 10) \
|
||||
V(PathMeasure::Create, 3) \
|
||||
V(Path::Create, 1) \
|
||||
V(PictureRecorder::Create, 1) \
|
||||
|
||||
@@ -2798,7 +2798,7 @@ abstract class Paragraph {
|
||||
/// This only returns a valid value if asserts are enabled, and must not be
|
||||
/// used otherwise.
|
||||
bool get debugDisposed;
|
||||
}
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
base class _NativeParagraph extends NativeFieldWrapperClass1 implements Paragraph {
|
||||
@@ -3015,6 +3015,28 @@ abstract class ParagraphBuilder {
|
||||
/// [Paragraph].
|
||||
factory ParagraphBuilder(ParagraphStyle style) = _NativeParagraphBuilder;
|
||||
|
||||
/// Whether the rounding hack enabled by default in SkParagraph and TextPainter
|
||||
/// is disabled.
|
||||
///
|
||||
/// Do not rely on this getter as it exists for migration purposes only and
|
||||
/// will soon be removed.
|
||||
static bool get shouldDisableRoundingHack {
|
||||
return const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
|
||||
|| _roundingHackDisabledInDebugMode;
|
||||
}
|
||||
static bool _roundingHackDisabledInDebugMode = false;
|
||||
|
||||
/// Only works in debug mode. Do not call this method as it is for migration
|
||||
/// purposes only and will soon be removed.
|
||||
static void setDisableRoundingHack(bool disableRoundingHack) {
|
||||
// bool.hasEnvironment does not work in internal tests so an additional flag
|
||||
// is needed for tests.
|
||||
assert(() {
|
||||
_roundingHackDisabledInDebugMode = disableRoundingHack;
|
||||
return true;
|
||||
}());
|
||||
}
|
||||
|
||||
/// The number of placeholders currently in the paragraph.
|
||||
int get placeholderCount;
|
||||
|
||||
@@ -3132,11 +3154,12 @@ base class _NativeParagraphBuilder extends NativeFieldWrapperClass1 implements P
|
||||
style._fontSize ?? 0,
|
||||
style._height ?? 0,
|
||||
style._ellipsis ?? '',
|
||||
_encodeLocale(style._locale)
|
||||
_encodeLocale(style._locale),
|
||||
!ParagraphBuilder.shouldDisableRoundingHack,
|
||||
);
|
||||
}
|
||||
|
||||
@Native<Void Function(Handle, Handle, Handle, Handle, Handle, Double, Double, Handle, Handle)>(symbol: 'ParagraphBuilder::Create')
|
||||
@Native<Void Function(Handle, Handle, Handle, Handle, Handle, Double, Double, Handle, Handle, Bool)>(symbol: 'ParagraphBuilder::Create')
|
||||
external void _constructor(
|
||||
Int32List encoded,
|
||||
ByteData? strutData,
|
||||
@@ -3145,7 +3168,8 @@ base class _NativeParagraphBuilder extends NativeFieldWrapperClass1 implements P
|
||||
double fontSize,
|
||||
double height,
|
||||
String ellipsis,
|
||||
String locale);
|
||||
String locale,
|
||||
bool applyRoundingHack);
|
||||
|
||||
@override
|
||||
int get placeholderCount => _placeholderCount;
|
||||
|
||||
@@ -151,11 +151,12 @@ void ParagraphBuilder::Create(Dart_Handle wrapper,
|
||||
double fontSize,
|
||||
double height,
|
||||
const std::u16string& ellipsis,
|
||||
const std::string& locale) {
|
||||
const std::string& locale,
|
||||
bool applyRoundingHack) {
|
||||
UIDartState::ThrowIfUIOperationsProhibited();
|
||||
auto res = fml::MakeRefCounted<ParagraphBuilder>(
|
||||
encoded_handle, strutData, fontFamily, strutFontFamilies, fontSize,
|
||||
height, ellipsis, locale);
|
||||
height, ellipsis, locale, applyRoundingHack);
|
||||
res->AssociateWithDartWrapper(wrapper);
|
||||
}
|
||||
|
||||
@@ -230,7 +231,8 @@ ParagraphBuilder::ParagraphBuilder(
|
||||
double fontSize,
|
||||
double height,
|
||||
const std::u16string& ellipsis,
|
||||
const std::string& locale) {
|
||||
const std::string& locale,
|
||||
bool applyRoundingHack) {
|
||||
int32_t mask = 0;
|
||||
txt::ParagraphStyle style;
|
||||
{
|
||||
@@ -291,6 +293,7 @@ ParagraphBuilder::ParagraphBuilder(
|
||||
if (mask & kPSLocaleMask) {
|
||||
style.locale = locale;
|
||||
}
|
||||
style.apply_rounding_hack = applyRoundingHack;
|
||||
|
||||
FontCollection& font_collection = UIDartState::Current()
|
||||
->platform_configuration()
|
||||
|
||||
@@ -30,7 +30,8 @@ class ParagraphBuilder : public RefCountedDartWrappable<ParagraphBuilder> {
|
||||
double fontSize,
|
||||
double height,
|
||||
const std::u16string& ellipsis,
|
||||
const std::string& locale);
|
||||
const std::string& locale,
|
||||
bool applyRoundingHack);
|
||||
|
||||
~ParagraphBuilder() override;
|
||||
|
||||
@@ -76,7 +77,8 @@ class ParagraphBuilder : public RefCountedDartWrappable<ParagraphBuilder> {
|
||||
double fontSize,
|
||||
double height,
|
||||
const std::u16string& ellipsis,
|
||||
const std::string& locale);
|
||||
const std::string& locale,
|
||||
bool applyRoundingHack);
|
||||
|
||||
std::unique_ptr<txt::ParagraphBuilder> m_paragraphBuilder;
|
||||
};
|
||||
|
||||
@@ -2722,6 +2722,8 @@ extension SkParagraphStylePropertiesExtension on SkParagraphStyleProperties {
|
||||
@JS('replaceTabCharacters')
|
||||
external set _replaceTabCharacters(JSBoolean? bool);
|
||||
set replaceTabCharacters(bool? bool) => _replaceTabCharacters = bool?.toJS;
|
||||
|
||||
external set applyRoundingHack(bool applyRoundingHack);
|
||||
}
|
||||
|
||||
@JS()
|
||||
|
||||
@@ -328,6 +328,7 @@ class CanvasKitRenderer implements Renderer {
|
||||
strutStyle: strutStyle,
|
||||
ellipsis: ellipsis,
|
||||
locale: locale,
|
||||
applyRoundingHack: !ui.ParagraphBuilder.shouldDisableRoundingHack,
|
||||
);
|
||||
|
||||
@override
|
||||
|
||||
@@ -33,6 +33,7 @@ class CkParagraphStyle implements ui.ParagraphStyle {
|
||||
ui.StrutStyle? strutStyle,
|
||||
String? ellipsis,
|
||||
ui.Locale? locale,
|
||||
bool applyRoundingHack = true,
|
||||
}) : skParagraphStyle = toSkParagraphStyle(
|
||||
textAlign,
|
||||
textDirection,
|
||||
@@ -46,6 +47,7 @@ class CkParagraphStyle implements ui.ParagraphStyle {
|
||||
strutStyle,
|
||||
ellipsis,
|
||||
locale,
|
||||
applyRoundingHack,
|
||||
),
|
||||
_fontFamily = _effectiveFontFamily(fontFamily),
|
||||
_fontSize = fontSize,
|
||||
@@ -145,6 +147,7 @@ class CkParagraphStyle implements ui.ParagraphStyle {
|
||||
ui.StrutStyle? strutStyle,
|
||||
String? ellipsis,
|
||||
ui.Locale? locale,
|
||||
bool applyRoundingHack,
|
||||
) {
|
||||
final SkParagraphStyleProperties properties = SkParagraphStyleProperties();
|
||||
|
||||
@@ -181,6 +184,7 @@ class CkParagraphStyle implements ui.ParagraphStyle {
|
||||
properties.replaceTabCharacters = true;
|
||||
properties.textStyle = toSkTextStyleProperties(
|
||||
fontFamily, fontSize, height, fontWeight, fontStyle);
|
||||
properties.applyRoundingHack = applyRoundingHack;
|
||||
|
||||
return canvasKit.ParagraphStyle(properties);
|
||||
}
|
||||
|
||||
@@ -685,6 +685,19 @@ abstract class Paragraph {
|
||||
abstract class ParagraphBuilder {
|
||||
factory ParagraphBuilder(ParagraphStyle style) =>
|
||||
engine.renderer.createParagraphBuilder(style);
|
||||
|
||||
static bool get shouldDisableRoundingHack {
|
||||
return const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
|
||||
|| _roundingHackDisabledInDebugMode;
|
||||
}
|
||||
static bool _roundingHackDisabledInDebugMode = false;
|
||||
static void setDisableRoundingHack(bool disableRoundingHack) {
|
||||
assert(() {
|
||||
_roundingHackDisabledInDebugMode = disableRoundingHack;
|
||||
return true;
|
||||
}());
|
||||
}
|
||||
|
||||
void pushStyle(TextStyle style);
|
||||
void pop();
|
||||
void addText(String text);
|
||||
|
||||
@@ -123,7 +123,51 @@ void testMain() {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('applyRoundingHack works', () {
|
||||
bool assertsEnabled = false;
|
||||
assert(() {
|
||||
assertsEnabled = true;
|
||||
return true;
|
||||
}());
|
||||
if (!assertsEnabled){
|
||||
return;
|
||||
}
|
||||
|
||||
const double fontSize = 1.25;
|
||||
const String text = '12345';
|
||||
assert((fontSize * text.length).truncate() != fontSize * text.length);
|
||||
final bool roundingHackWasDisabled = ui.ParagraphBuilder.shouldDisableRoundingHack;
|
||||
ui.ParagraphBuilder.setDisableRoundingHack(true);
|
||||
final ui.ParagraphBuilder builder = ui.ParagraphBuilder(
|
||||
ui.ParagraphStyle(fontSize: fontSize, fontFamily: 'FlutterTest'),
|
||||
);
|
||||
builder.addText(text);
|
||||
final ui.Paragraph paragraph = builder.build()
|
||||
..layout(const ui.ParagraphConstraints(width: text.length * fontSize));
|
||||
|
||||
expect(paragraph.maxIntrinsicWidth, text.length * fontSize);
|
||||
switch (paragraph.computeLineMetrics()) {
|
||||
case [ui.LineMetrics(width: final double width)]:
|
||||
expect(width, text.length * fontSize);
|
||||
case final List<ui.LineMetrics> metrics:
|
||||
expect(metrics, hasLength(1));
|
||||
}
|
||||
ui.ParagraphBuilder.setDisableRoundingHack(roundingHackWasDisabled);
|
||||
});
|
||||
|
||||
test('rounding hack applied by default', () {
|
||||
const double fontSize = 1.25;
|
||||
const String text = '12345';
|
||||
assert((fontSize * text.length).truncate() != fontSize * text.length);
|
||||
expect(ui.ParagraphBuilder.shouldDisableRoundingHack, isFalse);
|
||||
final ui.ParagraphBuilder builder = ui.ParagraphBuilder(ui.ParagraphStyle(fontSize: fontSize, fontFamily: 'FlutterTest'));
|
||||
builder.addText(text);
|
||||
final ui.Paragraph paragraph = builder.build()
|
||||
..layout(const ui.ParagraphConstraints(width: text.length * fontSize));
|
||||
expect(paragraph.computeLineMetrics().length, greaterThan(1));
|
||||
});
|
||||
|
||||
// TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520
|
||||
}, skip: isSafari || isFirefox);
|
||||
|
||||
}
|
||||
|
||||
@@ -233,4 +233,45 @@ void main() {
|
||||
expect(callback, throwsStateError);
|
||||
}
|
||||
});
|
||||
|
||||
test('disableRoundingHack works in tests', () {
|
||||
bool assertsEnabled = false;
|
||||
assert(() {
|
||||
assertsEnabled = true;
|
||||
return true;
|
||||
}());
|
||||
if (!assertsEnabled){
|
||||
return;
|
||||
}
|
||||
const double fontSize = 1.25;
|
||||
const String text = '12345';
|
||||
assert((fontSize * text.length).truncate() != fontSize * text.length);
|
||||
final bool roundingHackWasDisabled = ParagraphBuilder.shouldDisableRoundingHack;
|
||||
ParagraphBuilder.setDisableRoundingHack(true);
|
||||
final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle(fontSize: fontSize));
|
||||
builder.addText(text);
|
||||
final Paragraph paragraph = builder.build()
|
||||
..layout(const ParagraphConstraints(width: text.length * fontSize));
|
||||
|
||||
expect(paragraph.maxIntrinsicWidth, text.length * fontSize);
|
||||
switch (paragraph.computeLineMetrics()) {
|
||||
case [LineMetrics(width: final double width)]:
|
||||
expect(width, text.length * fontSize);
|
||||
case final List<LineMetrics> metrics:
|
||||
expect(metrics, hasLength(1));
|
||||
}
|
||||
ParagraphBuilder.setDisableRoundingHack(roundingHackWasDisabled);
|
||||
});
|
||||
|
||||
test('rounding hack applied by default', () {
|
||||
const double fontSize = 1.25;
|
||||
const String text = '12345';
|
||||
assert((fontSize * text.length).truncate() != fontSize * text.length);
|
||||
expect(ParagraphBuilder.shouldDisableRoundingHack, isFalse);
|
||||
final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle(fontSize: fontSize));
|
||||
builder.addText(text);
|
||||
final Paragraph paragraph = builder.build()
|
||||
..layout(const ParagraphConstraints(width: text.length * fontSize));
|
||||
expect(paragraph.computeLineMetrics().length, greaterThan(1));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,6 +138,7 @@ skt::ParagraphStyle ParagraphBuilderSkia::TxtToSkia(const ParagraphStyle& txt) {
|
||||
|
||||
skia.turnHintingOff();
|
||||
skia.setReplaceTabCharacters(true);
|
||||
skia.setApplyRoundingHack(txt.apply_rounding_hack);
|
||||
|
||||
return skia;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,14 @@ class ParagraphStyle {
|
||||
std::u16string ellipsis;
|
||||
std::string locale;
|
||||
|
||||
// Temporary flag that indicates whether the Paragraph should report its
|
||||
// metrics with rounding hacks applied.
|
||||
//
|
||||
// This flag currently defaults to true and will be flipped to false once the
|
||||
// migration is complete.
|
||||
// TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/31707
|
||||
bool apply_rounding_hack = true;
|
||||
|
||||
TextStyle GetTextStyle() const;
|
||||
|
||||
bool unlimited_lines() const;
|
||||
|
||||
Reference in New Issue
Block a user