@@ -3317,12 +3317,21 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
33173317 }
33183318
33193319 /// {@template flutter.rendering.RenderObject.getTransformTo}
3320- /// Applies the paint transform up the tree to `ancestor` .
3320+ /// Applies the paint transform from this [RenderObject] to the `target`
3321+ /// [RenderObject] .
33213322 ///
33223323 /// Returns a matrix that maps the local paint coordinate system to the
3323- /// coordinate system of `ancestor` .
3324+ /// coordinate system of `target` , or a [Matrix4.zero] if the paint transform
3325+ /// can not be computed.
33243326 ///
3325- /// If `ancestor` is null, this method returns a matrix that maps from the
3327+ /// This method throws an exception when the `target` is not in the same render
3328+ /// tree as this [RenderObject] , as the behavior is undefined.
3329+ ///
3330+ /// This method ignores [RenderObject.paintsChild] . This means it will still
3331+ /// try to compute the paint transform even if [this] or `target` is currently
3332+ /// not visible.
3333+ ///
3334+ /// If `target` is null, this method returns a matrix that maps from the
33263335 /// local paint coordinate system to the coordinate system of the
33273336 /// [PipelineOwner.rootNode] .
33283337 /// {@endtemplate}
@@ -3332,31 +3341,62 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
33323341 /// the global coordinate system in logical pixels. To get physical pixels,
33333342 /// use [applyPaintTransform] from the [RenderView] to further transform the
33343343 /// coordinate.
3335- Matrix4 getTransformTo (RenderObject ? ancestor) {
3336- final bool ancestorSpecified = ancestor != null ;
3344+ Matrix4 getTransformTo (RenderObject ? target) {
33373345 assert (attached);
3338- if (ancestor == null ) {
3339- final RenderObject ? rootNode = owner! .rootNode;
3340- if (rootNode is RenderObject ) {
3341- ancestor = rootNode;
3346+ // The paths from to fromRenderObject and toRenderObject's common ancestor.
3347+ // Each list's length is greater than 1 if not null.
3348+ //
3349+ // [this, ...., commonAncestorRenderObject], or null if `this` is the common
3350+ // ancestor.
3351+ List <RenderObject >? fromPath;
3352+ // [target, ...., commonAncestorRenderObject], or null if `target` is the
3353+ // common ancestor.
3354+ List <RenderObject >? toPath;
3355+
3356+ RenderObject from = this ;
3357+ RenderObject to = target ?? owner! .rootNode! ;
3358+
3359+ while (! identical (from, to)) {
3360+ final int fromDepth = from.depth;
3361+ final int toDepth = to.depth;
3362+
3363+ if (fromDepth >= toDepth) {
3364+ final RenderObject fromParent = from.parent ?? (throw FlutterError ('$target and $this are not in the same render tree.' ));
3365+ (fromPath ?? = < RenderObject > [this ]).add (fromParent);
3366+ from = fromParent;
3367+ }
3368+ if (fromDepth <= toDepth) {
3369+ final RenderObject toParent = to.parent ?? (throw FlutterError ('$target and $this are not in the same render tree.' ));
3370+ assert (target != null , '$this has a depth that is less than or equal to ${owner ?.rootNode }' );
3371+ (toPath ?? = < RenderObject > [target! ]).add (toParent);
3372+ to = toParent;
3373+ }
3374+ }
3375+
3376+ Matrix4 ? fromTransform;
3377+ if (fromPath != null ) {
3378+ assert (fromPath.length > 1 );
3379+ fromTransform = Matrix4 .identity ();
3380+ final int lastIndex = target == null ? fromPath.length - 2 : fromPath.length - 1 ;
3381+ for (int index = lastIndex; index > 0 ; index -= 1 ) {
3382+ fromPath[index].applyPaintTransform (fromPath[index - 1 ], fromTransform);
33423383 }
33433384 }
3344- final List <RenderObject > renderers = < RenderObject > [];
3345- for (RenderObject renderer = this ; renderer != ancestor; renderer = renderer.parent! ) {
3346- renderers.add (renderer);
3347- assert (renderer.parent != null ); // Failed to find ancestor in parent chain.
3385+ if (toPath == null ) {
3386+ return fromTransform ?? Matrix4 .identity ();
33483387 }
3349- if (ancestorSpecified) {
3350- renderers.add (ancestor! );
3388+
3389+ assert (toPath.length > 1 );
3390+ final Matrix4 toTransform = Matrix4 .identity ();
3391+ for (int index = toPath.length - 1 ; index > 0 ; index -= 1 ) {
3392+ toPath[index].applyPaintTransform (toPath[index - 1 ], toTransform);
33513393 }
3352- final Matrix4 transform = Matrix4 .identity ();
3353- for (int index = renderers.length - 1 ; index > 0 ; index -= 1 ) {
3354- renderers[index].applyPaintTransform (renderers[index - 1 ], transform);
3394+ if (toTransform.invert () == 0 ) { // If the matrix is singular then `invert()` doesn't do anything.
3395+ return Matrix4 .zero ();
33553396 }
3356- return transform ;
3397+ return (fromTransform ? .. multiply (toTransform)) ?? toTransform ;
33573398 }
33583399
3359-
33603400 /// Returns a rect in this object's coordinate system that describes
33613401 /// the approximate bounding box of the clip rect that would be
33623402 /// applied to the given child during the paint phase, if any.
0 commit comments