Make constraints a covariant argument in RenderBox.computeDryLayout() (#136432)

Some render box subclasses have a specific layout contract that is tightly coupled with other render box subclasses (e.g. two private classes in a local project file). In these cases, it is also possible that they use a constraints object that is a subclass of `BoxConstraints`. To allow for this, this change makes the `constraints` argument to `RenderBox.computeDryLayout()` a covariant argument.

For completeness' sake, this updates the other render objects in the rendering package to also use the covariant keyword for this argument.
This commit is contained in:
Todd Volkert 2023-10-12 21:10:29 -04:00 committed by GitHub
parent 0f082889a8
commit bc688cf0df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 113 additions and 38 deletions

View file

@ -264,7 +264,8 @@ class RenderAnimatedSize extends RenderAligningShiftedBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (child == null || constraints.isTight) {
return constraints.smallest;
}

View file

@ -1906,7 +1906,7 @@ abstract class RenderBox extends RenderObject {
/// [debugCannotComputeDryLayout] from within an assert and return a dummy
/// value of `const Size(0, 0)`.
@protected
Size computeDryLayout(BoxConstraints constraints) {
Size computeDryLayout(covariant BoxConstraints constraints) {
assert(debugCannotComputeDryLayout(
error: FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('The ${objectRuntimeType(this, 'RenderBox')} class does not implement "computeDryLayout".'),

View file

@ -393,7 +393,8 @@ class RenderCustomMultiChildLayoutBox extends RenderBox
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _getSize(constraints);
}

View file

@ -2270,7 +2270,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
bool get _canComputeIntrinsics => _canComputeIntrinsicsCached ??= _canComputeDryLayoutForInlineWidgets();
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (!_canComputeIntrinsics) {
assert(debugCannotComputeDryLayout(
reason: 'Dry layout not available for alignments that require baseline.',
@ -2630,7 +2631,8 @@ class _RenderEditableCustomPaint extends RenderBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) => constraints.biggest;
@protected
Size computeDryLayout(covariant BoxConstraints constraints) => constraints.biggest;
}
/// An interface that paints within a [RenderEditable]'s bounds, above or

View file

@ -4,6 +4,8 @@
import 'dart:ui' as ui show Paragraph, ParagraphBuilder, ParagraphConstraints, ParagraphStyle, TextStyle;
import 'package:flutter/foundation.dart';
import 'box.dart';
import 'object.dart';
@ -77,7 +79,8 @@ class RenderErrorBox extends RenderBox {
bool hitTestSelf(Offset position) => true;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.constrain(const Size(_kMaxWidth, _kMaxHeight));
}

View file

@ -653,7 +653,8 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (!_canComputeIntrinsics) {
assert(debugCannotComputeDryLayout(
reason: 'Dry layout cannot be computed for CrossAxisAlignment.baseline, which requires a full layout.',

View file

@ -299,7 +299,8 @@ class RenderFlow extends RenderBox
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _getSize(constraints);
}

View file

@ -5,6 +5,7 @@
import 'dart:ui' as ui show Image;
import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart';
import 'box.dart';
import 'object.dart';
@ -401,7 +402,8 @@ class RenderImage extends RenderBox {
bool hitTestSelf(Offset position) => true;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _sizeForConstraints(constraints);
}

View file

@ -4,6 +4,8 @@
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'box.dart';
import 'object.dart';
@ -62,7 +64,8 @@ class RenderListBody extends RenderBox
Axis get mainAxis => axisDirectionToAxis(axisDirection);
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
assert(_debugCheckConstraints(constraints));
double mainAxisExtent = 0.0;
RenderBox? child = firstChild;

View file

@ -5,6 +5,7 @@
import 'dart:math' as math;
import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart';
import 'package:vector_math/vector_math_64.dart' show Matrix4;
import 'box.dart';
@ -615,7 +616,8 @@ class RenderListWheelViewport
bool get sizedByParent => true;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.biggest;
}

View file

@ -772,7 +772,8 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (!_canComputeIntrinsics()) {
assert(debugCannotComputeDryLayout(
reason: 'Dry layout not available for alignments that require baseline.',

View file

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'box.dart';
import 'layer.dart';
import 'object.dart';
@ -157,7 +159,8 @@ class RenderPerformanceOverlay extends RenderBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.constrain(Size(double.infinity, _intrinsicHeight));
}

View file

@ -148,7 +148,8 @@ class RenderAndroidView extends PlatformViewRenderBox {
bool get isRepaintBoundary => true;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.biggest;
}
@ -319,7 +320,8 @@ abstract class RenderDarwinPlatformView<T extends DarwinPlatformViewController>
_UiKitViewGestureRecognizer? _gestureRecognizer;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.biggest;
}
@ -711,7 +713,8 @@ class PlatformViewRenderBox extends RenderBox with _PlatformViewGestureMixin {
bool get isRepaintBoundary => true;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.biggest;
}

View file

@ -95,7 +95,8 @@ mixin RenderProxyBoxMixin<T extends RenderBox> on RenderBox, RenderObjectWithChi
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return child?.getDryLayout(constraints) ?? computeSizeForNoChild(constraints);
}
@ -284,7 +285,8 @@ class RenderConstrainedBox extends RenderProxyBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (child != null) {
return child!.getDryLayout(_additionalConstraints.enforce(constraints));
} else {
@ -383,7 +385,8 @@ class RenderLimitedBox extends RenderProxyBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _computeSize(
constraints: constraints,
layoutChild: ChildLayoutHelper.dryLayoutChild,
@ -565,7 +568,8 @@ class RenderAspectRatio extends RenderProxyBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _applyAspectRatio(constraints);
}
@ -726,7 +730,8 @@ class RenderIntrinsicWidth extends RenderProxyBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _computeSize(
layoutChild: ChildLayoutHelper.dryLayoutChild,
constraints: constraints,
@ -826,7 +831,8 @@ class RenderIntrinsicHeight extends RenderProxyBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _computeSize(
layoutChild: ChildLayoutHelper.dryLayoutChild,
constraints: constraints,
@ -2672,7 +2678,8 @@ class RenderFittedBox extends RenderProxyBox {
// TODO(ianh): The intrinsic dimensions of this box are wrong.
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (child != null) {
final Size childSize = child!.getDryLayout(const BoxConstraints());
@ -3693,7 +3700,8 @@ class RenderOffstage extends RenderProxyBox {
bool get sizedByParent => offstage;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (offstage) {
return constraints.smallest;
}

View file

@ -4,6 +4,7 @@
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:vector_math/vector_math_64.dart';
import 'box.dart';
@ -74,7 +75,8 @@ class RenderRotatedBox extends RenderBox with RenderObjectWithChildMixin<RenderB
Matrix4? _paintTransform;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (child == null) {
return constraints.smallest;
}

View file

@ -205,7 +205,8 @@ class RenderPadding extends RenderShiftedBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
_resolve();
assert(_resolvedPadding != null);
if (child == null) {
@ -428,7 +429,8 @@ class RenderPositionedBox extends RenderAligningShiftedBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
final bool shrinkWrapWidth = _widthFactor != null || constraints.maxWidth == double.infinity;
final bool shrinkWrapHeight = _heightFactor != null || constraints.maxHeight == double.infinity;
if (child != null) {
@ -637,7 +639,8 @@ class RenderConstrainedOverflowBox extends RenderAligningShiftedBox {
bool get sizedByParent => true;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.biggest;
}
@ -772,7 +775,8 @@ class RenderConstraintsTransformBox extends RenderAligningShiftedBox with DebugO
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
final Size? childSize = child?.getDryLayout(constraintsTransform(constraints));
return childSize == null ? constraints.smallest : constraints.constrain(childSize);
}
@ -940,7 +944,8 @@ class RenderSizedOverflowBox extends RenderAligningShiftedBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.constrain(_requestedSize);
}
@ -1089,7 +1094,8 @@ class RenderFractionallySizedOverflowBox extends RenderAligningShiftedBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (child != null) {
final Size childSize = child!.getDryLayout(_getInnerConstraints(constraints));
return constraints.constrain(childSize);
@ -1288,7 +1294,8 @@ class RenderCustomSingleChildLayoutBox extends RenderShiftedBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _getSize(constraints);
}
@ -1355,7 +1362,8 @@ class RenderBaseline extends RenderShiftedBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (child != null) {
assert(debugCannotComputeDryLayout(
reason: 'Baseline metrics are only available after a full layout.',

View file

@ -547,7 +547,8 @@ class RenderStack extends RenderBox
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _computeSize(
constraints: constraints,
layoutChild: ChildLayoutHelper.dryLayoutChild,

View file

@ -1024,7 +1024,8 @@ class RenderTable extends RenderBox {
}
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
if (rows * columns == 0) {
return constraints.constrain(Size.zero);
}

View file

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'box.dart';
import 'layer.dart';
import 'object.dart';
@ -84,7 +86,8 @@ class TextureBox extends RenderBox {
bool get isRepaintBoundary => true;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return constraints.biggest;
}

View file

@ -1411,7 +1411,8 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
bool get sizedByParent => true;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
assert(debugCheckHasBoundedAxis(axis, constraints));
return constraints.biggest;
}

View file

@ -4,6 +4,8 @@
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'box.dart';
import 'layer.dart';
import 'layout_helper.dart';
@ -493,7 +495,8 @@ class RenderWrap extends RenderBox
bool _hasVisualOverflow = false;
@override
Size computeDryLayout(BoxConstraints constraints) {
@protected
Size computeDryLayout(covariant BoxConstraints constraints) {
return _computeDryLayout(constraints);
}

View file

@ -1825,11 +1825,13 @@ void main() {
);
layout(editable, constraints: constraints);
// ignore: invalid_use_of_protected_member
final double initialWidth = editable.computeDryLayout(constraints).width;
expect(initialWidth, 500);
// Turn off forceLine. Now the width should be significantly smaller.
editable.forceLine = false;
// ignore: invalid_use_of_protected_member
expect(editable.computeDryLayout(constraints).width, lessThan(initialWidth));
});

View file

@ -961,10 +961,17 @@ void main() {
expect(fancyProxyBox.fancyMethod(), 36);
// Box has behavior from RenderProxyBox:
expect(
// ignore: invalid_use_of_protected_member
fancyProxyBox.computeDryLayout(const BoxConstraints(minHeight: 8)),
const Size(0, 8),
);
});
test('computeDryLayout constraints are covariant', () {
final RenderBoxWithTestConstraints box = RenderBoxWithTestConstraints();
const TestConstraints constraints = TestConstraints(testValue: 6);
expect(box.computeDryLayout(constraints), const Size.square(6));
});
}
class _TestRectClipper extends CustomClipper<Rect> {
@ -1087,3 +1094,19 @@ void expectAssertionError() {
}
typedef DebugPaintCallback = void Function(PaintingContext context, Offset offset);
class TestConstraints extends BoxConstraints {
const TestConstraints({
double extent = 100,
required this.testValue,
}) : super(maxWidth: extent, maxHeight: extent);
final double testValue;
}
class RenderBoxWithTestConstraints extends RenderProxyBox {
@override
Size computeDryLayout(TestConstraints constraints) {
return constraints.constrain(Size.square(constraints.testValue));
}
}