Commit 906541c0 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Refactor out some helper functions (#7774)

These functions were previously hidden inside other functions but they
are useful enough to expose directly. Specifically, I plan to use these
when implementing Scrollable2.ensureVisible.
parent ac145e06
......@@ -100,6 +100,25 @@ class MatrixUtils {
return new Point(transformed3.x, transformed3.y);
}
/// Returns a rect that bounds the result of applying the given matrix as a
/// perspective transform to the given rect.
///
/// This function assumes the given rect is in the plane with z equals 0.0.
/// The transformed rect is then projected back into the plane with z equals
/// 0.0 before computing its bounding rect.
static Rect transformRect(Matrix4 transform, Rect rect) {
Point point1 = transformPoint(transform, rect.topLeft);
Point point2 = transformPoint(transform, rect.topRight);
Point point3 = transformPoint(transform, rect.bottomLeft);
Point point4 = transformPoint(transform, rect.bottomRight);
return new Rect.fromLTRB(
_min4(point1.x, point2.x, point3.x, point4.x),
_min4(point1.y, point2.y, point3.y, point4.y),
_max4(point1.x, point2.x, point3.x, point4.x),
_max4(point1.y, point2.y, point3.y, point4.y)
);
}
static double _min4(double a, double b, double c, double d) {
return math.min(a, math.min(b, math.min(c, d)));
}
......@@ -113,22 +132,12 @@ class MatrixUtils {
/// This function assumes the given rect is in the plane with z equals 0.0.
/// The transformed rect is then projected back into the plane with z equals
/// 0.0 before computing its bounding rect.
static Rect inverseTransformRect(Rect rect, Matrix4 transform) {
static Rect inverseTransformRect(Matrix4 transform, Rect rect) {
assert(rect != null);
assert(transform.determinant != 0.0);
if (isIdentity(transform))
return rect;
transform = new Matrix4.copy(transform)..invert();
Point point1 = transformPoint(transform, rect.topLeft);
Point point2 = transformPoint(transform, rect.topRight);
Point point3 = transformPoint(transform, rect.bottomLeft);
Point point4 = transformPoint(transform, rect.bottomRight);
return new Rect.fromLTRB(
_min4(point1.x, point2.x, point3.x, point4.x),
_min4(point1.y, point2.y, point3.y, point4.y),
_max4(point1.x, point2.x, point3.x, point4.x),
_max4(point1.y, point2.y, point3.y, point4.y)
);
return transformRect(transform, rect);
}
}
......@@ -1762,11 +1762,18 @@ abstract class RenderBox extends RenderObject {
transform.translate(offset.dx, offset.dy);
}
Matrix4 _collectPaintTransform() {
/// Returns a matrix that maps the local coordinate system to the coordinate
/// system of `ancestor`.
///
/// If `ancestor` is null, this method returns a matrix that maps from the
/// local coordinate system to the global coordinate system.
Matrix4 getTransformTo(RenderObject ancestor) {
assert(attached);
final List<RenderObject> renderers = <RenderObject>[];
for (RenderObject renderer = this; renderer != null; renderer = renderer.parent)
for (RenderObject renderer = this; renderer != ancestor; renderer = renderer.parent) {
assert(renderer != null); // Failed to find ancestor in parent chain.
renderers.add(renderer);
}
final Matrix4 transform = new Matrix4.identity();
for (int index = renderers.length - 1; index > 0; index -= 1)
renderers[index].applyPaintTransform(renderers[index - 1], transform);
......@@ -1777,9 +1784,13 @@ abstract class RenderBox extends RenderObject {
/// coordinate system for this box.
///
/// If the transform from global coordinates to local coordinates is
/// degenerate, this function returns Point.origin.
Point globalToLocal(Point point) {
final Matrix4 transform = _collectPaintTransform();
/// degenerate, this function returns [Point.origin].
///
/// If `ancestor` is non-null, this function converts the given point from the
/// coordinate system of `ancestor` (which must be an ancestor of this render
/// object) instead of from the global coordinate system.
Point globalToLocal(Point point, { RenderObject ancestor }) {
final Matrix4 transform = getTransformTo(ancestor);
double det = transform.invert();
if (det == 0.0)
return Point.origin;
......@@ -1788,8 +1799,12 @@ abstract class RenderBox extends RenderObject {
/// Convert the given point from the local coordinate system for this box to
/// the global coordinate system.
Point localToGlobal(Point point) {
return MatrixUtils.transformPoint(_collectPaintTransform(), point);
///
/// If `ancestor` is non-null, this function converts the given point to the
/// coordinate system of `ancestor` (which must be an ancestor of this render
/// object) instead of to the global coordinate system.
Point localToGlobal(Point point, { RenderObject ancestor }) {
return MatrixUtils.transformPoint(getTransformTo(ancestor), point);
}
/// Returns a rectangle that contains all the pixels painted by this box.
......
......@@ -347,7 +347,7 @@ class PaintingContext {
_stopRecordingIfNeeded();
final TransformLayer transformLayer = new TransformLayer(transform: effectiveTransform);
_appendLayer(transformLayer);
final Rect transformedPaintBounds = MatrixUtils.inverseTransformRect(_paintBounds, effectiveTransform);
final Rect transformedPaintBounds = MatrixUtils.inverseTransformRect(effectiveTransform, _paintBounds);
final PaintingContext childContext = new PaintingContext._(transformLayer, transformedPaintBounds);
painter(childContext, offset);
childContext._stopRecordingIfNeeded();
......@@ -565,7 +565,7 @@ class _SemanticsGeometry {
} else {
Matrix4 clipTransform = new Matrix4.identity();
parent.applyPaintTransform(child, clipTransform);
clipRect = MatrixUtils.inverseTransformRect(clipRect, clipTransform);
clipRect = MatrixUtils.inverseTransformRect(clipTransform, clipRect);
}
}
parent.applyPaintTransform(child, transform);
......
......@@ -97,6 +97,11 @@ enum AxisDirection {
left,
}
/// Returns the [Axis] that contains the given [AxisDirection].
///
/// Specifically, returns [Axis.vertical] for [AxisDirection.up] and
/// [AxisDirection.down] and returns [Axis.horizontal] for [AxisDirection.left]
/// and [AxisDirection.right].
Axis axisDirectionToAxis(AxisDirection axisDirection) {
assert(axisDirection != null);
switch (axisDirection) {
......@@ -110,6 +115,35 @@ Axis axisDirectionToAxis(AxisDirection axisDirection) {
return null;
}
/// Returns the opposite of the given [AxisDirection].
///
/// Specifically, returns [AxisDirection.up] for [AxisDirection.down] (and
/// vice versa), as well as [AxisDirection.left] for [AxisDirection.right] (and
/// vice versa).
AxisDirection flipAxisDirection(AxisDirection axisDirection) {
assert(axisDirection != null);
switch (axisDirection) {
case AxisDirection.up:
return AxisDirection.down;
case AxisDirection.right:
return AxisDirection.left;
case AxisDirection.down:
return AxisDirection.up;
case AxisDirection.left:
return AxisDirection.right;
}
return null;
}
/// Flips the [AxisDirection] if the [GrowthDirection] is [GrowthDirection.reverse].
///
/// Specifically, returns `axisDirection` if `growthDirection` is
/// [GrowthDirection.forward], otherwise returns [flipAxisDirection] applied to
/// `axisDirection`.
///
/// This function is useful in [RenderSliver] subclasses that are given both an
/// [AxisDirection] and a [GrowthDirection] and wish to compute the
/// [AxisDirection] in which growth will occur.
AxisDirection applyGrowthDirectionToAxisDirection(AxisDirection axisDirection, GrowthDirection growthDirection) {
assert(axisDirection != null);
assert(growthDirection != null);
......@@ -117,17 +151,7 @@ AxisDirection applyGrowthDirectionToAxisDirection(AxisDirection axisDirection, G
case GrowthDirection.forward:
return axisDirection;
case GrowthDirection.reverse:
switch (axisDirection) {
case AxisDirection.up:
return AxisDirection.down;
case AxisDirection.right:
return AxisDirection.left;
case AxisDirection.down:
return AxisDirection.up;
case AxisDirection.left:
return AxisDirection.right;
}
return null;
return flipAxisDirection(axisDirection);
}
return null;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment