Prevents infinite loop in Table._computeColumnWidths (#36262)
This commit is contained in:
parent
9946f7cff9
commit
1b57006c82
@ -918,10 +918,7 @@ class RenderTable extends RenderBox {
|
|||||||
// columns shrinking them proportionally until we have no
|
// columns shrinking them proportionally until we have no
|
||||||
// available columns, then do the same to the non-flexible ones.
|
// available columns, then do the same to the non-flexible ones.
|
||||||
int availableColumns = columns;
|
int availableColumns = columns;
|
||||||
// Handle double precision errors which causes this loop to become
|
while (deficit > precisionErrorTolerance && totalFlex > precisionErrorTolerance) {
|
||||||
// stuck in certain configurations.
|
|
||||||
const double minimumDeficit = precisionErrorTolerance;
|
|
||||||
while (deficit > minimumDeficit && totalFlex > minimumDeficit) {
|
|
||||||
double newTotalFlex = 0.0;
|
double newTotalFlex = 0.0;
|
||||||
for (int x = 0; x < columns; x += 1) {
|
for (int x = 0; x < columns; x += 1) {
|
||||||
if (flexes[x] != null) {
|
if (flexes[x] != null) {
|
||||||
@ -943,31 +940,30 @@ class RenderTable extends RenderBox {
|
|||||||
}
|
}
|
||||||
totalFlex = newTotalFlex;
|
totalFlex = newTotalFlex;
|
||||||
}
|
}
|
||||||
if (deficit > 0.0) {
|
while (deficit > precisionErrorTolerance && availableColumns > 0) {
|
||||||
// Now we have to take out the remaining space from the
|
// Now we have to take out the remaining space from the
|
||||||
// columns that aren't minimum sized.
|
// columns that aren't minimum sized.
|
||||||
// To make this fair, we repeatedly remove equal amounts from
|
// To make this fair, we repeatedly remove equal amounts from
|
||||||
// each column, clamped to the minimum width, until we run out
|
// each column, clamped to the minimum width, until we run out
|
||||||
// of columns that aren't at their minWidth.
|
// of columns that aren't at their minWidth.
|
||||||
do {
|
final double delta = deficit / availableColumns;
|
||||||
final double delta = deficit / availableColumns;
|
assert(delta != 0);
|
||||||
int newAvailableColumns = 0;
|
int newAvailableColumns = 0;
|
||||||
for (int x = 0; x < columns; x += 1) {
|
for (int x = 0; x < columns; x += 1) {
|
||||||
final double availableDelta = widths[x] - minWidths[x];
|
final double availableDelta = widths[x] - minWidths[x];
|
||||||
if (availableDelta > 0.0) {
|
if (availableDelta > 0.0) {
|
||||||
if (availableDelta <= delta) {
|
if (availableDelta <= delta) {
|
||||||
// shrank to minimum
|
// shrank to minimum
|
||||||
deficit -= widths[x] - minWidths[x];
|
deficit -= widths[x] - minWidths[x];
|
||||||
widths[x] = minWidths[x];
|
widths[x] = minWidths[x];
|
||||||
} else {
|
} else {
|
||||||
deficit -= delta;
|
deficit -= delta;
|
||||||
widths[x] -= delta;
|
widths[x] -= delta;
|
||||||
newAvailableColumns += 1;
|
newAvailableColumns += 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
availableColumns = newAvailableColumns;
|
}
|
||||||
} while (deficit > 0.0 && availableColumns > 0);
|
availableColumns = newAvailableColumns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return widths;
|
return widths;
|
||||||
|
@ -217,4 +217,30 @@ void main() {
|
|||||||
pumpFrame();
|
pumpFrame();
|
||||||
expect(table, paints..path()..path()..path()..path()..path()..path());
|
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.
|
// 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 {
|
testWidgets('Table widget - repump test', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
Directionality(
|
Directionality(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user