Skip to content

Commit 1783ae7

Browse files
daohoangsonclaude
andcommitted
fix: implement computeDryBaseline for custom RenderBox subclasses
In Flutter 3.32+, any RenderBox that overrides computeDistanceToActualBaseline must also override computeDryBaseline. Add computeDryBaseline to: - _ListItemRenderObject - _ListMarkerRenderObject - _RubyRenderObject - _TableRenderObject - _RenderCssSizing (pass correct child constraints) - _HorizontalMarginRenderObject (pass deflated constraints) - _ValignBaselineRenderObject (pass deflated constraints + padding) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e245916 commit 1783ae7

8 files changed

Lines changed: 149 additions & 9 deletions

File tree

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,20 @@ class _RenderCssSizing extends RenderProxyBox {
219219
markNeedsLayout();
220220
}
221221

222+
@override
223+
double? computeDryBaseline(
224+
BoxConstraints constraints,
225+
TextBaseline baseline,
226+
) {
227+
final scopedChild = child;
228+
if (scopedChild == null) {
229+
return null;
230+
}
231+
232+
final cc = _applyContraints(constraints);
233+
return scopedChild.getDryBaseline(cc, baseline);
234+
}
235+
222236
@override
223237
Size computeDryLayout(BoxConstraints constraints) {
224238
final scopedChild = child;

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ class _HorizontalMarginRenderObject extends RenderShiftedBox {
5555

5656
double get marginsOrZero => _left.or(0) + _right.or(0);
5757

58+
@override
59+
double? computeDryBaseline(
60+
BoxConstraints constraints,
61+
TextBaseline baseline,
62+
) {
63+
final scopedChild = child;
64+
if (scopedChild == null) {
65+
return null;
66+
}
67+
68+
final edges = EdgeInsets.only(left: _left.or(0), right: _right.or(0));
69+
final cc = constraints.deflate(edges);
70+
return scopedChild.getDryBaseline(cc, baseline);
71+
}
72+
5873
@override
5974
Size computeDryLayout(BoxConstraints constraints) =>
6075
_compute(child, constraints, ChildLayoutHelper.dryLayoutChild);

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,23 @@ class _ListItemRenderObject extends RenderBox
8787
double? computeDistanceToActualBaseline(TextBaseline baseline) =>
8888
defaultComputeDistanceToFirstActualBaseline(baseline);
8989

90+
@override
91+
double? computeDryBaseline(
92+
BoxConstraints constraints,
93+
TextBaseline baseline,
94+
) {
95+
final child = firstChild;
96+
if (child == null) {
97+
return null;
98+
}
99+
100+
final childConstraints = constraints.maxWidth.isFinite && textAlign != null
101+
? constraints.tighten(width: constraints.maxWidth)
102+
: constraints;
103+
// The first child's offset is always Offset.zero in _compute
104+
return child.getDryBaseline(childConstraints, baseline);
105+
}
106+
90107
@override
91108
Size computeDryLayout(BoxConstraints constraints) =>
92109
_compute(firstChild, constraints, ChildLayoutHelper.dryLayoutChild);

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ class _ListMarkerRenderObject extends RenderBox {
9797
double computeDistanceToActualBaseline(TextBaseline baseline) =>
9898
_textPainter.computeDistanceToActualBaseline(baseline);
9999

100+
@override
101+
double? computeDryBaseline(
102+
BoxConstraints constraints,
103+
TextBaseline baseline,
104+
) =>
105+
_textPainter.computeDistanceToActualBaseline(baseline);
106+
100107
@override
101108
Size computeDryLayout(BoxConstraints constraints) =>
102109
constraints.constrain(_textPainter.size);

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,37 @@ class _RubyRenderObject extends RenderBox
3939
return offset.dy + rubyValue;
4040
}
4141

42+
@override
43+
double? computeDryBaseline(
44+
BoxConstraints constraints,
45+
TextBaseline baseline,
46+
) {
47+
final ruby = firstChild;
48+
if (ruby == null) {
49+
return null;
50+
}
51+
52+
final rubyConstraints = constraints.loosen();
53+
final rubySize = ruby.getDryLayout(rubyConstraints);
54+
final rubyBaseline = ruby.getDryBaseline(rubyConstraints, baseline);
55+
if (rubyBaseline == null) {
56+
return null;
57+
}
58+
59+
final rt = (ruby.parentData! as _RubyParentData).nextSibling;
60+
final rtHeight = rt != null
61+
? rt
62+
.getDryLayout(
63+
rubyConstraints.copyWith(
64+
maxHeight: rubyConstraints.maxHeight - rubySize.height,
65+
),
66+
)
67+
.height
68+
: 0.0;
69+
70+
return rtHeight + rubyBaseline;
71+
}
72+
4273
@override
4374
Size computeDryLayout(BoxConstraints constraints) =>
4475
_compute(firstChild, constraints, ChildLayoutHelper.dryLayoutChild);

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,40 @@ class _TableRenderObject extends RenderBox
836836
return result;
837837
}
838838

839+
@override
840+
double? computeDryBaseline(
841+
BoxConstraints constraints,
842+
TextBaseline baseline,
843+
) {
844+
double? result;
845+
846+
var child = firstChild;
847+
while (child != null) {
848+
final data = child.parentData! as _TableCellData;
849+
850+
if (data.rowStart == 0) {
851+
// only compute cells in the first row
852+
// use the child's dry baseline with loosened constraints
853+
// since exact cell constraints require full table layout
854+
final candidate = child.getDryBaseline(constraints.loosen(), baseline);
855+
if (candidate != null) {
856+
final adjusted = candidate + paddingTop + rowGap;
857+
if (result != null) {
858+
if (adjusted < result) {
859+
result = adjusted;
860+
}
861+
} else {
862+
result = adjusted;
863+
}
864+
}
865+
}
866+
867+
child = data.nextSibling;
868+
}
869+
870+
return result;
871+
}
872+
839873
@override
840874
Size computeDryLayout(BoxConstraints constraints) =>
841875
_TableRenderLayouter.dry(this, constraints).compute(firstChild).totalSize;

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,25 @@ class _ValignBaselineRenderObject extends RenderProxyBox {
121121
double? _baselineWithOffset;
122122
var _paddingTop = 0.0;
123123

124+
@override
125+
double? computeDryBaseline(
126+
BoxConstraints constraints,
127+
TextBaseline baseline,
128+
) {
129+
final scopedChild = child;
130+
if (scopedChild == null) {
131+
return null;
132+
}
133+
134+
final cc = constraints.loosen().deflate(EdgeInsets.only(top: _paddingTop));
135+
final childBaseline = scopedChild.getDryBaseline(cc, baseline);
136+
if (childBaseline == null) {
137+
return null;
138+
}
139+
140+
return childBaseline + _paddingTop;
141+
}
142+
124143
@override
125144
Size computeDryLayout(BoxConstraints constraints) =>
126145
_compute(child, constraints, ChildLayoutHelper.dryLayoutChild);

packages/core/test/tag_table_test.dart

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -829,15 +829,18 @@ Future<void> main() async {
829829
testWidgets('computeDryBaseline', (tester) async {
830830
final key = GlobalKey();
831831
await tester.pumpWidget(
832-
HtmlTable(
833-
key: key,
834-
children: const [
835-
HtmlTableCell(
836-
columnStart: 0,
837-
rowStart: 0,
838-
child: Text('Cell'),
839-
),
840-
],
832+
Directionality(
833+
textDirection: TextDirection.ltr,
834+
child: HtmlTable(
835+
key: key,
836+
children: const [
837+
HtmlTableCell(
838+
columnStart: 0,
839+
rowStart: 0,
840+
child: Text('Cell'),
841+
),
842+
],
843+
),
841844
),
842845
);
843846
await tester.pumpAndSettle();

0 commit comments

Comments
 (0)