From 0ad2c11cc621f61b7c861e056d783d3dcfe88880 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Tue, 18 Aug 2015 11:04:37 -0700 Subject: [PATCH] Apply ImageFit and ImageRepeat to RenderImage These properties should apply to foreground images as well as background images. Also, rename these types from BackgroundFit and BackgroundRepeat because they apply to things other than backgrounds. --- examples/demo_launcher/lib/main.dart | 4 +- .../flutter/lib/painting/box_painter.dart | 127 ++++++++++-------- packages/flutter/lib/rendering/box.dart | 61 +++++---- 3 files changed, 109 insertions(+), 83 deletions(-) diff --git a/examples/demo_launcher/lib/main.dart b/examples/demo_launcher/lib/main.dart index bc5272e4e84..853932eea98 100644 --- a/examples/demo_launcher/lib/main.dart +++ b/examples/demo_launcher/lib/main.dart @@ -73,7 +73,7 @@ List demos = [ decoration: new BoxDecoration( backgroundImage: new BackgroundImage( image: _bundle.loadImage('assets/stocks_thumbnail.png'), - fit: BackgroundFit.cover + fit: ImageFit.cover ) ) ), @@ -86,7 +86,7 @@ List demos = [ decoration: new BoxDecoration( backgroundImage: new BackgroundImage( image: _bundle.loadImage('assets/game_thumbnail.png'), - fit: BackgroundFit.cover + fit: ImageFit.cover ) ) ), diff --git a/packages/flutter/lib/painting/box_painter.dart b/packages/flutter/lib/painting/box_painter.dart index 251aea7f229..139eba97551 100644 --- a/packages/flutter/lib/painting/box_painter.dart +++ b/packages/flutter/lib/painting/box_painter.dart @@ -167,21 +167,77 @@ class RadialGradient extends Gradient { } } -enum BackgroundFit { fill, contain, cover, none, scaleDown } +enum ImageFit { fill, contain, cover, none, scaleDown } -enum BackgroundRepeat { repeat, repeatX, repeatY, noRepeat } +enum ImageRepeat { repeat, repeatX, repeatY, noRepeat } + +void paintImage({ + sky.Canvas canvas, + Rect rect, + sky.Image image, + sky.ColorFilter colorFilter, + fit: ImageFit.scaleDown, + repeat: ImageRepeat.noRepeat +}) { + Size bounds = rect.size; + Size imageSize = new Size(image.width.toDouble(), image.height.toDouble()); + Size src; + Size dst; + switch(fit) { + case ImageFit.fill: + src = imageSize; + dst = bounds; + break; + case ImageFit.contain: + src = imageSize; + if (bounds.width / bounds.height > src.width / src.height) { + dst = new Size(bounds.width, src.height * bounds.width / src.width); + } else { + dst = new Size(src.width * bounds.height / src.height, bounds.height); + } + break; + case ImageFit.cover: + if (bounds.width / bounds.height > imageSize.width / imageSize.height) { + src = new Size(imageSize.width, imageSize.width * bounds.height / bounds.width); + } else { + src = new Size(imageSize.height * bounds.width / bounds.height, imageSize.height); + } + dst = bounds; + break; + case ImageFit.none: + src = new Size(math.min(imageSize.width, bounds.width), + math.min(imageSize.height, bounds.height)); + dst = src; + break; + case ImageFit.scaleDown: + src = imageSize; + dst = bounds; + if (src.height > dst.height) { + dst = new Size(src.width * dst.height / src.height, src.height); + } + if (src.width > dst.width) { + dst = new Size(dst.width, src.height * dst.width / src.width); + } + break; + } + // TODO(abarth): Implement |repeat|. + Paint paint = new Paint(); + if (colorFilter != null) + paint.setColorFilter(colorFilter); + canvas.drawImageRect(image, Point.origin & src, rect.topLeft & dst, paint); +} typedef void BackgroundImageChangeListener(); class BackgroundImage { - final BackgroundFit fit; - final BackgroundRepeat repeat; + final ImageFit fit; + final ImageRepeat repeat; final sky.ColorFilter colorFilter; BackgroundImage({ ImageResource image, - this.fit: BackgroundFit.scaleDown, - this.repeat: BackgroundRepeat.noRepeat, + this.fit: ImageFit.scaleDown, + this.repeat: ImageRepeat.noRepeat, this.colorFilter }) : _imageResource = image; @@ -189,7 +245,6 @@ class BackgroundImage { sky.Image get image => _image; ImageResource _imageResource; - Size _size; final List _listeners = new List(); @@ -215,7 +270,6 @@ class BackgroundImage { if (resolvedImage == null) return; _image = resolvedImage; - _size = new Size(resolvedImage.width.toDouble(), resolvedImage.height.toDouble()); final List localListeners = new List.from(_listeners); for (BackgroundImageChangeListener listener in localListeners) { @@ -386,53 +440,16 @@ class BoxPainter { if (backgroundImage == null) return; sky.Image image = backgroundImage.image; - if (image != null) { - Size bounds = rect.size; - Size imageSize = backgroundImage._size; - Size src; - Size dst; - switch(backgroundImage.fit) { - case BackgroundFit.fill: - src = imageSize; - dst = bounds; - break; - case BackgroundFit.contain: - src = imageSize; - if (bounds.width / bounds.height > src.width / src.height) { - dst = new Size(bounds.width, src.height * bounds.width / src.width); - } else { - dst = new Size(src.width * bounds.height / src.height, bounds.height); - } - break; - case BackgroundFit.cover: - if (bounds.width / bounds.height > imageSize.width / imageSize.height) { - src = new Size(imageSize.width, imageSize.width * bounds.height / bounds.width); - } else { - src = new Size(imageSize.height * bounds.width / bounds.height, imageSize.height); - } - dst = bounds; - break; - case BackgroundFit.none: - src = new Size(math.min(imageSize.width, bounds.width), - math.min(imageSize.height, bounds.height)); - dst = src; - break; - case BackgroundFit.scaleDown: - src = imageSize; - dst = bounds; - if (src.height > dst.height) { - dst = new Size(src.width * dst.height / src.height, src.height); - } - if (src.width > dst.width) { - dst = new Size(dst.width, src.height * dst.width / src.width); - } - break; - } - Paint paint = new Paint(); - if (backgroundImage.colorFilter != null) - paint.setColorFilter(backgroundImage.colorFilter); - canvas.drawImageRect(image, Point.origin & src, rect.topLeft & dst, paint); - } + if (image == null) + return; + paintImage( + canvas: canvas, + rect: rect, + image: image, + colorFilter: backgroundImage.colorFilter, + fit: backgroundImage.fit, + repeat: backgroundImage.repeat + ); } void _paintBorder(sky.Canvas canvas, Rect rect) { diff --git a/packages/flutter/lib/rendering/box.dart b/packages/flutter/lib/rendering/box.dart index afd7566b220..1a21802ab31 100644 --- a/packages/flutter/lib/rendering/box.dart +++ b/packages/flutter/lib/rendering/box.dart @@ -1324,12 +1324,19 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin _image; @@ -1366,18 +1373,25 @@ class RenderImage extends RenderBox { if (value == _colorFilter) return; _colorFilter = value; - _cachedPaint = null; markNeedsPaint(); } - Paint _cachedPaint; - Paint get _paint { - if (_cachedPaint == null) { - _cachedPaint = new Paint(); - if (colorFilter != null) - _cachedPaint.setColorFilter(colorFilter); - } - return _cachedPaint; + ImageFit _fit; + ImageFit get fit => _fit; + void set fit (ImageFit value) { + if (value == _fit) + return; + _fit = value; + markNeedsPaint(); + } + + ImageRepeat _repeat; + ImageRepeat get repeat => _repeat; + void set repeat (ImageRepeat value) { + if (value == _repeat) + return; + _repeat = value; + markNeedsPaint(); } Size _sizeForConstraints(BoxConstraints constraints) { @@ -1452,19 +1466,14 @@ class RenderImage extends RenderBox { void paint(PaintingContext context, Offset offset) { if (_image == null) return; - bool needsScale = size.width != _image.width || size.height != _image.height; - final PaintingCanvas canvas = context.canvas; - if (needsScale) { - double widthScale = size.width / _image.width; - double heightScale = size.height / _image.height; - canvas.save(); - canvas.translate(offset.dx, offset.dy); - canvas.scale(widthScale, heightScale); - offset = Offset.zero; - } - canvas.drawImage(_image, offset.toPoint(), _paint); - if (needsScale) - canvas.restore(); + paintImage( + canvas: context.canvas, + rect: offset & size, + image: _image, + colorFilter: _colorFilter, + fit: _fit, + repeat: _repeat + ); } String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}width: ${width}\n${prefix}height: ${height}\n';