Skip to content

Commit 8d18bda

Browse files
committed
[skip ci] Switch to use sizing hints
1 parent 37b6eb2 commit 8d18bda

File tree

4 files changed

+70
-90
lines changed

4 files changed

+70
-90
lines changed

packages/core/lib/src/internal/ops/tag_table.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,12 @@ class TagTable {
8585

8686
final layoutBuilder = LayoutBuilder(
8787
builder: (context, bc) {
88-
// wrap the table in a builder to obtain the layout constraints early
89-
// in order to calculate a conservative width
90-
// the whole thing becomes scrollable when columns are too wide
91-
final maxWidth = bc.maxWidth;
92-
9388
final resolved = tableTree.inheritanceResolvers.resolve(context);
9489
Widget built = ValignBaselineContainer(
9590
child: HtmlTable(
9691
border: border.getBorder(resolved),
9792
borderCollapse: borderCollapse == kCssBorderCollapseCollapse,
9893
borderSpacing: borderSpacing?.getValue(resolved) ?? 0.0,
99-
maxWidth: maxWidth,
100-
minWidth: bc.minWidth,
10194
textDirection: resolved.directionOrLtr,
10295
children: List.from(
10396
data.builders
@@ -108,7 +101,14 @@ class TagTable {
108101
),
109102
);
110103

111-
if (maxWidth.isFinite) {
104+
// provide hints to size the columns properly
105+
built = CssSizingHint(
106+
maxWidth: bc.maxWidth,
107+
minWidth: bc.minWidth,
108+
child: built,
109+
);
110+
111+
if (bc.maxWidth.isFinite) {
112112
built = wf.buildHorizontalScrollView(tableTree, built) ?? built;
113113
}
114114

packages/core/lib/src/widgets/css_sizing.dart

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ class CssSizing extends SingleChildRenderObjectWidget {
7373
return _RenderCssSizing(
7474
maxHeight: maxHeight ?? hint?.maxHeight.cssSizingValue,
7575
maxWidth: maxWidth ?? hint?.maxWidth.cssSizingValue,
76-
minHeight: minHeight,
77-
minWidth: minWidth,
76+
minHeight: minHeight ?? hint?.minHeight.cssSizingValue,
77+
minWidth: minWidth ?? hint?.minWidth.cssSizingValue,
7878
preferredAxis: preferredAxis,
7979
preferredHeight: preferredHeight,
8080
preferredWidth: preferredWidth,
@@ -137,17 +137,24 @@ class CssSizing extends SingleChildRenderObjectWidget {
137137
class CssSizingHint extends InheritedWidget {
138138
final double? maxHeight;
139139
final double? maxWidth;
140+
final double? minHeight;
141+
final double? minWidth;
140142

141143
const CssSizingHint({
142144
required super.child,
143145
super.key,
144146
this.maxHeight,
145147
this.maxWidth,
148+
this.minHeight,
149+
this.minWidth,
146150
});
147151

148152
@override
149153
bool updateShouldNotify(CssSizingHint oldWidget) =>
150-
maxHeight != oldWidget.maxHeight || maxWidth != oldWidget.maxWidth;
154+
maxHeight != oldWidget.maxHeight ||
155+
maxWidth != oldWidget.maxWidth ||
156+
minHeight != oldWidget.minHeight ||
157+
minWidth != oldWidget.minWidth;
151158
}
152159

153160
class _RenderCssSizing extends RenderProxyBox {
@@ -273,13 +280,17 @@ class _RenderCssSizing extends RenderProxyBox {
273280
)
274281
: null;
275282

276-
final cc = BoxConstraints(
283+
var cc = BoxConstraints(
277284
maxHeight: stableChildSize?.height ?? preferredHeight ?? maxHeight,
278285
maxWidth: stableChildSize?.width ?? preferredWidth ?? maxWidth,
279286
minHeight: stableChildSize?.height ?? preferredHeight ?? minHeight,
280287
minWidth: stableChildSize?.width ?? preferredWidth ?? minWidth,
281288
);
282289

290+
// after everything... if the incoming are tight then we must follow it
291+
cc = c.hasTightWidth ? cc.tighten(width: c.maxWidth) : cc;
292+
cc = c.hasTightHeight ? cc.tighten(height: c.maxHeight) : cc;
293+
283294
return cc;
284295
}
285296

packages/core/lib/src/widgets/html_table.dart

Lines changed: 46 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import 'package:flutter/rendering.dart';
44
import 'package:flutter/widgets.dart';
55
import 'package:logging/logging.dart';
66

7+
import 'css_sizing.dart' show CssSizingHint;
8+
79
/// A TABLE widget.
810
class HtmlTable extends MultiChildRenderObjectWidget {
911
/// The table border sides.
@@ -19,12 +21,6 @@ class HtmlTable extends MultiChildRenderObjectWidget {
1921
/// Default: `0.0`.
2022
final double borderSpacing;
2123

22-
/// If non-null, overwrites the incoming [BoxConstraints.maxWidth].
23-
final double? maxWidth;
24-
25-
/// If non-null, overwrites the incoming [BoxConstraints.minWidth].
26-
final double? minWidth;
27-
2824
/// Determines the order to lay children out horizontally.
2925
///
3026
/// Default: [TextDirection.ltr].
@@ -36,21 +32,22 @@ class HtmlTable extends MultiChildRenderObjectWidget {
3632
this.borderCollapse = false,
3733
this.borderSpacing = 0.0,
3834
required super.children,
39-
this.maxWidth,
40-
this.minWidth,
4135
this.textDirection = TextDirection.ltr,
4236
super.key,
4337
});
4438

4539
@override
46-
RenderObject createRenderObject(BuildContext context) => _TableRenderObject(
47-
border,
48-
textDirection,
49-
borderCollapse: borderCollapse,
50-
borderSpacing: borderSpacing,
51-
maxWidth: maxWidth,
52-
minWidth: minWidth,
53-
);
40+
RenderObject createRenderObject(BuildContext context) {
41+
final hint = context.dependOnInheritedWidgetOfExactType<CssSizingHint>();
42+
return _TableRenderObject(
43+
border,
44+
textDirection,
45+
borderCollapse: borderCollapse,
46+
borderSpacing: borderSpacing,
47+
maxWidth: hint?.maxWidth,
48+
minWidth: hint?.minWidth,
49+
);
50+
}
5451

5552
@override
5653
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
@@ -66,8 +63,6 @@ class HtmlTable extends MultiChildRenderObjectWidget {
6663
);
6764
properties
6865
.add(DoubleProperty('borderSpacing', borderSpacing, defaultValue: 0.0));
69-
properties.add(DoubleProperty('maxWidth', maxWidth, defaultValue: null));
70-
properties.add(DoubleProperty('minWidth', minWidth, defaultValue: null));
7166
properties.add(
7267
DiagnosticsProperty(
7368
'textDirection',
@@ -79,12 +74,13 @@ class HtmlTable extends MultiChildRenderObjectWidget {
7974

8075
@override
8176
void updateRenderObject(BuildContext context, RenderObject renderObject) {
77+
final hint = context.dependOnInheritedWidgetOfExactType<CssSizingHint>();
8278
(renderObject as _TableRenderObject)
8379
..setBorder(border)
8480
..setBorderCollapse(borderCollapse)
8581
..setBorderSpacing(borderSpacing)
86-
..setMaxWidth(maxWidth)
87-
..setMinWidth(minWidth)
82+
..setMaxWidth(hint?.maxWidth)
83+
..setMinWidth(hint?.minWidth)
8884
..setTextDirection(textDirection);
8985
}
9086
}
@@ -333,36 +329,38 @@ class _TableRenderLayouter {
333329
child = data.nextSibling;
334330
}
335331

332+
final columnGapsSum = (columnCount + 1) * tro.columnGap;
333+
final gapsAndPaddings = tro.paddingLeft + columnGapsSum + tro.paddingRight;
334+
335+
double? availableWidth;
336336
final maxWidth = tro._maxWidth ?? constraints.maxWidth;
337+
if (maxWidth.isFinite && maxWidth > 0) {
338+
availableWidth = maxWidth - gapsAndPaddings;
339+
}
337340

338-
var wc = const BoxConstraints();
339-
final troMinWidth = tro._minWidth;
340-
if (troMinWidth != null && troMinWidth > 0) {
341-
// only apply width constrains if a specific min value has been set
342-
// this will be used mostly in percentage calculations
343-
wc = BoxConstraints(maxWidth: maxWidth, minWidth: troMinWidth);
341+
double? requiredWidth;
342+
final minWidth = tro._minWidth ?? constraints.minWidth;
343+
if (minWidth.isFinite && minWidth > 0) {
344+
requiredWidth = minWidth - gapsAndPaddings;
344345
}
345346

346347
return _TableDataStep1(
348+
availableWidth: availableWidth,
347349
cells: cells,
348350
children: children,
349351
columnCount: columnCount,
350-
remainingMaxWidth:
351-
_TableDataStep1._calculateRemainingWidth(tro, columnCount, maxWidth),
352-
remainingMinWidth: _TableDataStep1._calculateRemainingWidth(
353-
tro, columnCount, wc.minWidth),
352+
requiredWidth: requiredWidth,
354353
rowCount: rowCount,
355-
widthConstraints: wc,
356354
);
357355
}
358356

359357
_TableDataStep2 step2NaiveColumnWidths(_TableDataStep1 step1) {
360358
final cells = step1.cells;
361359
final naiveColumnWidths = List.filled(step1.columnCount, .0);
362360

363-
final remainingMinWidth = step1.remainingMinWidth;
364-
if (remainingMinWidth != null && step1.columnCount > 0) {
365-
final cellMinWidth = remainingMinWidth / step1.columnCount;
361+
final requiredWidth = step1.requiredWidth;
362+
if (requiredWidth != null && step1.columnCount > 0) {
363+
final cellMinWidth = requiredWidth / step1.columnCount;
366364
for (var i = 0; i < cells.length; i++) {
367365
final data = cells[i];
368366
naiveColumnWidths.setMaxColumnWidths(tro, data, cellMinWidth);
@@ -379,9 +377,9 @@ class _TableRenderLayouter {
379377

380378
_TableDataStep3 step3MinIntrinsicWidth(_TableDataStep2 step2) {
381379
final step1 = step2.step1;
380+
final availableWidth = step1.availableWidth;
382381
final cells = step1.cells;
383382
final children = step1.children;
384-
final remainingMaxWidth = step1.remainingMaxWidth;
385383

386384
final cellSizes = List<Size?>.filled(children.length, null);
387385
final childMinWidths = List<double?>.filled(children.length, null);
@@ -393,7 +391,7 @@ class _TableRenderLayouter {
393391
// it only considers min value when the columns don't fit
394392
var columnWidths = maxColumnWidths;
395393
if (columnWidths.zeros.isEmpty &&
396-
(remainingMaxWidth == null || columnWidths.sum <= remainingMaxWidth)) {
394+
(availableWidth == null || columnWidths.sum <= availableWidth)) {
397395
return _TableDataStep3(
398396
step2,
399397
columnWidths: columnWidths,
@@ -411,10 +409,10 @@ class _TableRenderLayouter {
411409
if (cellSizes[i] == null) {
412410
// side effect
413411
// layout cells for the initial width
414-
final layoutSize = layouter(child, step1.widthConstraints);
412+
final layoutSize = layouter(child, constraints);
415413
cellSizes[i] = layoutSize;
416414
maxColumnWidths.setMaxColumnWidths(tro, data, layoutSize.width);
417-
logger.fine('[3] Got child#$i $layoutSize@${step1.widthConstraints}');
415+
logger.fine('[3] Got child#$i $layoutSize@$constraints');
418416
shouldLoop = true;
419417
}
420418

@@ -446,9 +444,9 @@ class _TableRenderLayouter {
446444
}
447445
}
448446

449-
if (remainingMaxWidth != null) {
447+
if (availableWidth != null) {
450448
columnWidths = redistributeValues(
451-
available: remainingMaxWidth,
449+
available: availableWidth,
452450
maxValues: maxColumnWidths,
453451
minValues: minColumnWidths,
454452
);
@@ -470,20 +468,20 @@ class _TableRenderLayouter {
470468
required List<double> minColumnWidths,
471469
}) {
472470
final step1 = step2.step1;
473-
final remainingMaxWidth = step1.remainingMaxWidth;
471+
final availableWidth = step1.availableWidth;
474472

475473
final widthSum = columnWidths.sumRange(data);
476474
final maxWidthSum = maxColumnWidths.sumRange(data);
477475
if (widthSum >= maxWidthSum) {
478476
// cell has been allocated more than its requested value
479477
// skip measuring if not absolutely needed because it's expensive
480478

481-
if (remainingMaxWidth == null) {
482-
// unbounded width constraints
479+
if (availableWidth == null) {
480+
// unlimited available space
483481
return null;
484482
}
485483

486-
if (columnWidths.sum <= remainingMaxWidth) {
484+
if (columnWidths.sum <= availableWidth) {
487485
// current widths are good enough
488486
return null;
489487
}
@@ -658,34 +656,21 @@ class _TableRenderLayouter {
658656

659657
@immutable
660658
class _TableDataStep1 {
659+
final double? availableWidth;
661660
final List<_TableCellData> cells;
662661
final List<RenderBox> children;
663662
final int columnCount;
664-
final double? remainingMaxWidth;
665-
final double? remainingMinWidth;
663+
final double? requiredWidth;
666664
final int rowCount;
667-
final BoxConstraints widthConstraints;
668665

669666
const _TableDataStep1({
667+
required this.availableWidth,
670668
required this.cells,
671669
required this.children,
672670
required this.columnCount,
673-
required this.remainingMaxWidth,
674-
required this.remainingMinWidth,
671+
required this.requiredWidth,
675672
required this.rowCount,
676-
required this.widthConstraints,
677673
});
678-
679-
static double _calculateRemainingWidth(
680-
_TableRenderObject tro, int columnCount, double width) {
681-
if (width.isZero) {
682-
return 0;
683-
}
684-
685-
final columnGapsSum = (columnCount + 1) * tro.columnGap;
686-
final gapsAndPaddings = tro.paddingLeft + columnGapsSum + tro.paddingRight;
687-
return width - gapsAndPaddings;
688-
}
689674
}
690675

691676
@immutable

packages/core/test/tag_table_test.dart

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -686,22 +686,6 @@ Future<void> main() async {
686686
expect(after.borderSpacing, equals(20.0));
687687
});
688688

689-
testWidgets('updates maxWidths', (WidgetTester tester) async {
690-
await explain(
691-
tester,
692-
'<div style="max-width: 100px"><table><tr><td>Foo</td></tr></table></div>',
693-
);
694-
final before = tester.table;
695-
expect(before.maxWidth, equals(100.0));
696-
697-
await explain(
698-
tester,
699-
'<div style="max-width: 200px"><table><tr><td>Foo</td></tr></table></div>',
700-
);
701-
final after = tester.table;
702-
expect(after.maxWidth, equals(200.0));
703-
});
704-
705689
testWidgets('updates textDirection', (WidgetTester tester) async {
706690
await explain(tester, '<table><tr><td>Foo</td></tr></table>');
707691
final before = tester.table;
@@ -994,7 +978,7 @@ Future<void> main() async {
994978

995979
final goldenSkipEnvVar = Platform.environment['GOLDEN_SKIP'];
996980
final goldenSkip = goldenSkipEnvVar == null
997-
? Platform.isLinux
981+
? Platform.isMacOS
998982
? null
999983
: 'Linux only'
1000984
: 'GOLDEN_SKIP=$goldenSkipEnvVar';

0 commit comments

Comments
 (0)