Commit aaa9d180 authored by Andrew Wilson's avatar Andrew Wilson Committed by GitHub

Handle negative and zero sizes. (#11827)

parent 4faa0367
...@@ -125,6 +125,9 @@ class FittedSizes { ...@@ -125,6 +125,9 @@ class FittedSizes {
/// * [DecoratedBox], [BoxDecoration], and [DecorationImage], which together /// * [DecoratedBox], [BoxDecoration], and [DecorationImage], which together
/// provide access to [paintImage] at the widgets layer. /// provide access to [paintImage] at the widgets layer.
FittedSizes applyBoxFit(BoxFit fit, Size inputSize, Size outputSize) { FittedSizes applyBoxFit(BoxFit fit, Size inputSize, Size outputSize) {
if (inputSize.height <= 0.0 || inputSize.width <= 0.0 || outputSize.height <= 0.0 || outputSize.width <= 0.0)
return const FittedSizes(Size.zero, Size.zero);
Size sourceSize, destinationSize; Size sourceSize, destinationSize;
switch (fit) { switch (fit) {
case BoxFit.fill: case BoxFit.fill:
......
...@@ -1212,7 +1212,7 @@ Iterable<Rect> _generateImageTileRects(Rect outputRect, Rect fundamentalRect, Im ...@@ -1212,7 +1212,7 @@ Iterable<Rect> _generateImageTileRects(Rect outputRect, Rect fundamentalRect, Im
/// * `canvas`: The canvas onto which the image will be painted. /// * `canvas`: The canvas onto which the image will be painted.
/// * `rect`: The region of the canvas into which the image will be painted. /// * `rect`: The region of the canvas into which the image will be painted.
/// The image might not fill the entire rectangle (e.g., depending on the /// The image might not fill the entire rectangle (e.g., depending on the
/// `fit`). /// `fit`). If `rect` is empty, nothing is painted.
/// * `image`: The image to paint onto the canvas. /// * `image`: The image to paint onto the canvas.
/// * `colorFilter`: If non-null, the color filter to apply when painting the /// * `colorFilter`: If non-null, the color filter to apply when painting the
/// image. /// image.
...@@ -1251,6 +1251,8 @@ void paintImage({ ...@@ -1251,6 +1251,8 @@ void paintImage({
}) { }) {
assert(canvas != null); assert(canvas != null);
assert(image != null); assert(image != null);
if (rect.isEmpty)
return;
Size outputSize = rect.size; Size outputSize = rect.size;
Size inputSize = new Size(image.width.toDouble(), image.height.toDouble()); Size inputSize = new Size(image.width.toDouble(), image.height.toDouble());
Offset sliceBorder; Offset sliceBorder;
......
...@@ -375,6 +375,8 @@ class _FlutterLogoPainter extends BoxPainter { ...@@ -375,6 +375,8 @@ class _FlutterLogoPainter extends BoxPainter {
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
offset += _config.margin.topLeft; offset += _config.margin.topLeft;
final Size canvasSize = _config.margin.deflateSize(configuration.size); final Size canvasSize = _config.margin.deflateSize(configuration.size);
if (canvasSize.isEmpty)
return;
Size logoSize; Size logoSize;
if (_config._position > 0.0) { if (_config._position > 0.0) {
// horizontal style // horizontal style
......
...@@ -1860,6 +1860,8 @@ class RenderFittedBox extends RenderProxyBox { ...@@ -1860,6 +1860,8 @@ class RenderFittedBox extends RenderProxyBox {
@override @override
bool hitTest(HitTestResult result, { Offset position }) { bool hitTest(HitTestResult result, { Offset position }) {
if (size.isEmpty)
return false;
_updatePaintData(); _updatePaintData();
Matrix4 inverse; Matrix4 inverse;
try { try {
...@@ -1875,8 +1877,12 @@ class RenderFittedBox extends RenderProxyBox { ...@@ -1875,8 +1877,12 @@ class RenderFittedBox extends RenderProxyBox {
@override @override
void applyPaintTransform(RenderBox child, Matrix4 transform) { void applyPaintTransform(RenderBox child, Matrix4 transform) {
_updatePaintData(); if (size.isEmpty) {
transform.multiply(_transform); transform.setZero();
} else {
_updatePaintData();
transform.multiply(_transform);
}
} }
@override @override
......
...@@ -25,5 +25,49 @@ void main() { ...@@ -25,5 +25,49 @@ void main() {
result = applyBoxFit(BoxFit.fitHeight, const Size(400.0, 2000.0), const Size(100.0, 1000.0)); result = applyBoxFit(BoxFit.fitHeight, const Size(400.0, 2000.0), const Size(100.0, 1000.0));
expect(result.source, equals(const Size(200.0, 2000.0))); expect(result.source, equals(const Size(200.0, 2000.0)));
expect(result.destination, equals(const Size(100.0, 1000.0))); expect(result.destination, equals(const Size(100.0, 1000.0)));
_testZeroAndNegativeSizes(BoxFit.fill);
_testZeroAndNegativeSizes(BoxFit.contain);
_testZeroAndNegativeSizes(BoxFit.cover);
_testZeroAndNegativeSizes(BoxFit.fitWidth);
_testZeroAndNegativeSizes(BoxFit.fitHeight);
_testZeroAndNegativeSizes(BoxFit.none);
_testZeroAndNegativeSizes(BoxFit.scaleDown);
}); });
} }
void _testZeroAndNegativeSizes(BoxFit fit) {
FittedSizes result;
result = applyBoxFit(fit, const Size(-400.0, 2000.0), const Size(100.0, 1000.0));
expect(result.source, equals(Size.zero));
expect(result.destination, equals(Size.zero));
result = applyBoxFit(fit, const Size(400.0, -2000.0), const Size(100.0, 1000.0));
expect(result.source, equals(Size.zero));
expect(result.destination, equals(Size.zero));
result = applyBoxFit(fit, const Size(400.0, 2000.0), const Size(-100.0, 1000.0));
expect(result.source, equals(Size.zero));
expect(result.destination, equals(Size.zero));
result = applyBoxFit(fit, const Size(400.0, 2000.0), const Size(100.0, -1000.0));
expect(result.source, equals(Size.zero));
expect(result.destination, equals(Size.zero));
result = applyBoxFit(fit, const Size(0.0, 2000.0), const Size(100.0, 1000.0));
expect(result.source, equals(Size.zero));
expect(result.destination, equals(Size.zero));
result = applyBoxFit(fit, const Size(400.0, 0.0), const Size(100.0, 1000.0));
expect(result.source, equals(Size.zero));
expect(result.destination, equals(Size.zero));
result = applyBoxFit(fit, const Size(400.0, 2000.0), const Size(0.0, 1000.0));
expect(result.source, equals(Size.zero));
expect(result.destination, equals(Size.zero));
result = applyBoxFit(fit, const Size(400.0, 2000.0), const Size(100.0, 0.0));
expect(result.source, equals(Size.zero));
expect(result.destination, equals(Size.zero));
}
...@@ -213,14 +213,14 @@ void main() { ...@@ -213,14 +213,14 @@ void main() {
final BoxDecoration boxDecoration = new BoxDecoration(image: backgroundImage); final BoxDecoration boxDecoration = new BoxDecoration(image: backgroundImage);
final BoxPainter boxPainter = boxDecoration.createBoxPainter(() { assert(false); }); final BoxPainter boxPainter = boxDecoration.createBoxPainter(() { assert(false); });
final TestCanvas canvas = new TestCanvas(<Invocation>[]); final TestCanvas canvas = new TestCanvas(<Invocation>[]);
boxPainter.paint(canvas, Offset.zero, const ImageConfiguration(size: const Size(10.0, 10.0))); boxPainter.paint(canvas, Offset.zero, const ImageConfiguration(size: const Size(100.0, 100.0)));
final Invocation call = canvas.invocations.singleWhere((Invocation call) => call.memberName == #drawImageNine); final Invocation call = canvas.invocations.singleWhere((Invocation call) => call.memberName == #drawImageNine);
expect(call.isMethod, isTrue); expect(call.isMethod, isTrue);
expect(call.positionalArguments, hasLength(4)); expect(call.positionalArguments, hasLength(4));
expect(call.positionalArguments[0], const isInstanceOf<TestImage>()); expect(call.positionalArguments[0], const isInstanceOf<TestImage>());
expect(call.positionalArguments[1], new Rect.fromLTRB(10.0, 20.0, 40.0, 60.0)); expect(call.positionalArguments[1], new Rect.fromLTRB(10.0, 20.0, 40.0, 60.0));
expect(call.positionalArguments[2], new Rect.fromLTRB(0.0, 0.0, 32.5, 10.0)); expect(call.positionalArguments[2], new Rect.fromLTRB(0.0, 0.0, 100.0, 100.0));
expect(call.positionalArguments[3], const isInstanceOf<Paint>()); expect(call.positionalArguments[3], const isInstanceOf<Paint>());
expect(call.positionalArguments[3].isAntiAlias, false); expect(call.positionalArguments[3].isAntiAlias, false);
expect(call.positionalArguments[3].colorFilter, colorFilter); expect(call.positionalArguments[3].colorFilter, colorFilter);
......
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