computeDryBaseline for rendering / widgets RenderBoxes (#146143)

RenderWrap, Table, Overlay / Stack are not included
This commit is contained in:
LongCatIsLooong 2024-04-03 11:36:19 -07:00 committed by GitHub
parent 99874c1c57
commit ef7019e801
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 321 additions and 212 deletions

View File

@ -4,7 +4,7 @@
import 'dart:collection';
import 'dart:math' as math;
import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle, LineMetrics, PlaceholderAlignment, TextBox;
import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle, LineMetrics, TextBox;
import 'package:characters/characters.dart';
import 'package:flutter/foundation.dart';
@ -777,7 +777,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
_textPainter.text = value;
_cachedAttributedValue = null;
_cachedCombinedSemanticsInfos = null;
_canComputeIntrinsicsCached = null;
markNeedsLayout();
markNeedsSemanticsUpdate();
}
@ -1828,10 +1827,11 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
@override
double computeMinIntrinsicWidth(double height) {
if (!_canComputeIntrinsics) {
return 0.0;
}
final List<PlaceholderDimensions> placeholderDimensions = layoutInlineChildren(double.infinity, (RenderBox child, BoxConstraints constraints) => Size(child.getMinIntrinsicWidth(double.infinity), 0.0));
final List<PlaceholderDimensions> placeholderDimensions = layoutInlineChildren(
double.infinity,
(RenderBox child, BoxConstraints constraints) => Size(child.getMinIntrinsicWidth(double.infinity), 0.0),
ChildLayoutHelper.getDryBaseline,
);
final (double minWidth, double maxWidth) = _adjustConstraints();
return (_textIntrinsics
..setPlaceholderDimensions(placeholderDimensions)
@ -1841,14 +1841,12 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
@override
double computeMaxIntrinsicWidth(double height) {
if (!_canComputeIntrinsics) {
return 0.0;
}
final List<PlaceholderDimensions> placeholderDimensions = layoutInlineChildren(
double.infinity,
// Height and baseline is irrelevant as all text will be laid
// out in a single line. Therefore, using 0.0 as a dummy for the height.
(RenderBox child, BoxConstraints constraints) => Size(child.getMaxIntrinsicWidth(double.infinity), 0.0),
ChildLayoutHelper.getDryBaseline,
);
final (double minWidth, double maxWidth) = _adjustConstraints();
return (_textIntrinsics
@ -1926,10 +1924,9 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
@override
double computeMaxIntrinsicHeight(double width) {
if (!_canComputeIntrinsics) {
return 0.0;
}
_textIntrinsics.setPlaceholderDimensions(layoutInlineChildren(width, ChildLayoutHelper.dryLayoutChild));
_textIntrinsics.setPlaceholderDimensions(
layoutInlineChildren(width, ChildLayoutHelper.dryLayoutChild, ChildLayoutHelper.getDryBaseline),
);
return _preferredHeight(width);
}
@ -2291,35 +2288,12 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
);
}
bool _canComputeDryLayoutForInlineWidgets() {
return text?.visitChildren((InlineSpan span) {
return (span is! PlaceholderSpan) || switch (span.alignment) {
ui.PlaceholderAlignment.baseline ||
ui.PlaceholderAlignment.aboveBaseline ||
ui.PlaceholderAlignment.belowBaseline => false,
ui.PlaceholderAlignment.top ||
ui.PlaceholderAlignment.middle ||
ui.PlaceholderAlignment.bottom => true,
};
}) ?? true;
}
bool? _canComputeIntrinsicsCached;
bool get _canComputeIntrinsics => _canComputeIntrinsicsCached ??= _canComputeDryLayoutForInlineWidgets();
@override
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (!_canComputeIntrinsics) {
assert(debugCannotComputeDryLayout(
reason: 'Dry layout not available for alignments that require baseline.',
));
return Size.zero;
}
final (double minWidth, double maxWidth) = _adjustConstraints(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);
_textIntrinsics
..setPlaceholderDimensions(layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.dryLayoutChild))
..setPlaceholderDimensions(layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.dryLayoutChild, ChildLayoutHelper.getDryBaseline))
..layout(minWidth: minWidth, maxWidth: maxWidth);
final double width = forceLine
? constraints.maxWidth
@ -2330,7 +2304,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
@override
void performLayout() {
final BoxConstraints constraints = this.constraints;
_placeholderDimensions = layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.layoutChild);
_placeholderDimensions = layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.layoutChild, ChildLayoutHelper.getBaseline);
final (double minWidth, double maxWidth) = _adjustConstraints(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);
_textPainter
..setPlaceholderDimensions(_placeholderDimensions)

View File

@ -63,6 +63,39 @@ class RenderListBody extends RenderBox
/// [axisDirection].
Axis get mainAxis => axisDirectionToAxis(axisDirection);
@override
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
assert(_debugCheckConstraints(constraints));
RenderBox? child;
final RenderBox? Function(RenderBox) nextChild;
switch (axisDirection) {
case AxisDirection.right:
case AxisDirection.left:
final BoxConstraints childConstraints = BoxConstraints.tightFor(height: constraints.maxHeight);
BaselineOffset baselineOffset = BaselineOffset.noBaseline;
for (child = firstChild; child != null; child = childAfter(child)) {
baselineOffset = baselineOffset.minOf(BaselineOffset(child.getDryBaseline(childConstraints, baseline)));
}
return baselineOffset.offset;
case AxisDirection.up:
child = lastChild;
nextChild = childBefore;
case AxisDirection.down:
child = firstChild;
nextChild = childAfter;
}
final BoxConstraints childConstraints = BoxConstraints.tightFor(width: constraints.maxWidth);
double mainAxisExtent = 0.0;
for (; child != null; child = nextChild(child)) {
final double? childBaseline = child.getDryBaseline(childConstraints, baseline);
if (childBaseline != null) {
return childBaseline + mainAxisExtent;
}
mainAxisExtent += child.getDryLayout(childConstraints).height;
}
return null;
}
@override
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {

View File

@ -125,14 +125,14 @@ mixin RenderInlineChildrenContainerDefaults on RenderBox, ContainerRenderObjectM
}
}
static PlaceholderDimensions _layoutChild(RenderBox child, double maxWidth, ChildLayouter layoutChild) {
static PlaceholderDimensions _layoutChild(RenderBox child, BoxConstraints childConstraints, ChildLayouter layoutChild, ChildBaselineGetter getBaseline) {
final TextParentData parentData = child.parentData! as TextParentData;
final PlaceholderSpan? span = parentData.span;
assert(span != null);
return span == null
? PlaceholderDimensions.empty
: PlaceholderDimensions(
size: layoutChild(child, BoxConstraints(maxWidth: maxWidth)),
size: layoutChild(child, childConstraints),
alignment: span.alignment,
baseline: span.baseline,
baselineOffset: switch (span.alignment) {
@ -141,17 +141,21 @@ mixin RenderInlineChildrenContainerDefaults on RenderBox, ContainerRenderObjectM
ui.PlaceholderAlignment.bottom ||
ui.PlaceholderAlignment.middle ||
ui.PlaceholderAlignment.top => null,
ui.PlaceholderAlignment.baseline => child.getDistanceToBaseline(span.baseline!),
ui.PlaceholderAlignment.baseline => getBaseline(child, childConstraints, span.baseline!),
},
);
}
/// Computes the layout for every inline child using the given `layoutChild`
/// function and the `maxWidth` constraint.
/// Computes the layout for every inline child using the `maxWidth` constraint.
///
/// Returns a list of [PlaceholderDimensions], representing the layout results
/// for each child managed by the [ContainerRenderObjectMixin] mixin.
///
/// The `getChildBaseline` parameter and the `layoutChild` parameter must be
/// consistent: if `layoutChild` computes the size of the child without
/// modifying the actual layout of that child, then `getChildBaseline` must
/// also be "dry", and vice versa.
///
/// Since this method does not impose a maximum height constraint on the
/// inline children, some children may become taller than this [RenderBox].
///
@ -160,10 +164,11 @@ mixin RenderInlineChildrenContainerDefaults on RenderBox, ContainerRenderObjectM
/// * [TextPainter.setPlaceholderDimensions], the method that usually takes
/// the layout results from this method as the input.
@protected
List<PlaceholderDimensions> layoutInlineChildren(double maxWidth, ChildLayouter layoutChild) {
List<PlaceholderDimensions> layoutInlineChildren(double maxWidth, ChildLayouter layoutChild, ChildBaselineGetter getChildBaseline) {
final BoxConstraints constraints = BoxConstraints(maxWidth: maxWidth);
return <PlaceholderDimensions>[
for (RenderBox? child = firstChild; child != null; child = childAfter(child))
_layoutChild(child, maxWidth, layoutChild),
_layoutChild(child, constraints, layoutChild, getChildBaseline),
];
}
@ -352,7 +357,6 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo
case RenderComparison.paint:
_textPainter.text = value;
_cachedAttributedLabels = null;
_canComputeIntrinsicsCached = null;
_cachedCombinedSemanticsInfos = null;
markNeedsPaint();
markNeedsSemanticsUpdate();
@ -361,7 +365,6 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo
_overflowShader = null;
_cachedAttributedLabels = null;
_cachedCombinedSemanticsInfos = null;
_canComputeIntrinsicsCached = null;
markNeedsLayout();
_removeSelectionRegistrarSubscription();
_disposeSelectableFragments();
@ -671,12 +674,10 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo
@override
double computeMinIntrinsicWidth(double height) {
if (!_canComputeIntrinsics()) {
return 0.0;
}
final List<PlaceholderDimensions> placeholderDimensions = layoutInlineChildren(
double.infinity,
(RenderBox child, BoxConstraints constraints) => Size(child.getMinIntrinsicWidth(double.infinity), 0.0),
ChildLayoutHelper.getDryBaseline,
);
return (_textIntrinsics..setPlaceholderDimensions(placeholderDimensions)..layout())
.minIntrinsicWidth;
@ -684,25 +685,20 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo
@override
double computeMaxIntrinsicWidth(double height) {
if (!_canComputeIntrinsics()) {
return 0.0;
}
final List<PlaceholderDimensions> placeholderDimensions = layoutInlineChildren(
double.infinity,
// Height and baseline is irrelevant as all text will be laid
// out in a single line. Therefore, using 0.0 as a dummy for the height.
(RenderBox child, BoxConstraints constraints) => Size(child.getMaxIntrinsicWidth(double.infinity), 0.0),
ChildLayoutHelper.getDryBaseline,
);
return (_textIntrinsics..setPlaceholderDimensions(placeholderDimensions)..layout())
.maxIntrinsicWidth;
}
double _computeIntrinsicHeight(double width) {
if (!_canComputeIntrinsics()) {
return 0.0;
}
return (_textIntrinsics
..setPlaceholderDimensions(layoutInlineChildren(width, ChildLayoutHelper.dryLayoutChild))
..setPlaceholderDimensions(layoutInlineChildren(width, ChildLayoutHelper.dryLayoutChild, ChildLayoutHelper.getDryBaseline))
..layout(minWidth: width, maxWidth: _adjustMaxWidth(width)))
.height;
}
@ -717,52 +713,6 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo
return _computeIntrinsicHeight(width);
}
@override
double computeDistanceToActualBaseline(TextBaseline baseline) {
assert(!debugNeedsLayout);
assert(constraints.debugAssertIsValid());
_layoutTextWithConstraints(constraints);
// TODO(garyq): Since our metric for ideographic baseline is currently
// inaccurate and the non-alphabetic baselines are based off of the
// alphabetic baseline, we use the alphabetic for now to produce correct
// layouts. We should eventually change this back to pass the `baseline`
// property when the ideographic baseline is properly implemented
// (https://github.com/flutter/flutter/issues/22625).
return _textPainter.computeDistanceToActualBaseline(TextBaseline.alphabetic);
}
/// Whether all inline widget children of this [RenderBox] support dry layout
/// calculation.
bool _canComputeDryLayoutForInlineWidgets() {
// Dry layout cannot be calculated without a full layout for
// alignments that require the baseline (baseline, aboveBaseline,
// belowBaseline).
return text.visitChildren((InlineSpan span) {
return (span is! PlaceholderSpan) || switch (span.alignment) {
ui.PlaceholderAlignment.baseline ||
ui.PlaceholderAlignment.aboveBaseline ||
ui.PlaceholderAlignment.belowBaseline => false,
ui.PlaceholderAlignment.top ||
ui.PlaceholderAlignment.middle ||
ui.PlaceholderAlignment.bottom => true,
};
});
}
bool? _canComputeIntrinsicsCached;
// Intrinsics cannot be calculated without a full layout for
// alignments that require the baseline (baseline, aboveBaseline,
// belowBaseline).
bool _canComputeIntrinsics() {
final bool returnValue = _canComputeIntrinsicsCached ??= _canComputeDryLayoutForInlineWidgets();
assert(
returnValue || RenderObject.debugCheckingIntrinsics,
'Intrinsics are not available for PlaceholderAlignment.baseline, '
'PlaceholderAlignment.aboveBaseline, or PlaceholderAlignment.belowBaseline.',
);
return returnValue;
}
@override
bool hitTestSelf(Offset position) => true;
@ -822,23 +772,40 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo
@override
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (!_canComputeIntrinsics()) {
assert(debugCannotComputeDryLayout(
reason: 'Dry layout not available for alignments that require baseline.',
));
return Size.zero;
}
final Size size = (_textIntrinsics
..setPlaceholderDimensions(layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.dryLayoutChild))
..setPlaceholderDimensions(layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.dryLayoutChild, ChildLayoutHelper.getDryBaseline))
..layout(minWidth: constraints.minWidth, maxWidth: _adjustMaxWidth(constraints.maxWidth)))
.size;
return constraints.constrain(size);
}
@override
double computeDistanceToActualBaseline(TextBaseline baseline) {
assert(!debugNeedsLayout);
assert(constraints.debugAssertIsValid());
_layoutTextWithConstraints(constraints);
// TODO(garyq): Since our metric for ideographic baseline is currently
// inaccurate and the non-alphabetic baselines are based off of the
// alphabetic baseline, we use the alphabetic for now to produce correct
// layouts. We should eventually change this back to pass the `baseline`
// property when the ideographic baseline is properly implemented
// (https://github.com/flutter/flutter/issues/22625).
return _textPainter.computeDistanceToActualBaseline(TextBaseline.alphabetic);
}
@override
double computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
assert(constraints.debugAssertIsValid());
_textIntrinsics
..setPlaceholderDimensions(layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.dryLayoutChild, ChildLayoutHelper.getDryBaseline))
..layout(minWidth: constraints.minWidth, maxWidth: _adjustMaxWidth(constraints.maxWidth));
return _textIntrinsics.computeDistanceToActualBaseline(TextBaseline.alphabetic);
}
@override
void performLayout() {
final BoxConstraints constraints = this.constraints;
_placeholderDimensions = layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.layoutChild);
_placeholderDimensions = layoutInlineChildren(constraints.maxWidth, ChildLayoutHelper.layoutChild, ChildLayoutHelper.getBaseline);
_layoutTextWithConstraints(constraints);
positionInlineChildren(_textPainter.inlinePlaceholderBoxes!);

View File

@ -94,6 +94,12 @@ mixin RenderProxyBoxMixin<T extends RenderBox> on RenderBox, RenderObjectWithChi
?? super.computeDistanceToActualBaseline(baseline);
}
@override
@protected
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
return child?.getDryBaseline(constraints, baseline);
}
@override
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
@ -292,11 +298,8 @@ class RenderConstrainedBox extends RenderProxyBox {
@override
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (child != null) {
return child!.getDryLayout(_additionalConstraints.enforce(constraints));
} else {
return _additionalConstraints.enforce(constraints).constrain(Size.zero);
}
return child?.getDryLayout(_additionalConstraints.enforce(constraints))
?? _additionalConstraints.enforce(constraints).constrain(Size.zero);
}
@override
@ -566,6 +569,11 @@ class RenderAspectRatio extends RenderProxyBox {
return _applyAspectRatio(constraints);
}
@override
double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
return super.computeDryBaseline(BoxConstraints.tight(getDryLayout(constraints)), baseline);
}
@override
void performLayout() {
size = getDryLayout(constraints);
@ -702,22 +710,16 @@ class RenderIntrinsicWidth extends RenderProxyBox {
return _applyStep(height, _stepHeight);
}
BoxConstraints _childConstraints(RenderBox child, BoxConstraints constraints) {
return constraints.tighten(
width: constraints.hasTightWidth ? null : _applyStep(child.getMaxIntrinsicWidth(constraints.maxHeight), _stepWidth),
height: stepHeight == null ? null : _applyStep(child.getMaxIntrinsicHeight(constraints.maxWidth), _stepHeight),
);
}
Size _computeSize({required ChildLayouter layoutChild, required BoxConstraints constraints}) {
if (child != null) {
if (!constraints.hasTightWidth) {
final double width = child!.getMaxIntrinsicWidth(constraints.maxHeight);
assert(width.isFinite);
constraints = constraints.tighten(width: _applyStep(width, _stepWidth));
}
if (_stepHeight != null) {
final double height = child!.getMaxIntrinsicHeight(constraints.maxWidth);
assert(height.isFinite);
constraints = constraints.tighten(height: _applyStep(height, _stepHeight));
}
return layoutChild(child!, constraints);
} else {
return constraints.smallest;
}
final RenderBox? child = this.child;
return child == null ? constraints.smallest : layoutChild(child, _childConstraints(child, constraints));
}
@override
@ -729,6 +731,12 @@ class RenderIntrinsicWidth extends RenderProxyBox {
);
}
@override
double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
final RenderBox? child = this.child;
return child?.getDryBaseline(_childConstraints(child, constraints), baseline);
}
@override
void performLayout() {
size = _computeSize(
@ -808,17 +816,15 @@ class RenderIntrinsicHeight extends RenderProxyBox {
return getMaxIntrinsicHeight(width);
}
BoxConstraints _childConstraints(RenderBox child, BoxConstraints constraints) {
return constraints.hasTightHeight
? constraints
: constraints.tighten(height: child.getMaxIntrinsicHeight(constraints.maxWidth));
}
Size _computeSize({required ChildLayouter layoutChild, required BoxConstraints constraints}) {
if (child != null) {
if (!constraints.hasTightHeight) {
final double height = child!.getMaxIntrinsicHeight(constraints.maxWidth);
assert(height.isFinite);
constraints = constraints.tighten(height: height);
}
return layoutChild(child!, constraints);
} else {
return constraints.smallest;
}
final RenderBox? child = this.child;
return child == null ? constraints.smallest : layoutChild(child, _childConstraints(child, constraints));
}
@override
@ -830,6 +836,12 @@ class RenderIntrinsicHeight extends RenderProxyBox {
);
}
@override
double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
final RenderBox? child = this.child;
return child?.getDryBaseline(_childConstraints(child, constraints), baseline);
}
@override
void performLayout() {
size = _computeSize(
@ -2596,15 +2608,9 @@ class RenderFittedBox extends RenderProxyBox {
_clipBehavior = clipBehavior,
super(child);
Alignment _resolve() => _resolvedAlignment ??= alignment.resolve(textDirection);
Alignment? _resolvedAlignment;
void _resolve() {
if (_resolvedAlignment != null) {
return;
}
_resolvedAlignment = alignment.resolve(textDirection);
}
void _markNeedResolution() {
_resolvedAlignment = null;
markNeedsPaint();
@ -2772,13 +2778,13 @@ class RenderFittedBox extends RenderProxyBox {
_hasVisualOverflow = false;
_transform = Matrix4.identity();
} else {
_resolve();
final Alignment resolvedAlignment = _resolve();
final Size childSize = child!.size;
final FittedSizes sizes = applyBoxFit(_fit, childSize, size);
final double scaleX = sizes.destination.width / sizes.source.width;
final double scaleY = sizes.destination.height / sizes.source.height;
final Rect sourceRect = _resolvedAlignment!.inscribe(sizes.source, Offset.zero & childSize);
final Rect destinationRect = _resolvedAlignment!.inscribe(sizes.destination, Offset.zero & size);
final Rect sourceRect = resolvedAlignment.inscribe(sizes.source, Offset.zero & childSize);
final Rect destinationRect = resolvedAlignment.inscribe(sizes.destination, Offset.zero & size);
_hasVisualOverflow = sourceRect.width < childSize.width || sourceRect.height < childSize.height;
assert(scaleX.isFinite && scaleY.isFinite);
_transform = Matrix4.translationValues(destinationRect.left, destinationRect.top, 0.0)
@ -3699,6 +3705,11 @@ class RenderOffstage extends RenderProxyBox {
@override
bool get sizedByParent => offstage;
@override
double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
return offstage ? null : super.computeDryBaseline(constraints, baseline);
}
@override
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {

View File

@ -114,18 +114,15 @@ class RenderPadding extends RenderShiftedBox {
_padding = padding,
super(child);
EdgeInsets? _resolvedPadding;
void _resolve() {
if (_resolvedPadding != null) {
return;
}
_resolvedPadding = padding.resolve(textDirection);
assert(_resolvedPadding!.isNonNegative);
EdgeInsets? _resolvedPaddingCache;
EdgeInsets get _resolvedPadding {
final EdgeInsets returnValue = _resolvedPaddingCache ??= padding.resolve(textDirection);
assert(returnValue.isNonNegative);
return returnValue;
}
void _markNeedResolution() {
_resolvedPadding = null;
_resolvedPaddingCache = null;
markNeedsLayout();
}
@ -160,90 +157,86 @@ class RenderPadding extends RenderShiftedBox {
@override
double computeMinIntrinsicWidth(double height) {
_resolve();
final double totalHorizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
final double totalVerticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
final EdgeInsets padding = _resolvedPadding;
if (child != null) {
// Relies on double.infinity absorption.
return child!.getMinIntrinsicWidth(math.max(0.0, height - totalVerticalPadding)) + totalHorizontalPadding;
return child!.getMinIntrinsicWidth(math.max(0.0, height - padding.vertical)) + padding.horizontal;
}
return totalHorizontalPadding;
return padding.horizontal;
}
@override
double computeMaxIntrinsicWidth(double height) {
_resolve();
final double totalHorizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
final double totalVerticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
final EdgeInsets padding = _resolvedPadding;
if (child != null) {
// Relies on double.infinity absorption.
return child!.getMaxIntrinsicWidth(math.max(0.0, height - totalVerticalPadding)) + totalHorizontalPadding;
return child!.getMaxIntrinsicWidth(math.max(0.0, height - padding.vertical)) + padding.horizontal;
}
return totalHorizontalPadding;
return padding.horizontal;
}
@override
double computeMinIntrinsicHeight(double width) {
_resolve();
final double totalHorizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
final double totalVerticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
final EdgeInsets padding = _resolvedPadding;
if (child != null) {
// Relies on double.infinity absorption.
return child!.getMinIntrinsicHeight(math.max(0.0, width - totalHorizontalPadding)) + totalVerticalPadding;
return child!.getMinIntrinsicHeight(math.max(0.0, width - padding.horizontal)) + padding.vertical;
}
return totalVerticalPadding;
return padding.vertical;
}
@override
double computeMaxIntrinsicHeight(double width) {
_resolve();
final double totalHorizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
final double totalVerticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
final EdgeInsets padding = _resolvedPadding;
if (child != null) {
// Relies on double.infinity absorption.
return child!.getMaxIntrinsicHeight(math.max(0.0, width - totalHorizontalPadding)) + totalVerticalPadding;
return child!.getMaxIntrinsicHeight(math.max(0.0, width - padding.horizontal)) + padding.vertical;
}
return totalVerticalPadding;
return padding.vertical;
}
@override
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
_resolve();
assert(_resolvedPadding != null);
final EdgeInsets padding = _resolvedPadding;
if (child == null) {
return constraints.constrain(Size(
_resolvedPadding!.left + _resolvedPadding!.right,
_resolvedPadding!.top + _resolvedPadding!.bottom,
));
return constraints.constrain(Size(padding.horizontal, padding.vertical));
}
final BoxConstraints innerConstraints = constraints.deflate(_resolvedPadding!);
final BoxConstraints innerConstraints = constraints.deflate(padding);
final Size childSize = child!.getDryLayout(innerConstraints);
return constraints.constrain(Size(
_resolvedPadding!.left + childSize.width + _resolvedPadding!.right,
_resolvedPadding!.top + childSize.height + _resolvedPadding!.bottom,
padding.horizontal + childSize.width,
padding.vertical + childSize.height,
));
}
@override
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
final RenderBox? child = this.child;
if (child == null) {
return null;
}
final EdgeInsets padding = _resolvedPadding;
final BoxConstraints innerConstraints = constraints.deflate(padding);
final BaselineOffset result = BaselineOffset(child.getDryBaseline(innerConstraints, baseline)) + padding.top;
return result.offset;
}
@override
void performLayout() {
final BoxConstraints constraints = this.constraints;
_resolve();
assert(_resolvedPadding != null);
final EdgeInsets padding = _resolvedPadding;
if (child == null) {
size = constraints.constrain(Size(
_resolvedPadding!.left + _resolvedPadding!.right,
_resolvedPadding!.top + _resolvedPadding!.bottom,
));
size = constraints.constrain(Size(padding.horizontal, padding.vertical));
return;
}
final BoxConstraints innerConstraints = constraints.deflate(_resolvedPadding!);
final BoxConstraints innerConstraints = constraints.deflate(padding);
child!.layout(innerConstraints, parentUsesSize: true);
final BoxParentData childParentData = child!.parentData! as BoxParentData;
childParentData.offset = Offset(_resolvedPadding!.left, _resolvedPadding!.top);
childParentData.offset = Offset(padding.left, padding.top);
size = constraints.constrain(Size(
_resolvedPadding!.left + child!.size.width + _resolvedPadding!.right,
_resolvedPadding!.top + child!.size.height + _resolvedPadding!.bottom,
padding.horizontal + child!.size.width,
padding.vertical + child!.size.height,
));
}
@ -252,7 +245,7 @@ class RenderPadding extends RenderShiftedBox {
super.debugPaintSize(context, offset);
assert(() {
final Rect outerRect = offset & size;
debugPaintPadding(context.canvas, outerRect, child != null ? _resolvedPadding!.deflateRect(outerRect) : null);
debugPaintPadding(context.canvas, outerRect, child != null ? _resolvedPaddingCache!.deflateRect(outerRect) : null);
return true;
}());
}
@ -690,6 +683,22 @@ class RenderConstrainedOverflowBox extends RenderAligningShiftedBox {
};
}
@override
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
final RenderBox? child = this.child;
if (child == null) {
return null;
}
final BoxConstraints childConstraints = _getInnerConstraints(constraints);
final double? result = child.getDryBaseline(childConstraints, baseline);
if (result == null) {
return null;
}
final Size childSize = child.getDryLayout(childConstraints);
final Size size = getDryLayout(constraints);
return result + resolvedAlignment.alongOffset(size - childSize as Offset).dy;
}
@override
void performLayout() {
if (child != null) {
@ -841,6 +850,22 @@ class RenderConstraintsTransformBox extends RenderAligningShiftedBox with DebugO
return childSize == null ? constraints.smallest : constraints.constrain(childSize);
}
@override
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
final RenderBox? child = this.child;
if (child == null) {
return null;
}
final BoxConstraints childConstraints = constraintsTransform(constraints);
final double? result = child.getDryBaseline(childConstraints, baseline);
if (result == null) {
return null;
}
final Size childSize = child.getDryLayout(childConstraints);
final Size size = constraints.constrain(childSize);
return result + resolvedAlignment.alongOffset(size - childSize as Offset).dy;
}
Rect _overflowContainerRect = Rect.zero;
Rect _overflowChildRect = Rect.zero;
bool _isOverflowing = false;
@ -997,10 +1022,23 @@ class RenderSizedOverflowBox extends RenderAligningShiftedBox {
@override
double? computeDistanceToActualBaseline(TextBaseline baseline) {
if (child != null) {
return child!.getDistanceToActualBaseline(baseline);
return child?.getDistanceToActualBaseline(baseline)
?? super.computeDistanceToActualBaseline(baseline);
}
@override
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
final RenderBox? child = this.child;
if (child == null) {
return null;
}
return super.computeDistanceToActualBaseline(baseline);
final double? result = child.getDryBaseline(constraints, baseline);
if (result == null) {
return null;
}
final Size childSize = child.getDryLayout(constraints);
final Size size = getDryLayout(constraints);
return result + resolvedAlignment.alongOffset(size - childSize as Offset).dy;
}
@override
@ -1163,6 +1201,22 @@ class RenderFractionallySizedOverflowBox extends RenderAligningShiftedBox {
return constraints.constrain(_getInnerConstraints(constraints).constrain(Size.zero));
}
@override
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
final RenderBox? child = this.child;
if (child == null) {
return null;
}
final BoxConstraints childConstraints = _getInnerConstraints(constraints);
final double? result = child.getDryBaseline(childConstraints, baseline);
if (result == null) {
return null;
}
final Size childSize = child.getDryLayout(childConstraints);
final Size size = getDryLayout(constraints);
return result + resolvedAlignment.alongOffset(size - childSize as Offset).dy;
}
@override
void performLayout() {
if (child != null) {
@ -1359,6 +1413,23 @@ class RenderCustomSingleChildLayoutBox extends RenderShiftedBox {
return _getSize(constraints);
}
@override
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
final RenderBox? child = this.child;
if (child == null) {
return null;
}
final BoxConstraints childConstraints = delegate.getConstraintsForChild(constraints);
final double? result = child.getDryBaseline(childConstraints, baseline);
if (result == null) {
return null;
}
return result + delegate.getPositionForChild(
_getSize(constraints),
childConstraints.isTight ? childConstraints.smallest : child.getDryLayout(childConstraints),
).dy;
}
@override
void performLayout() {
size = _getSize(constraints);

View File

@ -325,6 +325,15 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
return Size.zero;
}
@override
double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
assert(debugCannotComputeDryLayout(reason:
'Calculating the dry baseline would require running the layout callback '
'speculatively, which might mutate the live render object tree.',
));
return null;
}
@override
void performLayout() {
final BoxConstraints constraints = this.constraints;
@ -339,10 +348,8 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
@override
double? computeDistanceToActualBaseline(TextBaseline baseline) {
if (child != null) {
return child!.getDistanceToActualBaseline(baseline);
}
return super.computeDistanceToActualBaseline(baseline);
return child?.getDistanceToActualBaseline(baseline)
?? super.computeDistanceToActualBaseline(baseline);
}
@override

View File

@ -410,6 +410,44 @@ class _RenderOverflowBar extends RenderBox
return defaultComputeDistanceToHighestActualBaseline(baseline);
}
@override
double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
final BoxConstraints childConstraints = constraints.loosen();
final (RenderBox? Function(RenderBox) next, RenderBox? startChild) = switch (overflowDirection) {
VerticalDirection.down => (childAfter, firstChild),
VerticalDirection.up => (childBefore, lastChild),
};
double maxChildHeight = 0.0;
double y = 0.0;
double childrenWidth = 0.0;
BaselineOffset minHorizontalBaseline = BaselineOffset.noBaseline;
BaselineOffset verticalBaseline = BaselineOffset.noBaseline;
for (RenderBox? child = startChild; child != null; child = next(child)) {
final Size childSize = child.getDryLayout(childConstraints);
final double heightDiff = childSize.height - maxChildHeight;
if (heightDiff > 0) {
minHorizontalBaseline += heightDiff / 2;
maxChildHeight = childSize.height;
}
final BaselineOffset baselineOffset = BaselineOffset(child.getDryBaseline(childConstraints, baseline));
if (baselineOffset != null) {
verticalBaseline ??= baselineOffset + y;
minHorizontalBaseline = minHorizontalBaseline.minOf(baselineOffset + (maxChildHeight - childSize.height));
}
y += childSize.height + overflowSpacing;
childrenWidth += childSize.width;
}
assert((verticalBaseline == null) == (minHorizontalBaseline == null));
return childrenWidth + spacing * (childCount - 1) > constraints.maxWidth
? verticalBaseline.offset
: minHorizontalBaseline.offset;
}
@override
Size computeDryLayout(BoxConstraints constraints) {
RenderBox? child = firstChild;

View File

@ -379,6 +379,12 @@ class _RenderScaledInlineWidget extends RenderBox with RenderObjectWithChildMixi
};
}
@override
double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
final double? distance = child?.getDryBaseline(BoxConstraints(maxWidth: constraints.maxWidth / scale), baseline);
return distance == null ? null : scale * distance;
}
@override
Size computeDryLayout(BoxConstraints constraints) {
assert(!constraints.hasBoundedHeight);

View File

@ -21,16 +21,18 @@ class TestSingleChildLayoutDelegate extends SingleChildLayoutDelegate {
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
assert(!RenderObject.debugCheckingIntrinsics);
constraintsFromGetConstraintsForChild = constraints;
if (!RenderObject.debugCheckingIntrinsics) {
constraintsFromGetConstraintsForChild = constraints;
}
return const BoxConstraints(minWidth: 100.0, maxWidth: 150.0, minHeight: 200.0, maxHeight: 400.0);
}
@override
Offset getPositionForChild(Size size, Size childSize) {
assert(!RenderObject.debugCheckingIntrinsics);
sizeFromGetPositionForChild = size;
childSizeFromGetPositionForChild = childSize;
if (!RenderObject.debugCheckingIntrinsics) {
sizeFromGetPositionForChild = size;
childSizeFromGetPositionForChild = childSize;
}
return Offset.zero;
}