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 = [
decoration: new BoxDecoration(
backgroundImage: new BackgroundImage(
image: _bundle.loadImage('assets/stocks_thumbnail.png'),
fit: BackgroundFit.cover
fit: ImageFit.cover
)
)
),
......@@ -86,7 +86,7 @@ List<SkyDemo> demos = [
decoration: new BoxDecoration(
backgroundImage: new BackgroundImage(
image: _bundle.loadImage('assets/game_thumbnail.png'),
fit: BackgroundFit.cover
fit: ImageFit.cover
)
)
),
......
......@@ -167,21 +167,77 @@ class RadialGradient extends Gradient {
}
}
enum BackgroundFit { fill, contain, cover, none, scaleDown }
enum BackgroundRepeat { repeat, repeatX, repeatY, noRepeat }
enum ImageFit { fill, contain, cover, none, scaleDown }
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<BackgroundImageChangeListener> _listeners =
new List<BackgroundImageChangeListener>();
......@@ -215,7 +270,6 @@ class BackgroundImage {
if (resolvedImage == null)
return;
_image = resolvedImage;
_size = new Size(resolvedImage.width.toDouble(), resolvedImage.height.toDouble());
final List<BackgroundImageChangeListener> localListeners =
new List<BackgroundImageChangeListener>.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) {
......
......@@ -1324,12 +1324,19 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
}
class RenderImage extends RenderBox {
RenderImage({ sky.Image image, double width, double height, sky.ColorFilter colorFilter })
: _image = image,
RenderImage({
sky.Image image,
double width,
double height,
sky.ColorFilter colorFilter,
fit: ImageFit.scaleDown,
repeat: ImageRepeat.noRepeat
}) : _image = image,
_width = width,
_height = height,
_colorFilter = colorFilter;
_colorFilter = colorFilter,
_fit = fit,
_repeat = repeat;
sky.Image _image;
sky.Image get image => _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';
......
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