New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
migrate rendering to nullsafety #64456
Conversation
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat. Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
Gold has detected about 3 untriaged digest(s) on patchset 1. |
Gold has detected about 3 untriaged digest(s) on patchset 1. |
ed0efae
to
f14df20
Compare
@@ -634,7 +633,7 @@ class BoxConstraints extends Constraints { | |||
/// | |||
/// * [RenderBox.hitTest], which documents more details around hit testing | |||
/// [RenderBox]es. | |||
typedef BoxHitTest = bool Function(BoxHitTestResult result, Offset position); | |||
typedef BoxHitTest = bool Function(BoxHitTestResult result, Offset? position); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
position should be non-nullable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here i also added:
/// Method signature for hit testing a [RenderBox] with a manually
/// managed position (one that is passed out-of-band).
///
/// Used by [RenderSliverSingleBoxAdapter.hitTestBoxChild] to hit test
/// [RenderBox] children of a [RenderSliver].
///
/// See also:
///
/// * [RenderBox.hitTest], which documents more details around hit testing
/// [RenderBox]es.
typedef BoxHitTestWithOutOfBandPosition = bool Function(BoxHitTestResult result);
@required Offset position, | ||
@required BoxHitTest hitTest, | ||
required Matrix4? transform, | ||
required Offset? position, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
position should be non nullable
@required BoxHitTest hitTest, | ||
required Matrix4? transform, | ||
required Offset? position, | ||
required BoxHitTest hitTest, | ||
}) { | ||
assert(hitTest != null); | ||
if (transform != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert position isn't null
@required Offset position, | ||
@required BoxHitTest hitTest, | ||
required Offset? offset, | ||
required Offset? position, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here i think position should be non-nullable
final Offset? transformedPosition = position == null || offset == null | ||
? position | ||
: position - offset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final Offset? transformedPosition = position == null || offset == null | |
? position | |
: position - offset; | |
final Offset transformedPosition = offset == null ? position : position - offset; |
@required Offset position, | ||
@required BoxHitTest hitTest, | ||
required Matrix4? transform, | ||
required Offset? position, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-nullable position here too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the doc explicitally mentions null:
/// The `position` argument may be null, which will be forwarded to the
/// `hitTest` callback as-is. Using null as the position can be useful if
/// the child speaks a different hit test protocol then the parent and the
/// position is not required to do the actual hit testing in that protocol.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm proposing removing that and replacing it with dedicated methods to handle that case.
final Offset? transformedPosition = position == null || transform == null | ||
? position | ||
: MatrixUtils.transformPoint(transform, position); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final Offset? transformedPosition = position == null || transform == null | |
? position | |
: MatrixUtils.transformPoint(transform, position); | |
assert(position != null); | |
final Offset transformedPosition = transform == null ? | |
position : MatrixUtils.transformPoint(transform, position); |
}) { | ||
assert(hitTest != null); | ||
final Offset transformedPosition = position == null || transform == null | ||
final Offset? transformedPosition = position == null || transform == null | ||
? position | ||
: MatrixUtils.transformPoint(transform, position); | ||
if (transform != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at the end of this class i added:
/// Pass-through method for adding a hit test while manually managing
/// the position transformation logic.
///
/// The actual hit testing of the child needs to be implemented in the
/// provided `hitTest` callback. The position needs to be handled by
/// the caller.
///
/// The function returns the return value of the `hitTest` callback.
///
/// A `paintOffset`, `paintTransform`, or `rawTransform` should be
/// passed to the method to update the hit test stack.
///
/// * `paintOffset` has the semantics of the `offset` passed to
/// [addWithPaintOffset].
///
/// * `paintTransform` has the semantics of the `transform` passed to
/// [addWithPaintTransform], except thit it must be invertible; it
/// is the responsibility of the caller to ensure this.
///
/// * `rawTransform` has the semantics of the `transform` passed to
/// [addWithRawTransform].
///
/// Exactly one of these must be non-null.
///
/// See also:
///
/// * [addWithPaintTransform], which takes a generic paint transform matrix and
/// documents the intended usage of this API in more detail.
bool addWithOutOfBandPosition({
Offset? paintOffset,
Matrix4? paintTransform,
Matrix4? rawTransform,
required BoxHitTestWithOutOfBandPosition hitTest,
}) {
assert(hitTest != null);
assert((paintOffset == null && paintTransform == null && rawTransform != null) ||
(paintOffset == null && paintTransform != null && rawTransform == null) ||
(paintOffset != null && paintTransform == null && rawTransform == null));
if (paintOffset != null) {
pushOffset(-paintOffset);
} else if (rawTransform != null) {
pushTransform(rawTransform);
} else {
assert(paintTransform != null);
paintTransform = Matrix4.tryInvert(PointerEvent.removePerspectiveTransform(paintTransform!));
assert(paintTransform != null);
pushTransform(paintTransform!);
}
final bool isHit = hitTest(this);
popTransform();
return isHit;
}
@@ -311,7 +310,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix | |||
/// When the style is [CacheExtentStyle.viewport], it is the main axis extent | |||
/// of the viewport multiplied by the requested cache extent, which is still | |||
/// expressed in pixels. | |||
double _calculatedCacheExtent; | |||
double? _calculatedCacheExtent; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// TODO(ianh): cacheExtent/cacheExtentStyle should be a single | |
// object that specifies both the scalar value and the unit, not a | |
// pair of independent setters. Changing that would allow a more | |
// rational API and would let us make the getter non-nullable. | |
@@ -311,7 +310,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix | |||
/// When the style is [CacheExtentStyle.viewport], it is the main axis extent | |||
/// of the viewport multiplied by the requested cache extent, which is still | |||
/// expressed in pixels. | |||
double _calculatedCacheExtent; | |||
double? _calculatedCacheExtent; | |||
|
|||
/// {@template flutter.rendering.viewport.cacheExtentStyle} | |||
/// Controls how the [cacheExtent] is interpreted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replace from next line until just before the getter:
/// If set to [CacheExtentStyle.pixel], the [cacheExtent] will be
/// treated as a logical pixels, and the default [cacheExtent] is
/// [RenderAbstractViewport.defaultCacheExtent].
///
/// If set to [CacheExtentStyle.viewport], the [cacheExtent] will be
/// treated as a multiplier for the main axis extent of the
/// viewport. In this case there is no default [cacheExtent]; it
/// must be explicitly specified.
/// {@endtemplate}
///
/// Changing the [cacheExtentStyle] without also changing the [cacheExtent]
/// is rarely the correct choice.
@@ -297,7 +296,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix | |||
/// {@endtemplate} | |||
double get cacheExtent => _cacheExtent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replace from the getter until the assert:
///
/// The getter can never return null, but the field is nullable
/// because the setter can be set to null to reset the value to
/// [RenderAbstractViewport.defaultCacheExtent] (in which case
/// [cacheExtentStyle] must be [CacheExtentStyle.pixel]).
///
/// See also:
///
/// * [cacheExtentStyle], which controls the units of the [cacheExtent].
double? get cacheExtent => _cacheExtent;
double _cacheExtent;
set cacheExtent(double? value) {
value ??= RenderAbstractViewport.defaultCacheExtent;
applyPaintTransform(child, transform); | ||
final bool isHit = result.addWithPaintTransform( | ||
transform: transform, | ||
position: null, // Manually adapting from box to sliver position below. | ||
hitTest: (BoxHitTestResult result, Offset _) { | ||
hitTest: (BoxHitTestResult result, Offset? _) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
applyPaintTransform(child, transform); | |
final bool isHit = result.addWithPaintTransform( | |
transform: transform, | |
position: null, // Manually adapting from box to sliver position below. | |
hitTest: (BoxHitTestResult result, Offset _) { | |
hitTest: (BoxHitTestResult result, Offset? _) { | |
applyPaintTransform(child, transform); // must be invertible | |
final bool isHit = result.addWithOutOfBandPosition( | |
paintTransform: transform, | |
hitTest: (BoxHitTestResult result) { |
@@ -1510,10 +1507,10 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat | |||
void updateOutOfBandData(GrowthDirection growthDirection, SliverGeometry childLayoutGeometry) { | |||
switch (growthDirection) { | |||
case GrowthDirection.forward: | |||
_maxScrollExtent += childLayoutGeometry.scrollExtent; | |||
_maxScrollExtent = _maxScrollExtent + childLayoutGeometry.scrollExtent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+= should work fine here since _maxScrollExtent is late non-nullable
break; | ||
case GrowthDirection.reverse: | ||
_minScrollExtent -= childLayoutGeometry.scrollExtent; | ||
_minScrollExtent = _minScrollExtent - childLayoutGeometry.scrollExtent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar here
current = childBefore(current); | ||
} | ||
return pinnedExtent; | ||
} | ||
return null; | ||
} | ||
|
||
@override |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add this inside the applyPaintTransform method:
// Hit test logic relies on this always providing an invertible matrix.
while (current != child) { | ||
pinnedExtent += current.geometry.maxScrollObstructionExtent; | ||
pinnedExtent += current!.geometry!.maxScrollObstructionExtent; | ||
current = childAfter(current); | ||
} | ||
return pinnedExtent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add to applyPaintTransform:
// Hit test logic relies on this always providing an invertible matrix.
@@ -95,7 +93,7 @@ abstract class ViewportOffset extends ChangeNotifier { | |||
/// | |||
/// This object notifies its listeners when this value changes (except when | |||
/// the value changes due to [correctBy]). | |||
double get pixels; | |||
double? get pixels; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this should be non-nullable. it would simplify a ton of other code.
In addition to my comments above, the following changes would also be good to do at the same time (some are required by some of the changes I suggested): https://github.com/flutter/flutter/pull/64476/files#diff-acd2b473dd8ae3b5cab347ba47c55c94R902 until the end of the PR |
I applied the rest of my review comments and uploaded #64621, please feel free to continue from there if there's more work to be done. |
Continued in #64621 |
Description
NNBD migration for rendering
Related Issues
Tests
I added the following tests:
None
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.///
).flutter analyze --flutter-repo
) does not report any problems on my PR.Breaking Change
Did any tests fail when you ran them? Please read Handling breaking changes.