Commit 39ca4fa1 authored by Adam Barth's avatar Adam Barth

Merge pull request #672 from abarth/render_image_fit

Apply ImageFit and ImageRepeat to RenderImage
parents d9c743e1 0ad2c11c
...@@ -73,7 +73,7 @@ List<SkyDemo> demos = [ ...@@ -73,7 +73,7 @@ List<SkyDemo> demos = [
decoration: new BoxDecoration( decoration: new BoxDecoration(
backgroundImage: new BackgroundImage( backgroundImage: new BackgroundImage(
image: _bundle.loadImage('assets/stocks_thumbnail.png'), image: _bundle.loadImage('assets/stocks_thumbnail.png'),
fit: BackgroundFit.cover fit: ImageFit.cover
) )
) )
), ),
...@@ -86,7 +86,7 @@ List<SkyDemo> demos = [ ...@@ -86,7 +86,7 @@ List<SkyDemo> demos = [
decoration: new BoxDecoration( decoration: new BoxDecoration(
backgroundImage: new BackgroundImage( backgroundImage: new BackgroundImage(
image: _bundle.loadImage('assets/game_thumbnail.png'), image: _bundle.loadImage('assets/game_thumbnail.png'),
fit: BackgroundFit.cover fit: ImageFit.cover
) )
) )
), ),
......
...@@ -167,21 +167,77 @@ class RadialGradient extends Gradient { ...@@ -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(); typedef void BackgroundImageChangeListener();
class BackgroundImage { class BackgroundImage {
final BackgroundFit fit; final ImageFit fit;
final BackgroundRepeat repeat; final ImageRepeat repeat;
final sky.ColorFilter colorFilter; final sky.ColorFilter colorFilter;
BackgroundImage({ BackgroundImage({
ImageResource image, ImageResource image,
this.fit: BackgroundFit.scaleDown, this.fit: ImageFit.scaleDown,
this.repeat: BackgroundRepeat.noRepeat, this.repeat: ImageRepeat.noRepeat,
this.colorFilter this.colorFilter
}) : _imageResource = image; }) : _imageResource = image;
...@@ -189,7 +245,6 @@ class BackgroundImage { ...@@ -189,7 +245,6 @@ class BackgroundImage {
sky.Image get image => _image; sky.Image get image => _image;
ImageResource _imageResource; ImageResource _imageResource;
Size _size;
final List<BackgroundImageChangeListener> _listeners = final List<BackgroundImageChangeListener> _listeners =
new List<BackgroundImageChangeListener>(); new List<BackgroundImageChangeListener>();
...@@ -215,7 +270,6 @@ class BackgroundImage { ...@@ -215,7 +270,6 @@ class BackgroundImage {
if (resolvedImage == null) if (resolvedImage == null)
return; return;
_image = resolvedImage; _image = resolvedImage;
_size = new Size(resolvedImage.width.toDouble(), resolvedImage.height.toDouble());
final List<BackgroundImageChangeListener> localListeners = final List<BackgroundImageChangeListener> localListeners =
new List<BackgroundImageChangeListener>.from(_listeners); new List<BackgroundImageChangeListener>.from(_listeners);
for (BackgroundImageChangeListener listener in localListeners) { for (BackgroundImageChangeListener listener in localListeners) {
...@@ -386,53 +440,16 @@ class BoxPainter { ...@@ -386,53 +440,16 @@ class BoxPainter {
if (backgroundImage == null) if (backgroundImage == null)
return; return;
sky.Image image = backgroundImage.image; sky.Image image = backgroundImage.image;
if (image != null) { if (image == null)
Size bounds = rect.size; return;
Size imageSize = backgroundImage._size; paintImage(
Size src; canvas: canvas,
Size dst; rect: rect,
switch(backgroundImage.fit) { image: image,
case BackgroundFit.fill: colorFilter: backgroundImage.colorFilter,
src = imageSize; fit: backgroundImage.fit,
dst = bounds; repeat: backgroundImage.repeat
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);
}
} }
void _paintBorder(sky.Canvas canvas, Rect rect) { void _paintBorder(sky.Canvas canvas, Rect rect) {
......
...@@ -1324,12 +1324,19 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox ...@@ -1324,12 +1324,19 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
} }
class RenderImage extends RenderBox { class RenderImage extends RenderBox {
RenderImage({
RenderImage({ sky.Image image, double width, double height, sky.ColorFilter colorFilter }) sky.Image image,
: _image = image, double width,
double height,
sky.ColorFilter colorFilter,
fit: ImageFit.scaleDown,
repeat: ImageRepeat.noRepeat
}) : _image = image,
_width = width, _width = width,
_height = height, _height = height,
_colorFilter = colorFilter; _colorFilter = colorFilter,
_fit = fit,
_repeat = repeat;
sky.Image _image; sky.Image _image;
sky.Image get image => _image; sky.Image get image => _image;
...@@ -1366,18 +1373,25 @@ class RenderImage extends RenderBox { ...@@ -1366,18 +1373,25 @@ class RenderImage extends RenderBox {
if (value == _colorFilter) if (value == _colorFilter)
return; return;
_colorFilter = value; _colorFilter = value;
_cachedPaint = null;
markNeedsPaint(); markNeedsPaint();
} }
Paint _cachedPaint; ImageFit _fit;
Paint get _paint { ImageFit get fit => _fit;
if (_cachedPaint == null) { void set fit (ImageFit value) {
_cachedPaint = new Paint(); if (value == _fit)
if (colorFilter != null) return;
_cachedPaint.setColorFilter(colorFilter); _fit = value;
} markNeedsPaint();
return _cachedPaint; }
ImageRepeat _repeat;
ImageRepeat get repeat => _repeat;
void set repeat (ImageRepeat value) {
if (value == _repeat)
return;
_repeat = value;
markNeedsPaint();
} }
Size _sizeForConstraints(BoxConstraints constraints) { Size _sizeForConstraints(BoxConstraints constraints) {
...@@ -1452,19 +1466,14 @@ class RenderImage extends RenderBox { ...@@ -1452,19 +1466,14 @@ class RenderImage extends RenderBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (_image == null) if (_image == null)
return; return;
bool needsScale = size.width != _image.width || size.height != _image.height; paintImage(
final PaintingCanvas canvas = context.canvas; canvas: context.canvas,
if (needsScale) { rect: offset & size,
double widthScale = size.width / _image.width; image: _image,
double heightScale = size.height / _image.height; colorFilter: _colorFilter,
canvas.save(); fit: _fit,
canvas.translate(offset.dx, offset.dy); repeat: _repeat
canvas.scale(widthScale, heightScale); );
offset = Offset.zero;
}
canvas.drawImage(_image, offset.toPoint(), _paint);
if (needsScale)
canvas.restore();
} }
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}width: ${width}\n${prefix}height: ${height}\n'; String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}width: ${width}\n${prefix}height: ${height}\n';
......
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