Unverified Commit 43de3365 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Remove rounding from TextPainter (#127099)

To opt-in, run the tests with: `SKPARAGRAPH_REMOVE_ROUNDING_HACK=1 flutter test --dart-define=SKPARAGRAPH_REMOVE_ROUNDING_HACK=1 `

Migration plans:
1. Turn the flags on in CI, migrate customer tests if needed
1. Migrate internal customers
2. Remove the flag from skparagraph. Remove the framework flag with a manual engine roll.

Also fixes https://github.com/flutter/flutter/issues/52038
parent 07f7ffde
......@@ -271,9 +271,13 @@ class _TextLayout {
// object when it's no logner needed.
ui.Paragraph _paragraph;
/// Whether to enable the rounding in _applyFloatingPointHack and SkParagraph.
static const bool _shouldApplyFloatingPointHack = !bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK');
// TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/31707
// remove this hack as well as the flooring in `layout`.
static double _applyFloatingPointHack(double layoutValue) => layoutValue.ceilToDouble();
@pragma('vm:prefer-inline')
static double _applyFloatingPointHack(double layoutValue) => _shouldApplyFloatingPointHack ? layoutValue.ceilToDouble() : layoutValue;
/// Whether this layout has been invalidated and disposed.
///
......
......@@ -595,14 +595,19 @@ class TextStyle with Diagnosticable {
// in the [fontFamilyFallback] getter.
final String? _package;
/// The size of glyphs (in logical pixels) to use when painting the text.
/// The size of fonts (in logical pixels) to use when painting the text.
///
/// The value specified matches the dimension of the
/// [em square](https://fonts.google.com/knowledge/glossary/em) of the
/// underlying font, and more often then not isn't exactly the height or the
/// width of glyphs in the font.
///
/// During painting, the [fontSize] is multiplied by the current
/// `textScaleFactor` to let users make it easier to read text by increasing
/// its size.
///
/// [getParagraphStyle] will default to 14 logical pixels if the font size
/// isn't specified here.
/// The [getParagraphStyle] method defaults to 14 logical pixels if [fontSize]
/// is set to null.
final double? fontSize;
/// The typeface thickness to use when painting the text (e.g., bold).
......
......@@ -145,11 +145,17 @@ void main() {
// place.
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).first),
const Offset(342.33420100808144, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 342.547737105096302912 : 342.33420100808144,
13.5,
),
);
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).last),
const Offset(342.33420100808144, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 342.547737105096302912 : 342.33420100808144,
13.5,
),
);
});
......@@ -166,11 +172,17 @@ void main() {
// Same as LTR but more to the right now.
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).first),
const Offset(357.66579899191856, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 357.912261979376353338 : 357.66579899191856,
13.5,
),
);
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).last),
const Offset(357.66579899191856, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 357.912261979376353338 : 357.66579899191856,
13.5,
),
);
});
......@@ -356,9 +368,13 @@ void main() {
final RenderParagraph bottomMiddle =
tester.renderObject(flying(tester, find.text('Page 1')).first);
expect(bottomMiddle.text.style!.color, const Color(0xff000306));
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).first),
const Offset(342.33420100808144, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 342.547737105096302912 : 342.33420100808144,
13.5,
),
);
// The top back label is styled exactly the same way. But the opacity tweens
......@@ -368,7 +384,10 @@ void main() {
expect(topBackLabel.text.style!.color, const Color(0xff000306));
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).last),
const Offset(342.33420100808144, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 342.547737105096302912 : 342.33420100808144,
13.5,
),
);
}
......@@ -403,7 +422,10 @@ void main() {
expect(bottomMiddle.text.style!.color, const Color(0xff000306));
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).first),
const Offset(357.66579899191856, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 357.912261979376353338 : 357.66579899191856,
13.5,
),
);
// The top back label is styled exactly the same way. But the opacity tweens
......@@ -413,7 +435,10 @@ void main() {
expect(topBackLabel.text.style!.color, const Color(0xff000306));
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).last),
const Offset(357.66579899191856, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 357.912261979376353338 : 357.66579899191856,
13.5,
),
);
}
......@@ -711,11 +736,17 @@ void main() {
);
// Come in from the right and fade in.
checkOpacity(tester, backChevron, 0.0);
expect(tester.getTopLeft(backChevron), const Offset(88.04496401548386, 7.0));
expect(tester.getTopLeft(backChevron), const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 87.2460581221158690823 : 88.04496401548386,
7.0,
));
await tester.pump(const Duration(milliseconds: 200));
checkOpacity(tester, backChevron, 0.09497911669313908);
expect(tester.getTopLeft(backChevron), const Offset(31.055883467197418, 7.0));
expect(tester.getTopLeft(backChevron), const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 30.8718595298545324113 : 31.055883467197418,
7.0,
));
});
testWidgets('First appearance of back chevron fades in from the left in RTL', (WidgetTester tester) async {
......@@ -753,14 +784,20 @@ void main() {
checkOpacity(tester, backChevron, 0.0);
expect(
tester.getTopRight(backChevron),
const Offset(685.9550359845161, 7.0),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 687.163941725296126606 : 685.9550359845161,
7.0,
),
);
await tester.pump(const Duration(milliseconds: 200));
checkOpacity(tester, backChevron, 0.09497911669313908);
expect(
tester.getTopRight(backChevron),
const Offset(742.9441165328026, 7.0),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 743.538140317557690651 : 742.9441165328026,
7.0,
),
);
});
......@@ -862,14 +899,20 @@ void main() {
checkOpacity(tester, flying(tester, find.text('custom')), 0.9280824661254883);
expect(
tester.getTopLeft(flying(tester, find.text('custom'))),
const Offset(684.0, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 684.459999084472656250 : 684.0,
13.5,
),
);
await tester.pump(const Duration(milliseconds: 150));
checkOpacity(tester, flying(tester, find.text('custom')), 0.0);
expect(
tester.getTopLeft(flying(tester, find.text('custom'))),
const Offset(684.0, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 684.459999084472656250 : 684.0,
13.5,
),
);
});
......@@ -898,14 +941,20 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Page 1')), 0.7952219992876053);
expect(
tester.getTopLeft(flying(tester, find.text('Page 1'))),
const Offset(41.71033692359924, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 41.3003370761871337891 : 41.71033692359924,
13.5,
),
);
await tester.pump(const Duration(milliseconds: 200));
checkOpacity(tester, flying(tester, find.text('Page 1')), 0.0);
expect(
tester.getTopLeft(flying(tester, find.text('Page 1'))),
const Offset(-258.2321922779083, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? -258.642192125320434570 : -258.2321922779083,
13.5,
),
);
});
......@@ -935,7 +984,10 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Page 1')), 0.7952219992876053);
expect(
tester.getTopRight(flying(tester, find.text('Page 1'))),
const Offset(758.2896630764008, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 758.699662923812866211 : 758.2896630764008,
13.5,
),
);
await tester.pump(const Duration(milliseconds: 200));
......@@ -943,7 +995,10 @@ void main() {
expect(
tester.getTopRight(flying(tester, find.text('Page 1'))),
// >1000. It's now off the screen.
const Offset(1058.2321922779083, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 1058.64219212532043457 : 1058.2321922779083,
13.5,
),
);
});
......@@ -963,25 +1018,39 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Page 1')).first, 0.9280824661254883);
checkOpacity(tester, flying(tester, find.text('Page 1')).last, 0.0);
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).first),
const Offset(16.926069676876068, 52.73951627314091),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 16.9155227761479522997 : 16.926069676876068,
52.73951627314091,
),
);
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).last),
const Offset(16.926069676876068, 52.73951627314091),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 16.9155227761479522997 : 16.926069676876068,
52.73951627314091,
),
);
await tester.pump(const Duration(milliseconds: 200));
checkOpacity(tester, flying(tester, find.text('Page 1')).first, 0.0);
checkOpacity(tester, flying(tester, find.text('Page 1')).last, 0.4604858811944723);
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).first),
const Offset(43.92089730501175, 22.49655644595623),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 43.6029094262710827934 : 43.92089730501175,
22.49655644595623,
),
);
expect(
tester.getTopLeft(flying(tester, find.text('Page 1')).last),
const Offset(43.92089730501175, 22.49655644595623),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 43.6029094262710827934 : 43.92089730501175,
22.49655644595623,
),
);
});
......@@ -1003,11 +1072,17 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Back')), 0.0);
expect(
tester.getTopLeft(flying(tester, find.text('A title too long to fit'))),
const Offset(16.926069676876068, 52.73951627314091),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 16.9155227761479522997 : 16.926069676876068,
52.73951627314091,
),
);
expect(
tester.getTopLeft(flying(tester, find.text('Back'))),
const Offset(16.926069676876068, 52.73951627314091),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 16.9155227761479522997 : 16.926069676876068,
52.73951627314091,
),
);
await tester.pump(const Duration(milliseconds: 200));
......@@ -1015,11 +1090,17 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Back')), 0.4604858811944723);
expect(
tester.getTopLeft(flying(tester, find.text('A title too long to fit'))),
const Offset(43.92089730501175, 22.49655644595623),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 43.6029094262710827934 : 43.92089730501175,
22.49655644595623,
),
);
expect(
tester.getTopLeft(flying(tester, find.text('Back'))),
const Offset(43.92089730501175, 22.49655644595623),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 43.6029094262710827934 : 43.92089730501175,
22.49655644595623,
),
);
});
......@@ -1075,7 +1156,10 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Page 2')), 0.0);
expect(
tester.getTopLeft(flying(tester, find.text('Page 2'))),
const Offset(739.7103369235992, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 739.940336465835571289 : 739.7103369235992,
13.5,
),
);
await tester.pump(const Duration(milliseconds: 150));
......@@ -1083,7 +1167,10 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Page 2')), 0.29867843724787235);
expect(
tester.getTopLeft(flying(tester, find.text('Page 2'))),
const Offset(504.65044379234314, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 504.880443334579467773 : 504.65044379234314,
13.5,
),
);
});
......@@ -1125,7 +1212,10 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Page 2')), 0.0);
expect(
tester.getTopRight(flying(tester, find.text('Page 2'))),
const Offset(60.28966307640076, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 60.0596635341644287109 : 60.28966307640076,
13.5,
),
);
await tester.pump(const Duration(milliseconds: 150));
......@@ -1133,7 +1223,10 @@ void main() {
checkOpacity(tester, flying(tester, find.text('Page 2')), 0.29867843724787235);
expect(
tester.getTopRight(flying(tester, find.text('Page 2'))),
const Offset(295.34955620765686, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 295.119556665420532227 : 295.34955620765686,
13.5,
),
);
});
......@@ -1257,7 +1350,10 @@ void main() {
// Page 2, which is the middle of the top route, start to fly back to the right.
expect(
tester.getTopLeft(flying(tester, find.text('Page 2'))),
const Offset(353.5802058875561, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 353.810205429792404175 : 353.5802058875561,
13.5,
),
);
// Page 1 is in transition in 2 places. Once as the top back label and once
......@@ -1272,12 +1368,18 @@ void main() {
// Transition continues.
expect(
tester.getTopLeft(flying(tester, find.text('Page 2'))),
const Offset(655.2055835723877, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 655.435583114624023438 : 655.2055835723877,
13.5,
),
);
await tester.pump(const Duration(milliseconds: 50));
expect(
tester.getTopLeft(flying(tester, find.text('Page 2'))),
const Offset(749.6335566043854, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 749.863556146621704102 : 749.6335566043854,
13.5,
),
);
await tester.pump(const Duration(milliseconds: 500));
......@@ -1319,7 +1421,10 @@ void main() {
// Page 2, which is the middle of the top route, start to fly back to the right.
expect(
tester.getTopLeft(flying(tester, find.text('Page 2'))),
const Offset(353.5802058875561, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 353.810205429792404175 : 353.5802058875561,
13.5,
),
);
await gesture.up();
......@@ -1328,12 +1433,18 @@ void main() {
// Transition continues from the point we let off.
expect(
tester.getTopLeft(flying(tester, find.text('Page 2'))),
const Offset(353.5802058875561, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 353.810205429792404175 : 353.5802058875561,
13.5,
),
);
await tester.pump(const Duration(milliseconds: 50));
expect(
tester.getTopLeft(flying(tester, find.text('Page 2'))),
const Offset(350.0011436641216, 13.5),
const Offset(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 350.231143206357955933 : 350.0011436641216,
13.5,
),
);
// Finish the snap back animation.
......
......@@ -161,7 +161,8 @@ void main() {
// Also shows the previous page's title next to the back button.
expect(find.widgetWithText(CupertinoButton, 'An iPod'), findsOneWidget);
// 3 paddings + 1 test font character at font size 34.0.
expect(tester.getTopLeft(find.text('An iPod')).dx, 8.0 + 4.0 + 34.0 + 6.0);
// The epsilon is needed since the text theme has a negative letter spacing thus.
expect(tester.getTopLeft(find.text('An iPod')).dx, moreOrLessEquals(8.0 + 4.0 + 34.0 + 6.0, epsilon: 0.5));
});
testWidgets('Previous title is correct on first transition frame', (WidgetTester tester) async {
......@@ -267,7 +268,8 @@ void main() {
// from An iPod to Back (since An Internet communicator is too long to
// fit in the back button).
expect(find.widgetWithText(CupertinoButton, 'Back'), findsOneWidget);
expect(tester.getTopLeft(find.text('Back')).dx, 8.0 + 4.0 + 34.0 + 6.0);
// The epsilon is needed since the text theme has a negative letter spacing thus.
expect(tester.getTopLeft(find.text('Back')).dx, moreOrLessEquals(8.0 + 4.0 + 34.0 + 6.0, epsilon: 0.5));
});
testWidgets('Back swipe dismiss interrupted by route push', (WidgetTester tester) async {
......
......@@ -4726,7 +4726,7 @@ void main() {
child: CustomScrollView(
slivers: <Widget>[
const SliverAppBar.large(
title: Text(title),
title: Text(title, maxLines: 1),
),
SliverToBoxAdapter(
child: Container(
......@@ -4771,7 +4771,7 @@ void main() {
child: CustomScrollView(
slivers: <Widget>[
const SliverAppBar.medium(
title: Text(title),
title: Text(title, maxLines: 1),
),
SliverToBoxAdapter(
child: Container(
......@@ -4820,7 +4820,7 @@ void main() {
child: CustomScrollView(
slivers: <Widget>[
const SliverAppBar.large(
title: Text(title),
title: Text(title, maxLines: 1),
),
SliverToBoxAdapter(
child: Container(
......
......@@ -50,7 +50,10 @@ void main() {
expect(tester.getTopLeft(find.text('0')), const Offset(16, -4));
final RenderBox box = tester.renderObject(find.byType(Badge));
expect(box, paints..rrect(rrect: RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8)), color: theme.colorScheme.error));
final RRect rrect = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? RRect.fromLTRBR(12, -4, 31.5, 12, const Radius.circular(8))
: RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8));
expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error));
});
testWidgets('Large Badge defaults with RTL', (WidgetTester tester) async {
......@@ -89,7 +92,10 @@ void main() {
expect(tester.getTopLeft(find.text('0')), const Offset(0, -4));
final RenderBox box = tester.renderObject(find.byType(Badge));
expect(box, paints..rrect(rrect: RRect.fromLTRBR(-4, -4, 16, 12, const Radius.circular(8)), color: theme.colorScheme.error));
final RRect rrect = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? RRect.fromLTRBR(-4, -4, 15.5, 12, const Radius.circular(8))
: RRect.fromLTRBR(-4, -4, 16, 12, const Radius.circular(8));
expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error));
});
// Essentially the same as 'Large Badge defaults'
......@@ -143,7 +149,10 @@ void main() {
// T = alignment.top
// R = L + '0'.width + padding.width
// B = T + largeSize, R = largeSize/2
expect(box, paints..rrect(rrect: RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8)), color: theme.colorScheme.error));
final RRect rrect = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? RRect.fromLTRBR(12, -4, 31.5, 12, const Radius.circular(8))
: RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8));
expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error));
await tester.pumpWidget(buildFrame(1000));
expect(find.text('999+'), findsOneWidget);
......
......@@ -465,18 +465,16 @@ void main() {
),
);
final double textWidth = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? width
: (width / 1.5).floorToDouble() * 1.5;
// The title is scaled and transformed to be 1.5 times bigger, when the
// FlexibleSpaceBar is fully expanded, thus we expect the width to be
// 1.5 times smaller than the full width. The height of the text is the same
// as the font size, with 10 dps bottom margin.
expect(
tester.getRect(find.byType(Text)),
Rect.fromLTRB(
0,
height - titleFontSize - 10,
(width / 1.5).floorToDouble() * 1.5,
height,
),
rectMoreOrLessEquals(Rect.fromLTRB(0, height - titleFontSize - 10, textWidth, height), epsilon: 0.0001),
);
});
......@@ -537,18 +535,16 @@ void main() {
// bottom edge.
const double bottomMargin = titleFontSize * (expandedTitleScale - 1);
final double textWidth = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? collapsedWidth
: (collapsedWidth / 3).floorToDouble() * 3;
// The title is scaled and transformed to be 3 times bigger, when the
// FlexibleSpaceBar is fully expanded, thus we expect the width to be
// 3 times smaller than the full width. The height of the text is the same
// as the font size, with 40 dps bottom margin to maintain its bottom position.
expect(
tester.getRect(title),
Rect.fromLTRB(
0,
height - titleFontSize - bottomMargin,
(collapsedWidth / 3).floorToDouble() * 3,
height,
),
rectMoreOrLessEquals(Rect.fromLTRB(0, height - titleFontSize - bottomMargin, textWidth, height), epsilon: 0.0001),
);
});
......
......@@ -5697,8 +5697,11 @@ void main() {
return false;
}
final Rect clipRect = arguments[0] as Rect;
// 133.3 is approximately 100 / 0.75 (_kFinalLabelScale)
expect(clipRect, rectMoreOrLessEquals(const Rect.fromLTWH(0, 0, 133.0, 16.0)));
// _kFinalLabelScale = 0.75
const double width = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? 100 / 0.75
: 133.0;
expect(clipRect, rectMoreOrLessEquals(const Rect.fromLTWH(0, 0, width, 16.0), epsilon: 1e-5));
return true;
}),
);
......
......@@ -583,7 +583,7 @@ void main() {
// Padding at the top of the rail.
const double topPadding = 8.0;
// Width of a destination.
const double destinationWidth = 126.0;
const double destinationWidth = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 125.5 : 126.0;
// Height of a destination indicator with icon.
const double destinationHeight = 32.0;
// Space between the indicator and label.
......@@ -858,7 +858,7 @@ void main() {
// Padding at the top of the rail.
const double topPadding = 8.0;
// Width of a destination.
const double destinationWidth = 126.0;
const double destinationWidth = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 125.5 : 126.0;
// Height of a destination indicator with icon.
const double destinationHeight = 32.0;
// Space between the indicator and label.
......
......@@ -1045,7 +1045,7 @@ void main() {
child: Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(textScaleFactor: 1.3),
data: const MediaQueryData(textScaleFactor: 1.25),
child: Center(
child: OutlinedButton(
style: const ButtonStyle(
......@@ -1064,7 +1064,10 @@ void main() {
);
expect(tester.getSize(find.byType(OutlinedButton)), equals(const Size(88.0, 48.0)));
expect(tester.getSize(find.byType(Text)), const Size(55.0, 18.0));
expect(tester.getSize(find.byType(Text)), const Size(
bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 52.5 : 53.0,
18.0,
));
// Set text scale large enough to expand text and button.
await tester.pumpWidget(
......
......@@ -607,8 +607,8 @@ void main() {
..line(
color: theme.colorScheme.primary,
strokeWidth: indicatorWeight,
p1: const Offset(65.5, indicatorY),
p2: const Offset(134.5, indicatorY),
p1: const Offset(bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 65.75 : 65.5, indicatorY),
p2: const Offset(bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 134.25 : 134.5, indicatorY),
),
);
});
......
......@@ -473,19 +473,31 @@ void main() {
const double indicatorWeight = 3.0;
expect(
tabBarBox,
paints
..rrect(
color: theme.colorScheme.primary,
rrect: RRect.fromLTRBAndCorners(
final RRect rrect = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? RRect.fromLTRBAndCorners(
64.75,
tabBarBox.size.height - indicatorWeight,
135.25,
tabBarBox.size.height,
topLeft: const Radius.circular(3.0),
topRight: const Radius.circular(3.0),
)
: RRect.fromLTRBAndCorners(
64.5,
tabBarBox.size.height - indicatorWeight,
135.5,
tabBarBox.size.height,
topLeft: const Radius.circular(3.0),
topRight: const Radius.circular(3.0),
),
);
expect(
tabBarBox,
paints
..rrect(
color: theme.colorScheme.primary,
rrect: rrect,
));
});
......
......@@ -608,7 +608,7 @@ void main() {
child: Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(textScaleFactor: 1.3),
data: const MediaQueryData(textScaleFactor: 1.25),
child: Center(
child: TextButton(
onPressed: () { },
......@@ -620,8 +620,14 @@ void main() {
),
);
expect(tester.getSize(find.byType(TextButton)), const Size(71.0, 48.0));
expect(tester.getSize(find.byType(Text)), const Size(55.0, 18.0));
const Size textButtonSize = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? Size(68.5, 48.0)
: Size(69.0, 48.0);
const Size textSize = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')
? Size(52.5, 18.0)
: Size(53.0, 18.0);
expect(tester.getSize(find.byType(TextButton)), textButtonSize);
expect(tester.getSize(find.byType(Text)), textSize);
// Set text scale large enough to expand text and button.
await tester.pumpWidget(
......
......@@ -744,7 +744,9 @@ void main() {
switch (materialType) {
case MaterialType.material2:
expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(154, 155)));
expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(281, 165)));
expect(tester.getBottomRight(find.text(selectTimeString)), equals(
const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? const Offset(280.5, 165) : const Offset(281, 165),
));
expect(tester.getBottomRight(find.text(okString)).dx, 644);
expect(tester.getBottomLeft(find.text(okString)).dx, 616);
expect(tester.getBottomRight(find.text(cancelString)).dx, 582);
......@@ -764,7 +766,9 @@ void main() {
switch (materialType) {
case MaterialType.material2:
expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(519, 155)));
expect(tester.getTopLeft(find.text(selectTimeString)), equals(
const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? const Offset(519.5, 155) : const Offset(519, 155),
));
expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(646, 165)));
expect(tester.getBottomLeft(find.text(okString)).dx, 156);
expect(tester.getBottomRight(find.text(okString)).dx, 184);
......
......@@ -180,11 +180,11 @@ void main() {
);
// Metrics should be refreshed
// ignore: avoid_dynamic_calls
expect(state.numberLabelWidth - 46.0 < precisionErrorTolerance, isTrue);
expect(state.numberLabelWidth, lessThan(46.0 + precisionErrorTolerance));
// ignore: avoid_dynamic_calls
expect(state.numberLabelHeight - 23.0 < precisionErrorTolerance, isTrue);
expect(state.numberLabelHeight, lessThan(23.0 + precisionErrorTolerance));
// ignore: avoid_dynamic_calls
expect(state.numberLabelBaseline - 18.400070190429688 < precisionErrorTolerance, isTrue);
expect(state.numberLabelBaseline, lessThan(18.400070190429688 + precisionErrorTolerance));
final Element element = tester.element(find.byType(CupertinoTimerPicker));
expect(element.dirty, isTrue);
}, skip: isBrowser); // TODO(yjbanov): cupertino does not work on the Web yet: https://github.com/flutter/flutter/issues/41920
......
......@@ -1507,6 +1507,27 @@ void main() {
painter.dispose();
});
test('TextPainter line breaking does not round to integers', () {
if (! const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')) {
return;
}
const double fontSize = 1.25;
const String text = '12345';
assert((fontSize * text.length).truncate() != fontSize * text.length);
final TextPainter painter = TextPainter(
textDirection: TextDirection.ltr,
text: const TextSpan(text: text, style: TextStyle(fontSize: fontSize)),
)..layout(maxWidth: text.length * fontSize);
expect(painter.maxIntrinsicWidth, text.length * fontSize);
switch (painter.computeLineMetrics()) {
case [ui.LineMetrics(width: final double width)]:
expect(width, text.length * fontSize);
case final List<ui.LineMetrics> metrics:
expect(metrics, hasLength(1));
}
}, skip: kIsWeb && !isCanvasKit); // [intended] Browsers seem to always round font/glyph metrics.
}
class MockCanvas extends Fake implements Canvas {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment