Commit 1b57006c authored by K. P. Sroka's avatar K. P. Sroka Committed by Dan Field

Prevents infinite loop in Table._computeColumnWidths (#36262)

parent 9946f7cf
......@@ -918,10 +918,7 @@ class RenderTable extends RenderBox {
// columns shrinking them proportionally until we have no
// available columns, then do the same to the non-flexible ones.
int availableColumns = columns;
// Handle double precision errors which causes this loop to become
// stuck in certain configurations.
const double minimumDeficit = precisionErrorTolerance;
while (deficit > minimumDeficit && totalFlex > minimumDeficit) {
while (deficit > precisionErrorTolerance && totalFlex > precisionErrorTolerance) {
double newTotalFlex = 0.0;
for (int x = 0; x < columns; x += 1) {
if (flexes[x] != null) {
......@@ -943,14 +940,14 @@ class RenderTable extends RenderBox {
}
totalFlex = newTotalFlex;
}
if (deficit > 0.0) {
while (deficit > precisionErrorTolerance && availableColumns > 0) {
// Now we have to take out the remaining space from the
// columns that aren't minimum sized.
// To make this fair, we repeatedly remove equal amounts from
// each column, clamped to the minimum width, until we run out
// of columns that aren't at their minWidth.
do {
final double delta = deficit / availableColumns;
assert(delta != 0);
int newAvailableColumns = 0;
for (int x = 0; x < columns; x += 1) {
final double availableDelta = widths[x] - minWidths[x];
......@@ -967,7 +964,6 @@ class RenderTable extends RenderBox {
}
}
availableColumns = newAvailableColumns;
} while (deficit > 0.0 && availableColumns > 0);
}
}
return widths;
......
......@@ -217,4 +217,30 @@ void main() {
pumpFrame();
expect(table, paints..path()..path()..path()..path()..path()..path());
});
test('Table flex sizing', () {
const BoxConstraints cellConstraints =
BoxConstraints.tightFor(width: 100, height: 100);
final RenderTable table = RenderTable(
textDirection: TextDirection.rtl,
children: <List<RenderBox>>[
List<RenderBox>.generate(
7,
(int _) => RenderConstrainedBox(additionalConstraints: cellConstraints),
),
],
columnWidths: const <int, TableColumnWidth>{
0: FlexColumnWidth(1.0),
1: FlexColumnWidth(0.123),
2: FlexColumnWidth(0.123),
3: FlexColumnWidth(0.123),
4: FlexColumnWidth(0.123),
5: FlexColumnWidth(0.123),
6: FlexColumnWidth(0.123),
},
);
layout(table, constraints: BoxConstraints.tight(const Size(800.0, 600.0)));
expect(table.hasSize, true);
});
}
......@@ -376,6 +376,36 @@ void main() {
// If the above bug is present this test will never terminate.
});
testWidgets('Calculating flex columns with small width deficit', (WidgetTester tester) async {
const SizedBox cell = SizedBox(width: 1, height: 1);
// If the error is present, pumpWidget() will fail due to an unsatisfied
// assertion during the layout phase.
await tester.pumpWidget(
ConstrainedBox(
constraints: BoxConstraints.tight(const Size(600, 800)),
child: Directionality(
textDirection: TextDirection.ltr,
child: Table(
columnWidths: const <int, TableColumnWidth>{
0: FlexColumnWidth(1.0),
1: FlexColumnWidth(0.123),
2: FlexColumnWidth(0.123),
3: FlexColumnWidth(0.123),
4: FlexColumnWidth(0.123),
5: FlexColumnWidth(0.123),
6: FlexColumnWidth(0.123),
},
children: <TableRow>[
TableRow(children: List<Widget>.filled(7, cell)),
TableRow(children: List<Widget>.filled(7, cell)),
],
),
),
),
);
expect(tester.takeException(), null);
});
testWidgets('Table widget - repump test', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
......
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