getTransformTo method

Matrix4 getTransformTo(
  1. RenderObject? target
)

Applies the paint transform from this RenderObject to the target RenderObject.

Returns a matrix that maps the local paint coordinate system to the coordinate system of target, or a Matrix4.zero if the paint transform can not be computed.

This method throws an exception when the target is not in the same render tree as this RenderObject, as the behavior is undefined.

This method ignores RenderObject.paintsChild. This means it will still try to compute the paint transform even if this RenderObject or target is currently not visible.

If target is null, this method returns a matrix that maps from the local paint coordinate system to the coordinate system of the PipelineOwner.rootNode.

For the render tree owned by the RendererBinding (i.e. for the main render tree displayed on the device) this means that this method maps to the global coordinate system in logical pixels. To get physical pixels, use applyPaintTransform from the RenderView to further transform the coordinate.

Implementation

Matrix4 getTransformTo(RenderObject? target) {
  assert(attached);
  // The paths from to fromRenderObject and toRenderObject's common ancestor.
  // Each list's length is greater than 1 if not null.
  //
  // [this, ...., commonAncestorRenderObject], or null if `this` is the common
  // ancestor.
  List<RenderObject>? fromPath;
  // [target, ...., commonAncestorRenderObject], or null if `target` is the
  // common ancestor.
  List<RenderObject>? toPath;

  RenderObject from = this;
  RenderObject to = target ?? owner!.rootNode!;

  while (!identical(from, to)) {
    final int fromDepth = from.depth;
    final int toDepth = to.depth;

    if (fromDepth >= toDepth) {
      final RenderObject fromParent = from.parent ?? (throw FlutterError('$target and $this are not in the same render tree.'));
      (fromPath ??= <RenderObject>[this]).add(fromParent);
      from = fromParent;
    }
    if (fromDepth <= toDepth) {
      final RenderObject toParent = to.parent ?? (throw FlutterError('$target and $this are not in the same render tree.'));
      assert(target != null, '$this has a depth that is less than or equal to ${owner?.rootNode}');
      (toPath ??= <RenderObject>[target!]).add(toParent);
      to = toParent;
    }
  }

  Matrix4? fromTransform;
  if (fromPath != null) {
    assert(fromPath.length > 1);
    fromTransform = Matrix4.identity();
    final int lastIndex = target == null ? fromPath.length - 2 : fromPath.length - 1;
    for (int index = lastIndex; index > 0; index -= 1) {
      fromPath[index].applyPaintTransform(fromPath[index - 1], fromTransform);
    }
  }
  if (toPath == null) {
    return fromTransform ?? Matrix4.identity();
  }

  assert(toPath.length > 1);
  final Matrix4 toTransform = Matrix4.identity();
  for (int index = toPath.length - 1; index > 0; index -= 1) {
    toPath[index].applyPaintTransform(toPath[index - 1], toTransform);
  }
  if (toTransform.invert() == 0) {      // If the matrix is singular then `invert()` doesn't do anything.
    return Matrix4.zero();
  }
  return (fromTransform?..multiply(toTransform)) ?? toTransform;
}