Commit 0ad2c11c authored by Adam Barth's avatar Adam Barth

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.
parent 66c2cc2a
...@@ -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