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 { ...@@ -100,6 +100,25 @@ class MatrixUtils {
return new Point(transformed3.x, transformed3.y); 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) { static double _min4(double a, double b, double c, double d) {
return math.min(a, math.min(b, math.min(c, d))); return math.min(a, math.min(b, math.min(c, d)));
} }
...@@ -113,22 +132,12 @@ class MatrixUtils { ...@@ -113,22 +132,12 @@ class MatrixUtils {
/// This function assumes the given rect is in the plane with z equals 0.0. /// 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 /// The transformed rect is then projected back into the plane with z equals
/// 0.0 before computing its bounding rect. /// 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(rect != null);
assert(transform.determinant != 0.0); assert(transform.determinant != 0.0);
if (isIdentity(transform)) if (isIdentity(transform))
return rect; return rect;
transform = new Matrix4.copy(transform)..invert(); transform = new Matrix4.copy(transform)..invert();
Point point1 = transformPoint(transform, rect.topLeft); return transformRect(transform, rect);
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)
);
} }
} }
...@@ -1762,11 +1762,18 @@ abstract class RenderBox extends RenderObject { ...@@ -1762,11 +1762,18 @@ abstract class RenderBox extends RenderObject {
transform.translate(offset.dx, offset.dy); 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); assert(attached);
final List<RenderObject> renderers = <RenderObject>[]; 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); renderers.add(renderer);
}
final Matrix4 transform = new Matrix4.identity(); final Matrix4 transform = new Matrix4.identity();
for (int index = renderers.length - 1; index > 0; index -= 1) for (int index = renderers.length - 1; index > 0; index -= 1)
renderers[index].applyPaintTransform(renderers[index - 1], transform); renderers[index].applyPaintTransform(renderers[index - 1], transform);
...@@ -1777,9 +1784,13 @@ abstract class RenderBox extends RenderObject { ...@@ -1777,9 +1784,13 @@ abstract class RenderBox extends RenderObject {
/// coordinate system for this box. /// coordinate system for this box.
/// ///
/// If the transform from global coordinates to local coordinates is /// If the transform from global coordinates to local coordinates is
/// degenerate, this function returns Point.origin. /// degenerate, this function returns [Point.origin].
Point globalToLocal(Point point) { ///
final Matrix4 transform = _collectPaintTransform(); /// 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(); double det = transform.invert();
if (det == 0.0) if (det == 0.0)
return Point.origin; return Point.origin;
...@@ -1788,8 +1799,12 @@ abstract class RenderBox extends RenderObject { ...@@ -1788,8 +1799,12 @@ abstract class RenderBox extends RenderObject {
/// Convert the given point from the local coordinate system for this box to /// Convert the given point from the local coordinate system for this box to
/// the global coordinate system. /// 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. /// Returns a rectangle that contains all the pixels painted by this box.
......
...@@ -347,7 +347,7 @@ class PaintingContext { ...@@ -347,7 +347,7 @@ class PaintingContext {
_stopRecordingIfNeeded(); _stopRecordingIfNeeded();
final TransformLayer transformLayer = new TransformLayer(transform: effectiveTransform); final TransformLayer transformLayer = new TransformLayer(transform: effectiveTransform);
_appendLayer(transformLayer); _appendLayer(transformLayer);
final Rect transformedPaintBounds = MatrixUtils.inverseTransformRect(_paintBounds, effectiveTransform); final Rect transformedPaintBounds = MatrixUtils.inverseTransformRect(effectiveTransform, _paintBounds);
final PaintingContext childContext = new PaintingContext._(transformLayer, transformedPaintBounds); final PaintingContext childContext = new PaintingContext._(transformLayer, transformedPaintBounds);
painter(childContext, offset); painter(childContext, offset);
childContext._stopRecordingIfNeeded(); childContext._stopRecordingIfNeeded();
...@@ -565,7 +565,7 @@ class _SemanticsGeometry { ...@@ -565,7 +565,7 @@ class _SemanticsGeometry {
} else { } else {
Matrix4 clipTransform = new Matrix4.identity(); Matrix4 clipTransform = new Matrix4.identity();
parent.applyPaintTransform(child, clipTransform); parent.applyPaintTransform(child, clipTransform);
clipRect = MatrixUtils.inverseTransformRect(clipRect, clipTransform); clipRect = MatrixUtils.inverseTransformRect(clipTransform, clipRect);
} }
} }
parent.applyPaintTransform(child, transform); parent.applyPaintTransform(child, transform);
......
...@@ -97,6 +97,11 @@ enum AxisDirection { ...@@ -97,6 +97,11 @@ enum AxisDirection {
left, 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) { Axis axisDirectionToAxis(AxisDirection axisDirection) {
assert(axisDirection != null); assert(axisDirection != null);
switch (axisDirection) { switch (axisDirection) {
...@@ -110,13 +115,13 @@ Axis axisDirectionToAxis(AxisDirection axisDirection) { ...@@ -110,13 +115,13 @@ Axis axisDirectionToAxis(AxisDirection axisDirection) {
return null; return null;
} }
AxisDirection applyGrowthDirectionToAxisDirection(AxisDirection axisDirection, GrowthDirection growthDirection) { /// 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); assert(axisDirection != null);
assert(growthDirection != null);
switch (growthDirection) {
case GrowthDirection.forward:
return axisDirection;
case GrowthDirection.reverse:
switch (axisDirection) { switch (axisDirection) {
case AxisDirection.up: case AxisDirection.up:
return AxisDirection.down; return AxisDirection.down;
...@@ -128,6 +133,25 @@ AxisDirection applyGrowthDirectionToAxisDirection(AxisDirection axisDirection, G ...@@ -128,6 +133,25 @@ AxisDirection applyGrowthDirectionToAxisDirection(AxisDirection axisDirection, G
return AxisDirection.right; return AxisDirection.right;
} }
return null; 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);
switch (growthDirection) {
case GrowthDirection.forward:
return axisDirection;
case GrowthDirection.reverse:
return flipAxisDirection(axisDirection);
} }
return null; 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