@@ -3531,7 +3531,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
35313531 // node, thus marking this semantics boundary dirty is not enough, it needs
35323532 // to find the first parent semantics boundary that does not have any
35333533 // possible sibling node.
3534- while (node.parent is RenderObject && (mayProduceSiblingNodes || ! isEffectiveSemanticsBoundary)) {
3534+ while (node.parent != null && (mayProduceSiblingNodes || ! isEffectiveSemanticsBoundary)) {
35353535 if (node != this && node._needsSemanticsUpdate) {
35363536 break ;
35373537 }
@@ -3565,7 +3565,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
35653565 if (! node._needsSemanticsUpdate) {
35663566 node._needsSemanticsUpdate = true ;
35673567 if (owner != null ) {
3568- assert (node._semanticsConfiguration.isSemanticBoundary || node.parent is ! RenderObject );
3568+ assert (node._semanticsConfiguration.isSemanticBoundary || node.parent == null );
35693569 owner! ._nodesNeedingSemantics.add (node);
35703570 owner! .requestVisualUpdate ();
35713571 }
@@ -3574,7 +3574,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
35743574
35753575 /// Updates the semantic information of the render object.
35763576 void _updateSemantics () {
3577- assert (_semanticsConfiguration.isSemanticBoundary || parent is ! RenderObject );
3577+ assert (_semanticsConfiguration.isSemanticBoundary || parent == null );
35783578 if (_needsLayout) {
35793579 // There's not enough information in this subtree to compute semantics.
35803580 // 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
36253625 final bool blockChildInteractions = blockUserActions || config.isBlockingUserActions;
36263626 final bool childrenMergeIntoParent = mergeIntoParent || config.isMergingSemanticsOfDescendants;
36273627 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;
36303630 final Map <SemanticsConfiguration , _InterestingSemanticsFragment > configToFragment = < SemanticsConfiguration , _InterestingSemanticsFragment > {};
36313631 final List <_InterestingSemanticsFragment > mergeUpFragments = < _InterestingSemanticsFragment > [];
36323632 final List <List <_InterestingSemanticsFragment >> siblingMergeFragmentGroups = < List <_InterestingSemanticsFragment >> [];
@@ -3650,7 +3650,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
36503650 if (hasTags) {
36513651 fragment.addTags (config.tagsForChildren! );
36523652 }
3653- if (hasChildConfigurationsDelegate && fragment.config != null ) {
3653+ if (childConfigurationsDelegate != null && fragment.config != null ) {
36543654 // This fragment need to go through delegate to determine whether it
36553655 // merge up or not.
36563656 childConfigurations.add (fragment.config! );
@@ -3674,14 +3674,14 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
36743674 }
36753675 });
36763676
3677- assert (hasChildConfigurationsDelegate || configToFragment.isEmpty);
3677+ assert (childConfigurationsDelegate != null || configToFragment.isEmpty);
36783678
36793679 if (explicitChildNode) {
36803680 for (final _InterestingSemanticsFragment fragment in mergeUpFragments) {
36813681 fragment.markAsExplicit ();
36823682 }
3683- } else if (hasChildConfigurationsDelegate ) {
3684- final ChildSemanticsConfigurationsResult result = config. childConfigurationsDelegate ! (childConfigurations);
3683+ } else if (childConfigurationsDelegate != null ) {
3684+ final ChildSemanticsConfigurationsResult result = childConfigurationsDelegate (childConfigurations);
36853685 mergeUpFragments.addAll (
36863686 result.mergeUp.map <_InterestingSemanticsFragment >((SemanticsConfiguration config) {
36873687 final _InterestingSemanticsFragment ? fragment = configToFragment[config];
@@ -3706,7 +3706,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
37063706 _needsSemanticsUpdate = false ;
37073707
37083708 final _SemanticsFragment result;
3709- if (parent is ! RenderObject ) {
3709+ if (parent == null ) {
37103710 assert (! config.hasBeenAnnotated);
37113711 assert (! mergeIntoParent);
37123712 assert (siblingMergeFragmentGroups.isEmpty);
@@ -4781,26 +4781,14 @@ class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment {
47814781 parentPaintClipRect: parentPaintClipRect,
47824782 )! ;
47834783 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;
47894785 if (geometry.semanticsClipRect != null ) {
47904786 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;
47964788 }
47974789 if (geometry.paintClipRect != null ) {
47984790 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;
48044792 }
48054793 if (switchableFragment._tagsForChildren != null ) {
48064794 tags.addAll (switchableFragment._tagsForChildren! );
@@ -4891,8 +4879,7 @@ class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment {
48914879 return ; // Drop the node, it's not going to be visible.
48924880 }
48934881
4894- owner._semantics ?? = SemanticsNode (showOnScreen: owner.showOnScreen);
4895- final SemanticsNode node = owner._semantics!
4882+ final SemanticsNode node = (owner._semantics ?? = SemanticsNode (showOnScreen: owner.showOnScreen))
48964883 ..isMergedIntoParent = _mergeIntoParent
48974884 ..tags = _tagsForChildren;
48984885
@@ -5070,24 +5057,45 @@ class _SemanticsGeometry {
50705057 _transform = Matrix4 .identity ();
50715058 _semanticsClipRect = parentSemanticsClipRect;
50725059 _paintClipRect = parentPaintClipRect;
5060+
50735061 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);
50805071 } 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+ }
50825094 }
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);
50875095 }
50885096
50895097 final RenderObject owner = ancestors.first;
5090- _rect = _semanticsClipRect == null ? owner.semanticBounds : _semanticsClipRect ! . intersect ( owner.semanticBounds) ;
5098+ _rect = _semanticsClipRect? . intersect ( owner.semanticBounds) ?? owner.semanticBounds;
50915099 if (_paintClipRect != null ) {
50925100 final Rect paintRect = _paintClipRect! .intersect (_rect);
50935101 _markAsHidden = paintRect.isEmpty && ! _rect.isEmpty;
@@ -5097,15 +5105,6 @@ class _SemanticsGeometry {
50975105 }
50985106 }
50995107
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-
51095108 /// From parent to child coordinate system.
51105109 static Rect ? _transformRect (Rect ? rect, Matrix4 transform) {
51115110 if (rect == null ) {
@@ -5117,36 +5116,88 @@ class _SemanticsGeometry {
51175116 return MatrixUtils .inverseTransformRect (transform, rect);
51185117 }
51195118
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 .
51235122 //
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).
51255125 static void _applyIntermediatePaintTransforms (
5126- RenderObject ancestor ,
5127- RenderObject child ,
5126+ RenderObject parentFragmentOwner ,
5127+ RenderObject childFragmentOwner ,
51285128 Matrix4 transform,
5129- Matrix4 clipRectTransform,
51305129 ) {
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+ }
51375158 }
5138- ancestor.applyPaintTransform (child, transform);
5139- ancestor.applyPaintTransform (child, clipRectTransform);
51405159 }
51415160
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);
51455193 }
5194+ }
5195+
5196+ static Rect ? _intersectRects (Rect ? a, Rect ? b) {
51465197 if (b == null ) {
51475198 return a;
51485199 }
5149- return a.intersect (b);
5200+ return a? .intersect (b) ?? b ;
51505201 }
51515202
51525203 /// Whether the [SemanticsNode] annotated with the geometric information tracked
0 commit comments