@@ -3531,7 +3531,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3531
3531
// node, thus marking this semantics boundary dirty is not enough, it needs
3532
3532
// to find the first parent semantics boundary that does not have any
3533
3533
// possible sibling node.
3534
- while (node.parent is RenderObject && (mayProduceSiblingNodes || ! isEffectiveSemanticsBoundary)) {
3534
+ while (node.parent != null && (mayProduceSiblingNodes || ! isEffectiveSemanticsBoundary)) {
3535
3535
if (node != this && node._needsSemanticsUpdate) {
3536
3536
break ;
3537
3537
}
@@ -3565,7 +3565,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3565
3565
if (! node._needsSemanticsUpdate) {
3566
3566
node._needsSemanticsUpdate = true ;
3567
3567
if (owner != null ) {
3568
- assert (node._semanticsConfiguration.isSemanticBoundary || node.parent is ! RenderObject );
3568
+ assert (node._semanticsConfiguration.isSemanticBoundary || node.parent == null );
3569
3569
owner! ._nodesNeedingSemantics.add (node);
3570
3570
owner! .requestVisualUpdate ();
3571
3571
}
@@ -3574,7 +3574,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3574
3574
3575
3575
/// Updates the semantic information of the render object.
3576
3576
void _updateSemantics () {
3577
- assert (_semanticsConfiguration.isSemanticBoundary || parent is ! RenderObject );
3577
+ assert (_semanticsConfiguration.isSemanticBoundary || parent == null );
3578
3578
if (_needsLayout) {
3579
3579
// There's not enough information in this subtree to compute semantics.
3580
3580
// The subtree is probably being kept alive by a viewport but not laid out.
@@ -3625,8 +3625,8 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3625
3625
final bool blockChildInteractions = blockUserActions || config.isBlockingUserActions;
3626
3626
final bool childrenMergeIntoParent = mergeIntoParent || config.isMergingSemanticsOfDescendants;
3627
3627
final List <SemanticsConfiguration > childConfigurations = < SemanticsConfiguration > [];
3628
- final bool explicitChildNode = config.explicitChildNodes || parent is ! RenderObject ;
3629
- final bool hasChildConfigurationsDelegate = config.childConfigurationsDelegate != null ;
3628
+ final bool explicitChildNode = config.explicitChildNodes || parent == null ;
3629
+ final ChildSemanticsConfigurationsDelegate ? childConfigurationsDelegate = config.childConfigurationsDelegate;
3630
3630
final Map <SemanticsConfiguration , _InterestingSemanticsFragment > configToFragment = < SemanticsConfiguration , _InterestingSemanticsFragment > {};
3631
3631
final List <_InterestingSemanticsFragment > mergeUpFragments = < _InterestingSemanticsFragment > [];
3632
3632
final List <List <_InterestingSemanticsFragment >> siblingMergeFragmentGroups = < List <_InterestingSemanticsFragment >> [];
@@ -3650,7 +3650,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3650
3650
if (hasTags) {
3651
3651
fragment.addTags (config.tagsForChildren! );
3652
3652
}
3653
- if (hasChildConfigurationsDelegate && fragment.config != null ) {
3653
+ if (childConfigurationsDelegate != null && fragment.config != null ) {
3654
3654
// This fragment need to go through delegate to determine whether it
3655
3655
// merge up or not.
3656
3656
childConfigurations.add (fragment.config! );
@@ -3674,14 +3674,14 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3674
3674
}
3675
3675
});
3676
3676
3677
- assert (hasChildConfigurationsDelegate || configToFragment.isEmpty);
3677
+ assert (childConfigurationsDelegate != null || configToFragment.isEmpty);
3678
3678
3679
3679
if (explicitChildNode) {
3680
3680
for (final _InterestingSemanticsFragment fragment in mergeUpFragments) {
3681
3681
fragment.markAsExplicit ();
3682
3682
}
3683
- } else if (hasChildConfigurationsDelegate ) {
3684
- final ChildSemanticsConfigurationsResult result = config. childConfigurationsDelegate ! (childConfigurations);
3683
+ } else if (childConfigurationsDelegate != null ) {
3684
+ final ChildSemanticsConfigurationsResult result = childConfigurationsDelegate (childConfigurations);
3685
3685
mergeUpFragments.addAll (
3686
3686
result.mergeUp.map <_InterestingSemanticsFragment >((SemanticsConfiguration config) {
3687
3687
final _InterestingSemanticsFragment ? fragment = configToFragment[config];
@@ -3706,7 +3706,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3706
3706
_needsSemanticsUpdate = false ;
3707
3707
3708
3708
final _SemanticsFragment result;
3709
- if (parent is ! RenderObject ) {
3709
+ if (parent == null ) {
3710
3710
assert (! config.hasBeenAnnotated);
3711
3711
assert (! mergeIntoParent);
3712
3712
assert (siblingMergeFragmentGroups.isEmpty);
@@ -4781,26 +4781,14 @@ class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment {
4781
4781
parentPaintClipRect: parentPaintClipRect,
4782
4782
)! ;
4783
4783
final Rect fragmentRect = MatrixUtils .transformRect (geometry.transform, geometry.rect);
4784
- if (rect == null ) {
4785
- rect = fragmentRect;
4786
- } else {
4787
- rect = rect.expandToInclude (fragmentRect);
4788
- }
4784
+ rect = rect? .expandToInclude (fragmentRect) ?? fragmentRect;
4789
4785
if (geometry.semanticsClipRect != null ) {
4790
4786
final Rect rect = MatrixUtils .transformRect (geometry.transform, geometry.semanticsClipRect! );
4791
- if (semanticsClipRect == null ) {
4792
- semanticsClipRect = rect;
4793
- } else {
4794
- semanticsClipRect = semanticsClipRect.intersect (rect);
4795
- }
4787
+ semanticsClipRect = semanticsClipRect? .intersect (rect) ?? rect;
4796
4788
}
4797
4789
if (geometry.paintClipRect != null ) {
4798
4790
final Rect rect = MatrixUtils .transformRect (geometry.transform, geometry.paintClipRect! );
4799
- if (paintClipRect == null ) {
4800
- paintClipRect = rect;
4801
- } else {
4802
- paintClipRect = paintClipRect.intersect (rect);
4803
- }
4791
+ paintClipRect = paintClipRect? .intersect (rect) ?? rect;
4804
4792
}
4805
4793
if (switchableFragment._tagsForChildren != null ) {
4806
4794
tags.addAll (switchableFragment._tagsForChildren! );
@@ -4891,8 +4879,7 @@ class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment {
4891
4879
return ; // Drop the node, it's not going to be visible.
4892
4880
}
4893
4881
4894
- owner._semantics ?? = SemanticsNode (showOnScreen: owner.showOnScreen);
4895
- final SemanticsNode node = owner._semantics!
4882
+ final SemanticsNode node = (owner._semantics ?? = SemanticsNode (showOnScreen: owner.showOnScreen))
4896
4883
..isMergedIntoParent = _mergeIntoParent
4897
4884
..tags = _tagsForChildren;
4898
4885
@@ -5070,24 +5057,45 @@ class _SemanticsGeometry {
5070
5057
_transform = Matrix4 .identity ();
5071
5058
_semanticsClipRect = parentSemanticsClipRect;
5072
5059
_paintClipRect = parentPaintClipRect;
5060
+
5073
5061
for (int index = ancestors.length- 1 ; index > 0 ; index -= 1 ) {
5074
- final RenderObject parent = ancestors[index];
5075
- final RenderObject child = ancestors[index- 1 ];
5076
- final Rect ? parentSemanticsClipRect = parent.describeSemanticsClip (child);
5077
- if (parentSemanticsClipRect != null ) {
5078
- _semanticsClipRect = parentSemanticsClipRect;
5079
- _paintClipRect = _intersectRects (_paintClipRect, parent.describeApproximatePaintClip (child));
5062
+ final RenderObject semanticsParent = ancestors[index];
5063
+ final RenderObject semanticsChild = ancestors[index- 1 ];
5064
+ _applyIntermediatePaintTransforms (semanticsParent, semanticsChild, _transform);
5065
+
5066
+ if (identical (semanticsParent, semanticsChild.parent)) {
5067
+ // The easier and more common case: semanticsParent is directly
5068
+ // responsible for painting (and potentially clipping) the semanticsChild
5069
+ // RenderObject.
5070
+ _computeClipRect (semanticsParent, semanticsChild, _semanticsClipRect, _paintClipRect);
5080
5071
} else {
5081
- _semanticsClipRect = _intersectRects (_semanticsClipRect, parent.describeApproximatePaintClip (child));
5072
+ // Otherwise we have to find the closest ancestor RenderObject that
5073
+ // has up-to-date semantics geometry and compute the clip rects from there.
5074
+ //
5075
+ // Currently it can only happen when the subtree contains an OverlayPortal.
5076
+ final List <RenderObject > clipPath = < RenderObject > [semanticsChild];
5077
+
5078
+ RenderObject ? ancestor = semanticsChild.parent;
5079
+ while (ancestor != null && ancestor._semantics == null ) {
5080
+ clipPath.add (ancestor);
5081
+ ancestor = ancestor.parent;
5082
+ }
5083
+ _paintClipRect = ancestor? ._semantics? .parentPaintClipRect;
5084
+ _semanticsClipRect = ancestor? ._semantics? .parentSemanticsClipRect;
5085
+ if (ancestor != null ) {
5086
+ assert (ancestor._semantics != null );
5087
+ assert (! ancestor._needsSemanticsUpdate);
5088
+ RenderObject parent = ancestor;
5089
+ for (int i = clipPath.length - 1 ; i >= 0 ; i -= 1 ) {
5090
+ _computeClipRect (parent, clipPath[i], _semanticsClipRect, _paintClipRect);
5091
+ parent = clipPath[i];
5092
+ }
5093
+ }
5082
5094
}
5083
- _temporaryTransformHolder.setIdentity (); // clears data from previous call(s)
5084
- _applyIntermediatePaintTransforms (parent, child, _transform, _temporaryTransformHolder);
5085
- _semanticsClipRect = _transformRect (_semanticsClipRect, _temporaryTransformHolder);
5086
- _paintClipRect = _transformRect (_paintClipRect, _temporaryTransformHolder);
5087
5095
}
5088
5096
5089
5097
final RenderObject owner = ancestors.first;
5090
- _rect = _semanticsClipRect == null ? owner.semanticBounds : _semanticsClipRect ! . intersect ( owner.semanticBounds) ;
5098
+ _rect = _semanticsClipRect? . intersect ( owner.semanticBounds) ?? owner.semanticBounds;
5091
5099
if (_paintClipRect != null ) {
5092
5100
final Rect paintRect = _paintClipRect! .intersect (_rect);
5093
5101
_markAsHidden = paintRect.isEmpty && ! _rect.isEmpty;
@@ -5097,15 +5105,6 @@ class _SemanticsGeometry {
5097
5105
}
5098
5106
}
5099
5107
5100
- // A matrix used to store transient transform data.
5101
- //
5102
- // Reusing this matrix avoids allocating a new matrix every time a temporary
5103
- // matrix is needed.
5104
- //
5105
- // This instance should never be returned to the caller. Otherwise, the data
5106
- // stored in it will be overwritten unpredictably by subsequent reuses.
5107
- static final Matrix4 _temporaryTransformHolder = Matrix4 .zero ();
5108
-
5109
5108
/// From parent to child coordinate system.
5110
5109
static Rect ? _transformRect (Rect ? rect, Matrix4 transform) {
5111
5110
if (rect == null ) {
@@ -5117,36 +5116,88 @@ class _SemanticsGeometry {
5117
5116
return MatrixUtils .inverseTransformRect (transform, rect);
5118
5117
}
5119
5118
5120
- // Calls applyPaintTransform on all of the render objects between [child] and
5121
- // [ancestor]. This method handles cases where the immediate semantic parent
5122
- // is not the immediate render object parent of the child .
5119
+ // Computes the paint transform from `childFragmentOwner` to
5120
+ // `parentFragmentOwner` and applies the paint transform to `transform` in
5121
+ // place .
5123
5122
//
5124
- // It will mutate both transform and clipRectTransform.
5123
+ // The `parentFragmentOwner` and `childFragmentOwner` [RenderObject]s must be
5124
+ // in the same render tree (so they have a common ancestor).
5125
5125
static void _applyIntermediatePaintTransforms (
5126
- RenderObject ancestor ,
5127
- RenderObject child ,
5126
+ RenderObject parentFragmentOwner ,
5127
+ RenderObject childFragmentOwner ,
5128
5128
Matrix4 transform,
5129
- Matrix4 clipRectTransform,
5130
5129
) {
5131
- assert (clipRectTransform.isIdentity ());
5132
- RenderObject intermediateParent = child.parent! ;
5133
- while (intermediateParent != ancestor) {
5134
- intermediateParent.applyPaintTransform (child, transform);
5135
- intermediateParent = intermediateParent.parent! ;
5136
- child = child.parent! ;
5130
+ Matrix4 ? parentToCommonAncestorTransform;
5131
+ RenderObject from = childFragmentOwner;
5132
+ RenderObject to = parentFragmentOwner;
5133
+
5134
+ while (! identical (from, to)) {
5135
+ final int fromDepth = from.depth;
5136
+ final int toDepth = to.depth;
5137
+
5138
+ if (fromDepth >= toDepth) {
5139
+ assert (from.parent != null , '$parentFragmentOwner and $childFragmentOwner are not in the same render tree.' );
5140
+ final RenderObject fromParent = from.parent! ;
5141
+ fromParent.applyPaintTransform (from, transform);
5142
+ from = fromParent;
5143
+ }
5144
+ if (fromDepth <= toDepth) {
5145
+ assert (to.parent != null , '$parentFragmentOwner and $childFragmentOwner are not in the same render tree.' );
5146
+ final RenderObject toParent = to.parent! ;
5147
+ toParent.applyPaintTransform (to, parentToCommonAncestorTransform ?? = Matrix4 .identity ());
5148
+ to = toParent;
5149
+ }
5150
+ }
5151
+
5152
+ if (parentToCommonAncestorTransform != null ) {
5153
+ if (parentToCommonAncestorTransform.invert () != 0 ) {
5154
+ transform.multiply (parentToCommonAncestorTransform);
5155
+ } else {
5156
+ transform.setZero ();
5157
+ }
5137
5158
}
5138
- ancestor.applyPaintTransform (child, transform);
5139
- ancestor.applyPaintTransform (child, clipRectTransform);
5140
5159
}
5141
5160
5142
- static Rect ? _intersectRects (Rect ? a, Rect ? b) {
5143
- if (a == null ) {
5144
- return b;
5161
+ // A matrix used to store transient transform data.
5162
+ //
5163
+ // Reusing this matrix avoids allocating a new matrix every time a temporary
5164
+ // matrix is needed.
5165
+ //
5166
+ // This instance should never be returned to the caller. Otherwise, the data
5167
+ // stored in it will be overwritten unpredictably by subsequent reuses.
5168
+ static final Matrix4 _temporaryTransformHolder = Matrix4 .zero ();
5169
+
5170
+ // Computes the semantics and painting clip rects for the given child and
5171
+ // assigns the rects to _semanticsClipRect and _paintClipRect respectively.
5172
+ //
5173
+ // The caller must guarantee that child.parent == parent. The resulting rects
5174
+ // are in `child`'s coordinate system.
5175
+ void _computeClipRect (RenderObject parent, RenderObject child, Rect ? parentSemanticsClipRect, Rect ? parentPaintClipRect) {
5176
+ assert (identical (child.parent, parent));
5177
+ // Computes the paint transform from child to parent. The _transformRect
5178
+ // method will compute the inverse.
5179
+ _temporaryTransformHolder.setIdentity (); // clears data from previous call(s)
5180
+ parent.applyPaintTransform (child, _temporaryTransformHolder);
5181
+
5182
+ final Rect ? additionalPaintClip = parent.describeApproximatePaintClip (child);
5183
+ _paintClipRect = _transformRect (
5184
+ _intersectRects (additionalPaintClip, parentPaintClipRect),
5185
+ _temporaryTransformHolder,
5186
+ );
5187
+
5188
+ if (_paintClipRect == null ) {
5189
+ _semanticsClipRect = null ;
5190
+ } else {
5191
+ final Rect ? semanticsClip = parent.describeSemanticsClip (child) ?? _intersectRects (parentSemanticsClipRect, additionalPaintClip);
5192
+ _semanticsClipRect = _transformRect (semanticsClip, _temporaryTransformHolder);
5145
5193
}
5194
+ }
5195
+
5196
+ static Rect ? _intersectRects (Rect ? a, Rect ? b) {
5146
5197
if (b == null ) {
5147
5198
return a;
5148
5199
}
5149
- return a.intersect (b);
5200
+ return a? .intersect (b) ?? b ;
5150
5201
}
5151
5202
5152
5203
/// Whether the [SemanticsNode] annotated with the geometric information tracked
0 commit comments