Fix DecorationImage.centerSlice (#10257)
...and rearrange a bunch of code so that all these arguments/members are always in the same order.
This commit is contained in:
parent
61e938aa1e
commit
51ba6b377b
@ -1239,9 +1239,9 @@ void paintImage({
|
|||||||
@required ui.Image image,
|
@required ui.Image image,
|
||||||
ColorFilter colorFilter,
|
ColorFilter colorFilter,
|
||||||
BoxFit fit,
|
BoxFit fit,
|
||||||
ImageRepeat repeat: ImageRepeat.noRepeat,
|
FractionalOffset alignment,
|
||||||
Rect centerSlice,
|
Rect centerSlice,
|
||||||
FractionalOffset alignment
|
ImageRepeat repeat: ImageRepeat.noRepeat,
|
||||||
}) {
|
}) {
|
||||||
assert(canvas != null);
|
assert(canvas != null);
|
||||||
assert(image != null);
|
assert(image != null);
|
||||||
@ -1266,7 +1266,7 @@ void paintImage({
|
|||||||
destinationSize += sliceBorder;
|
destinationSize += sliceBorder;
|
||||||
// We don't have the ability to draw a subset of the image at the same time
|
// We don't have the ability to draw a subset of the image at the same time
|
||||||
// as we apply a nine-patch stretch.
|
// as we apply a nine-patch stretch.
|
||||||
assert(sourceSize == inputSize);
|
assert(sourceSize == inputSize, 'centerSlice was used with a BoxFit that does not guarantee that the image is fully visible.');
|
||||||
}
|
}
|
||||||
if (repeat != ImageRepeat.noRepeat && destinationSize == outputSize) {
|
if (repeat != ImageRepeat.noRepeat && destinationSize == outputSize) {
|
||||||
// There's no need to repeat the image because we're exactly filling the
|
// There's no need to repeat the image because we're exactly filling the
|
||||||
@ -1315,11 +1315,11 @@ class DecorationImage {
|
|||||||
/// The [image] argument must not be null.
|
/// The [image] argument must not be null.
|
||||||
const DecorationImage({
|
const DecorationImage({
|
||||||
@required this.image,
|
@required this.image,
|
||||||
this.fit,
|
|
||||||
this.repeat: ImageRepeat.noRepeat,
|
|
||||||
this.centerSlice,
|
|
||||||
this.colorFilter,
|
this.colorFilter,
|
||||||
|
this.fit,
|
||||||
this.alignment,
|
this.alignment,
|
||||||
|
this.centerSlice,
|
||||||
|
this.repeat: ImageRepeat.noRepeat,
|
||||||
}) : assert(image != null);
|
}) : assert(image != null);
|
||||||
|
|
||||||
/// The image to be painted into the decoration.
|
/// The image to be painted into the decoration.
|
||||||
@ -1328,6 +1328,9 @@ class DecorationImage {
|
|||||||
/// application) or a [NetworkImage] (for an image obtained from the network).
|
/// application) or a [NetworkImage] (for an image obtained from the network).
|
||||||
final ImageProvider image;
|
final ImageProvider image;
|
||||||
|
|
||||||
|
/// A color filter to apply to the image before painting it.
|
||||||
|
final ColorFilter colorFilter;
|
||||||
|
|
||||||
/// How the image should be inscribed into the box.
|
/// How the image should be inscribed into the box.
|
||||||
///
|
///
|
||||||
/// The default is [BoxFit.scaleDown] if [centerSlice] is null, and
|
/// The default is [BoxFit.scaleDown] if [centerSlice] is null, and
|
||||||
@ -1336,9 +1339,14 @@ class DecorationImage {
|
|||||||
/// See the discussion at [paintImage] for more details.
|
/// See the discussion at [paintImage] for more details.
|
||||||
final BoxFit fit;
|
final BoxFit fit;
|
||||||
|
|
||||||
/// How to paint any portions of the box that would not otherwise be covered
|
/// How to align the image within its bounds.
|
||||||
/// by the image.
|
///
|
||||||
final ImageRepeat repeat;
|
/// An alignment of (0.0, 0.0) aligns the image to the top-left corner of its
|
||||||
|
/// layout bounds. An alignment of (1.0, 0.5) aligns the image to the middle
|
||||||
|
/// of the right edge of its layout bounds.
|
||||||
|
///
|
||||||
|
/// Defaults to [FractionalOffset.center].
|
||||||
|
final FractionalOffset alignment;
|
||||||
|
|
||||||
/// The center slice for a nine-patch image.
|
/// The center slice for a nine-patch image.
|
||||||
///
|
///
|
||||||
@ -1357,17 +1365,9 @@ class DecorationImage {
|
|||||||
/// scaling, as if it wasn't specified).
|
/// scaling, as if it wasn't specified).
|
||||||
final Rect centerSlice;
|
final Rect centerSlice;
|
||||||
|
|
||||||
/// A color filter to apply to the image before painting it.
|
/// How to paint any portions of the box that would not otherwise be covered
|
||||||
final ColorFilter colorFilter;
|
/// by the image.
|
||||||
|
final ImageRepeat repeat;
|
||||||
/// How to align the image within its bounds.
|
|
||||||
///
|
|
||||||
/// An alignment of (0.0, 0.0) aligns the image to the top-left corner of its
|
|
||||||
/// layout bounds. An alignment of (1.0, 0.5) aligns the image to the middle
|
|
||||||
/// of the right edge of its layout bounds.
|
|
||||||
///
|
|
||||||
/// Defaults to [FractionalOffset.center].
|
|
||||||
final FractionalOffset alignment;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
@ -1376,19 +1376,35 @@ class DecorationImage {
|
|||||||
if (runtimeType != other.runtimeType)
|
if (runtimeType != other.runtimeType)
|
||||||
return false;
|
return false;
|
||||||
final DecorationImage typedOther = other;
|
final DecorationImage typedOther = other;
|
||||||
return image == typedOther.image &&
|
return image == typedOther.image
|
||||||
fit == typedOther.fit &&
|
&& colorFilter == typedOther.colorFilter
|
||||||
repeat == typedOther.repeat &&
|
&& fit == typedOther.fit
|
||||||
centerSlice == typedOther.centerSlice &&
|
&& alignment == typedOther.alignment
|
||||||
colorFilter == typedOther.colorFilter &&
|
&& centerSlice == typedOther.centerSlice
|
||||||
alignment == typedOther.alignment;
|
&& repeat == typedOther.repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => hashValues(image, fit, repeat, centerSlice, colorFilter, alignment);
|
int get hashCode => hashValues(image, colorFilter, fit, alignment, centerSlice, repeat);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => '$runtimeType($image, $fit, $repeat)';
|
String toString() {
|
||||||
|
final List<String> properties = <String>[];
|
||||||
|
properties.add('$image');
|
||||||
|
if (colorFilter != null)
|
||||||
|
properties.add('$colorFilter');
|
||||||
|
if (fit != null &&
|
||||||
|
!(fit == BoxFit.fill && centerSlice != null) &&
|
||||||
|
!(fit == BoxFit.scaleDown && centerSlice == null))
|
||||||
|
properties.add('$fit');
|
||||||
|
if (alignment != null)
|
||||||
|
properties.add('$alignment');
|
||||||
|
if (centerSlice != null)
|
||||||
|
properties.add('centerSlice: $centerSlice');
|
||||||
|
if (repeat != ImageRepeat.noRepeat)
|
||||||
|
properties.add('$repeat');
|
||||||
|
return '$runtimeType(${properties.join(", ")})';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An immutable description of how to paint a box.
|
/// An immutable description of how to paint a box.
|
||||||
@ -1452,7 +1468,7 @@ class BoxDecoration extends Decoration {
|
|||||||
this.borderRadius,
|
this.borderRadius,
|
||||||
this.boxShadow,
|
this.boxShadow,
|
||||||
this.gradient,
|
this.gradient,
|
||||||
this.shape: BoxShape.rectangle
|
this.shape: BoxShape.rectangle,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1505,7 +1521,7 @@ class BoxDecoration extends Decoration {
|
|||||||
borderRadius: BorderRadius.lerp(null, borderRadius, factor),
|
borderRadius: BorderRadius.lerp(null, borderRadius, factor),
|
||||||
boxShadow: BoxShadow.lerpList(null, boxShadow, factor),
|
boxShadow: BoxShadow.lerpList(null, boxShadow, factor),
|
||||||
gradient: gradient,
|
gradient: gradient,
|
||||||
shape: shape
|
shape: shape,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1532,7 +1548,7 @@ class BoxDecoration extends Decoration {
|
|||||||
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
||||||
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
||||||
gradient: b.gradient,
|
gradient: b.gradient,
|
||||||
shape: b.shape
|
shape: b.shape,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1575,7 +1591,7 @@ class BoxDecoration extends Decoration {
|
|||||||
borderRadius,
|
borderRadius,
|
||||||
boxShadow,
|
boxShadow,
|
||||||
gradient,
|
gradient,
|
||||||
shape
|
shape,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1741,9 +1757,10 @@ class _BoxDecorationPainter extends BoxPainter {
|
|||||||
rect: rect,
|
rect: rect,
|
||||||
image: image,
|
image: image,
|
||||||
colorFilter: backgroundImage.colorFilter,
|
colorFilter: backgroundImage.colorFilter,
|
||||||
alignment: backgroundImage.alignment,
|
|
||||||
fit: backgroundImage.fit,
|
fit: backgroundImage.fit,
|
||||||
repeat: backgroundImage.repeat
|
alignment: backgroundImage.alignment,
|
||||||
|
centerSlice: backgroundImage.centerSlice,
|
||||||
|
repeat: backgroundImage.repeat,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (clipPath != null)
|
if (clipPath != null)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ui' as ui show Image;
|
import 'dart:ui' as ui show Image, ColorFilter;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/painting.dart';
|
import 'package:flutter/painting.dart';
|
||||||
@ -33,7 +33,7 @@ class SynchronousTestImageProvider extends ImageProvider<int> {
|
|||||||
@override
|
@override
|
||||||
ImageStreamCompleter load(int key) {
|
ImageStreamCompleter load(int key) {
|
||||||
return new OneFrameImageStreamCompleter(
|
return new OneFrameImageStreamCompleter(
|
||||||
new SynchronousFuture<ImageInfo>(new TestImageInfo(key))
|
new SynchronousFuture<ImageInfo>(new TestImageInfo(key, image: new TestImage(), scale: 1.0))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ class TestImage extends ui.Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test("Decoration.lerp()", () {
|
test('Decoration.lerp()', () {
|
||||||
final BoxDecoration a = const BoxDecoration(color: const Color(0xFFFFFFFF));
|
final BoxDecoration a = const BoxDecoration(color: const Color(0xFFFFFFFF));
|
||||||
final BoxDecoration b = const BoxDecoration(color: const Color(0x00000000));
|
final BoxDecoration b = const BoxDecoration(color: const Color(0x00000000));
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ void main() {
|
|||||||
expect(c.color, equals(b.color));
|
expect(c.color, equals(b.color));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("BoxDecorationImageListenerSync", () {
|
test('BoxDecorationImageListenerSync', () {
|
||||||
final ImageProvider imageProvider = new SynchronousTestImageProvider();
|
final ImageProvider imageProvider = new SynchronousTestImageProvider();
|
||||||
final DecorationImage backgroundImage = new DecorationImage(image: imageProvider);
|
final DecorationImage backgroundImage = new DecorationImage(image: imageProvider);
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ void main() {
|
|||||||
expect(onChangedCalled, equals(false));
|
expect(onChangedCalled, equals(false));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("BoxDecorationImageListenerAsync", () {
|
test('BoxDecorationImageListenerAsync', () {
|
||||||
new FakeAsync().run((FakeAsync async) {
|
new FakeAsync().run((FakeAsync async) {
|
||||||
final ImageProvider imageProvider = new AsyncTestImageProvider();
|
final ImageProvider imageProvider = new AsyncTestImageProvider();
|
||||||
final DecorationImage backgroundImage = new DecorationImage(image: imageProvider);
|
final DecorationImage backgroundImage = new DecorationImage(image: imageProvider);
|
||||||
@ -146,7 +146,7 @@ void main() {
|
|||||||
|
|
||||||
// Regression test for https://github.com/flutter/flutter/issues/7289.
|
// Regression test for https://github.com/flutter/flutter/issues/7289.
|
||||||
// A reference test would be better.
|
// A reference test would be better.
|
||||||
test("BoxDecoration backgroundImage clip", () {
|
test('BoxDecoration backgroundImage clip', () {
|
||||||
void testDecoration({ BoxShape shape, BorderRadius borderRadius, bool expectClip}) {
|
void testDecoration({ BoxShape shape, BorderRadius borderRadius, bool expectClip}) {
|
||||||
new FakeAsync().run((FakeAsync async) {
|
new FakeAsync().run((FakeAsync async) {
|
||||||
final DelayedImageProvider imageProvider = new DelayedImageProvider();
|
final DelayedImageProvider imageProvider = new DelayedImageProvider();
|
||||||
@ -198,4 +198,32 @@ void main() {
|
|||||||
testDecoration(borderRadius: const BorderRadius.all(const Radius.circular(16.0)), expectClip: true);
|
testDecoration(borderRadius: const BorderRadius.all(const Radius.circular(16.0)), expectClip: true);
|
||||||
testDecoration(expectClip: false);
|
testDecoration(expectClip: false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('DecorationImage test', () {
|
||||||
|
final ColorFilter colorFilter = const ui.ColorFilter.mode(const Color(0xFF00FF00), BlendMode.src);
|
||||||
|
final DecorationImage backgroundImage = new DecorationImage(
|
||||||
|
image: new SynchronousTestImageProvider(),
|
||||||
|
colorFilter: colorFilter,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
alignment: FractionalOffset.bottomLeft,
|
||||||
|
centerSlice: new Rect.fromLTWH(10.0, 20.0, 30.0, 40.0),
|
||||||
|
repeat: ImageRepeat.repeatY,
|
||||||
|
);
|
||||||
|
|
||||||
|
final BoxDecoration boxDecoration = new BoxDecoration(image: backgroundImage);
|
||||||
|
final BoxPainter boxPainter = boxDecoration.createBoxPainter(() { assert(false); });
|
||||||
|
final TestCanvas canvas = new TestCanvas(<Invocation>[]);
|
||||||
|
boxPainter.paint(canvas, Offset.zero, const ImageConfiguration(size: const Size(10.0, 10.0)));
|
||||||
|
|
||||||
|
final Invocation call = canvas.invocations.singleWhere((Invocation call) => call.memberName == #drawImageNine);
|
||||||
|
expect(call.isMethod, isTrue);
|
||||||
|
expect(call.positionalArguments, hasLength(4));
|
||||||
|
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[2], new Rect.fromLTRB(0.0, 0.0, 32.5, 10.0));
|
||||||
|
expect(call.positionalArguments[3], const isInstanceOf<Paint>());
|
||||||
|
expect(call.positionalArguments[3].isAntiAlias, false);
|
||||||
|
expect(call.positionalArguments[3].colorFilter, colorFilter);
|
||||||
|
expect(call.positionalArguments[3].filterQuality, FilterQuality.low);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class TestCanvas implements Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test("Cover and align", () {
|
test('Cover and align', () {
|
||||||
final TestImage image = new TestImage(width: 300, height: 300);
|
final TestImage image = new TestImage(width: 300, height: 300);
|
||||||
final TestCanvas canvas = new TestCanvas();
|
final TestCanvas canvas = new TestCanvas();
|
||||||
paintImage(
|
paintImage(
|
||||||
@ -51,4 +51,6 @@ void main() {
|
|||||||
expect(command.positionalArguments[1], equals(new Rect.fromLTWH(0.0, 75.0, 300.0, 150.0)));
|
expect(command.positionalArguments[1], equals(new Rect.fromLTWH(0.0, 75.0, 300.0, 150.0)));
|
||||||
expect(command.positionalArguments[2], equals(new Rect.fromLTWH(50.0, 75.0, 200.0, 100.0)));
|
expect(command.positionalArguments[2], equals(new Rect.fromLTWH(50.0, 75.0, 200.0, 100.0)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See also the DecorationImage tests in: decoration_test.dart
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,13 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class TestImageInfo implements ImageInfo {
|
class TestImageInfo implements ImageInfo {
|
||||||
const TestImageInfo(this.value) : image = null, scale = null;
|
const TestImageInfo(this.value, { this.image, this.scale });
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final ui.Image image; // ignored in test
|
final ui.Image image;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final double scale; // ignored in test
|
final double scale;
|
||||||
|
|
||||||
final int value;
|
final int value;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user