@@ -3317,12 +3317,21 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3317
3317
}
3318
3318
3319
3319
/// {@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] .
3321
3322
///
3322
3323
/// 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.
3324
3326
///
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
3326
3335
/// local paint coordinate system to the coordinate system of the
3327
3336
/// [PipelineOwner.rootNode] .
3328
3337
/// {@endtemplate}
@@ -3332,31 +3341,62 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
3332
3341
/// the global coordinate system in logical pixels. To get physical pixels,
3333
3342
/// use [applyPaintTransform] from the [RenderView] to further transform the
3334
3343
/// coordinate.
3335
- Matrix4 getTransformTo (RenderObject ? ancestor) {
3336
- final bool ancestorSpecified = ancestor != null ;
3344
+ Matrix4 getTransformTo (RenderObject ? target) {
3337
3345
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);
3342
3383
}
3343
3384
}
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 ();
3348
3387
}
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);
3351
3393
}
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 ();
3355
3396
}
3356
- return transform ;
3397
+ return (fromTransform ? .. multiply (toTransform)) ?? toTransform ;
3357
3398
}
3358
3399
3359
-
3360
3400
/// Returns a rect in this object's coordinate system that describes
3361
3401
/// the approximate bounding box of the clip rect that would be
3362
3402
/// applied to the given child during the paint phase, if any.
0 commit comments