这是indexloc提供的服务,不要输入任何密码
Skip to content

RenderFlex baseline intrinsics #145483

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

Merged

Conversation

LongCatIsLooong
Copy link
Contributor

Implements RenderFlex intrinsics calculation when children are baseline aligned in the cross axis.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added the framework flutter/packages/flutter repository. See also f: labels. label Mar 20, 2024
@LongCatIsLooong LongCatIsLooong force-pushed the RenderFlex-baseline-intrinsics branch from 9c518bc to f1655ee Compare March 20, 2024 17:13
@LongCatIsLooong LongCatIsLooong marked this pull request as ready for review March 20, 2024 18:10
reason: 'Baseline metrics are only available after a full layout.',
));
return Size.zero;
return _computeSizes(constraints, ChildLayoutHelper.dryLayoutChild, ChildLayoutHelper.getDryBaseline).$1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using $1 could you give the items in the record meaningful names that could be used here? That would also remove the guesswork from figuring out what the "double" represents?

@@ -1419,33 +1420,46 @@ class RenderBaseline extends RenderShiftedBox {
markNeedsLayout();
}

(Size, double) _computeSizes(covariant BoxConstraints constraints, ChildLayouter layoutChild, ChildBaselineGetter computeBaseline) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: shoud the last argument be named getBaseline (to avoid the confusion of whether the method passed in here should use the getBaseline methods over the computeBaseline methods)?

}
final BoxConstraints childConstraints = constraints.loosen();
final Size childSize = layoutChild(child, childConstraints);
final double childBaseline = computeBaseline(child, childConstraints, baselineType) ?? childSize.height;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my own understanding: There is a slight semantics change here, right? Previously, we would blow up if the child didn't have a baseline? Now, we assume the baseline to be the child's height. I suspect that this is fine, just making sure that this is intentional... (Maybe also worthwhile to add a test for this case)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right now it returns null if the child doesn't have a baseline.

if (result1 == null || result2 == null) {
return this.baseline;
}
return this.baseline + result1 - result2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, the new dry baseline and dry layout support is indirectly already tested, but I think this logic deserves some dedicated tests.

Comment on lines 15 to 16
// A type that describes a 2D size along the main axis and the cross axis of a
// [RenderFlex].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what this represents. Isn't every size by default aligned with the cross and main axis? What does it mean to "convert" a size to a direction?

Also: Should this just be a regular class with two fields: mainAxisExtent and crossAxisExtent? How do we benefit from wrapping Size here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's just ({double mainAxisExtent, double crossAxisExtent}). Under the hood it's still a size so I don't have to reimplement methods like BoxConstraints.constrained(Size size).


static const _LayoutAxisDimensions empty = _LayoutAxisDimensions((axisSize: _AxisSize(Size.zero), ascentDescent: null));

// Updates the `current` _LayoutAxisDimensions with the dimensions of the given
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH, it is not clear to me what updating a _LayoutAxisDimensions with a _AxisSize means semantically? What does this do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the class with _AscentDscent and _AxisSize. Both of them have a + binary operator to add to the sizes when a new child is laid out.

}
inflexibleSpace += mainSize;
maxCrossSize = math.max(maxCrossSize, crossSize);
Size computeIntrinsicCrossExtentForChild(RenderBox child, BoxConstraints constraints) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: these names seem inaccurate. It does not only return the extend, it returns a full size.

FWIW, I found this code easier to follow when it was implemented in terms of mainExtend and crossExtend and not in terms of width/height.

}

return maxCrossSize;
return _computeSizes(constraints: extentConstraints, layoutChild: computeIntrinsicCrossExtentForChild, computeBaseline: ChildLayoutHelper.getDryBaseline).size.crossAxisExtent;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and elsewhere in this method: these long method calls should probably be formatted over multiple lines.

@@ -12,6 +12,84 @@ import 'layer.dart';
import 'layout_helper.dart';
import 'object.dart';

// A type that describes a 2D size along the main axis and the cross axis of a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I found the sizing and positioning algorithm way harder to follow with the _AxisSize and _LayoutAxisDimensions abstractions in place - compared to what it was before. Part of the problem is that after reading everything I couldn't explain what an _AxisSize or a _LayoutAxisDimensions is, which makes me think that these are not helpful abstractions?

Comment on lines 676 to 677
// `defaultComputeDistanceToFirstActualBaseline` does not work even for
// Columns, because the children reorder with VerticalDirection.up.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it a bug that we used defaultComputeDistanceToFirstActualBaseline here before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. there's a test that would fail if this diff gets reverted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to revert this change because of G3 failures. Will create an issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LongCatIsLooong LongCatIsLooong force-pushed the RenderFlex-baseline-intrinsics branch from 2a676e7 to 8b7a1f5 Compare March 22, 2024 07:15
@LongCatIsLooong LongCatIsLooong force-pushed the RenderFlex-baseline-intrinsics branch 2 times, most recently from e81b19d to 1503b30 Compare March 22, 2024 08:41
@LongCatIsLooong LongCatIsLooong force-pushed the RenderFlex-baseline-intrinsics branch from 1503b30 to 899e331 Compare March 22, 2024 08:47
@LongCatIsLooong
Copy link
Contributor Author

LongCatIsLooong commented Mar 22, 2024

@goderbauer I found it strange that the last flex child gets the remaining main axis extent instead of flex * spacePerFlex (here). That makes the last flex child special if other flex children opt to not take the full main extent allowance offered to them. I changed the implementation and no existing tests fail. Does that sound like a reasonable change to make?

@LongCatIsLooong LongCatIsLooong force-pushed the RenderFlex-baseline-intrinsics branch from 179eaaa to 5e27bbb Compare March 22, 2024 20:46
@LongCatIsLooong LongCatIsLooong force-pushed the RenderFlex-baseline-intrinsics branch from 5e27bbb to 9fac18c Compare March 22, 2024 20:52
@goderbauer
Copy link
Member

I found it strange that the last flex child gets the remaining main axis extent instead of flex * spacePerFlex (here).

This does look strange in deed. I am not aware of a reason for this. But is it really worth it to change this since nobody seems to actually depend on it? Also, if we do change it, maybe we should do it in a dedicated change and not as part of this already pretty big change.

@LongCatIsLooong
Copy link
Contributor Author

I tried the change out in a separate PR and there appeared to be no internal failures.

Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

//
// Baseline-aligned children contributes to the cross axis extent of a [RenderFlex]
// differently from chidren with other [CrossAxisAlignment]s.
extension type const _AscentDescent._((double ascent, double descent)? ascentDescent) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This extension type I am still not sure about. What are we getting by wrapping a record here? Seems like this could easily be just a plain old data class with two fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type doesn't exist at runtime I guess? Probably not much.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still allocating a record at runtime. It shouldn't matter whether you allocate an instance of a class or a record? Since the extension type isn't giving us anything here my suggestion is to use the simpler concept of a regular class here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The (double, double)? pair is probably still needed even if switch to using a class, because it needs an additional bit to represent the "no baselines" state.

spaceEvenly,
spaceEvenly;

// Returns (leadingSpace, betweenSpace).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Giving it proper names here would make the function signature self-documenting though and remove the need for this comment.

@@ -273,6 +273,11 @@ class RenderConstrainedBox extends RenderProxyBox {
return height;
}

@override
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
return child?.computeDryBaseline(_additionalConstraints.enforce(constraints), baseline);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this call the get* method instead?

@goderbauer
Copy link
Member

I tried the change out in a separate PR and there appeared to be no internal failures.

If this causes any issues in the future, it will be much easier to bisect and root cause it if those independent changes are submitted separately.

@LongCatIsLooong
Copy link
Contributor Author

I found it strange that the last flex child gets the remaining main axis extent instead of flex * spacePerFlex

well I tried to create a separate PR for the flex factor change, and when writing tests I realized I read the code wrong. There's no difference between the two except for minor floating point errors, which shouldn't make much of a difference because inconsequential overflow is ignored anyway.

@LongCatIsLooong LongCatIsLooong force-pushed the RenderFlex-baseline-intrinsics branch from 5b73103 to eba50c5 Compare March 28, 2024 02:31
@LongCatIsLooong LongCatIsLooong added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 28, 2024
@auto-submit auto-submit bot merged commit 460a5e2 into flutter:master Mar 28, 2024
@LongCatIsLooong LongCatIsLooong deleted the RenderFlex-baseline-intrinsics branch March 28, 2024 23:09
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 29, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 29, 2024
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Mar 29, 2024
flutter/flutter@89ea492...8528881

2024-03-29 34871572+gmackall@users.noreply.github.com Remove trailing commas in android dependency version checking gradle plugin (flutter/flutter#145718)
2024-03-29 polinach@google.com Upgrade leak_tracker. (flutter/flutter#145940)
2024-03-29 engine-flutter-autoroll@skia.org Roll Flutter Engine from 8b893cb3b607 to 68aa9ba386e1 (2 revisions) (flutter/flutter#145946)
2024-03-29 103135467+sealesj@users.noreply.github.com Refactor flutter_plugins (flutter/flutter#145870)
2024-03-29 34871572+gmackall@users.noreply.github.com Point kotlin message in `gradle_errors.dart` towards new place where templates define the kotlin version (flutter/flutter#145936)
2024-03-29 engine-flutter-autoroll@skia.org Roll Flutter Engine from b917b24836fd to 8b893cb3b607 (1 revision) (flutter/flutter#145941)
2024-03-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from c176d114d01e to b917b24836fd (4 revisions) (flutter/flutter#145938)
2024-03-28 31859944+LongCatIsLooong@users.noreply.github.com `RenderFlex` baseline intrinsics (flutter/flutter#145483)
2024-03-28 godofredoc@google.com Use reporter extended consistently. (flutter/flutter#145617)
2024-03-28 36861262+QuncCccccc@users.noreply.github.com Update tokens to v2.3.5 (flutter/flutter#145356)
2024-03-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from a396dc1a03a9 to c176d114d01e (2 revisions) (flutter/flutter#145934)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC dit@google.com,rmistry@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants