1048 lines
34 KiB
Dart
1048 lines
34 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// This file is run as part of a reduced test set in CI on Mac and Windows
|
|
// machines.
|
|
@Tags(<String>['reduced-test-set'])
|
|
library;
|
|
|
|
import 'dart:math' as math;
|
|
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
bool _listDoubleMatches(List<double>? x, List<double>? y) {
|
|
if (x == null && y == null) {
|
|
return true;
|
|
}
|
|
if (x == null || y == null) {
|
|
return false;
|
|
}
|
|
if (x.length != y.length) {
|
|
return false;
|
|
}
|
|
for (var i = 0; i < x.length; i++) {
|
|
if ((x[i] - y[i]).abs() >= 0.0001) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool _listColorMatches(List<Color> x, List<Color> y) {
|
|
if (x.length != y.length) {
|
|
return false;
|
|
}
|
|
const double limit = 1 / 255;
|
|
for (var i = 0; i < x.length; i++) {
|
|
if ((x[i].a - y[i].a).abs() >= limit ||
|
|
(x[i].r - y[i].r).abs() >= limit ||
|
|
(x[i].g - y[i].g).abs() >= limit ||
|
|
(x[i].b - y[i].b).abs() >= limit) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
class _LinearGradientMatcher extends Matcher {
|
|
_LinearGradientMatcher(this._target);
|
|
final LinearGradient _target;
|
|
|
|
@override
|
|
Description describe(Description description) {
|
|
description.add('expected $_target');
|
|
return description;
|
|
}
|
|
|
|
@override
|
|
bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
|
|
return item is LinearGradient &&
|
|
item.begin == _target.begin &&
|
|
item.end == _target.end &&
|
|
item.tileMode == _target.tileMode &&
|
|
item.transform == _target.transform &&
|
|
_listColorMatches(item.colors, _target.colors) &&
|
|
_listDoubleMatches(item.stops, _target.stops);
|
|
}
|
|
}
|
|
|
|
Matcher _matchesLinearGradient(LinearGradient target) => _LinearGradientMatcher(target);
|
|
|
|
class _RadialGradientMatcher extends Matcher {
|
|
_RadialGradientMatcher(this._target);
|
|
final RadialGradient _target;
|
|
|
|
@override
|
|
Description describe(Description description) {
|
|
description.add('expected $_target');
|
|
return description;
|
|
}
|
|
|
|
@override
|
|
bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
|
|
if (item is RadialGradient) {
|
|
return item.center == _target.center &&
|
|
item.radius == _target.radius &&
|
|
item.tileMode == _target.tileMode &&
|
|
item.transform == _target.transform &&
|
|
item.focal == _target.focal &&
|
|
item.focalRadius == _target.focalRadius &&
|
|
_listColorMatches(item.colors, _target.colors) &&
|
|
_listDoubleMatches(item.stops, _target.stops);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Matcher _matchesRadialGradient(RadialGradient target) => _RadialGradientMatcher(target);
|
|
|
|
class _SweepGradientMatcher extends Matcher {
|
|
_SweepGradientMatcher(this._target);
|
|
final SweepGradient _target;
|
|
|
|
@override
|
|
Description describe(Description description) {
|
|
description.add('expected $_target');
|
|
return description;
|
|
}
|
|
|
|
@override
|
|
bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
|
|
if (item is SweepGradient) {
|
|
return item.center == _target.center &&
|
|
item.startAngle == _target.startAngle &&
|
|
item.endAngle == _target.endAngle &&
|
|
item.tileMode == _target.tileMode &&
|
|
item.transform == _target.transform &&
|
|
_listColorMatches(item.colors, _target.colors) &&
|
|
_listDoubleMatches(item.stops, _target.stops);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Matcher _matchesSweepGradient(SweepGradient target) => _SweepGradientMatcher(target);
|
|
|
|
void main() {
|
|
test('LinearGradient scale test', () {
|
|
const testGradient = LinearGradient(
|
|
begin: Alignment.bottomRight,
|
|
end: Alignment(0.7, 1.0),
|
|
colors: <Color>[Color(0x00FFFFFF), Color(0x11777777), Color(0x44444444)],
|
|
);
|
|
final LinearGradient? actual = LinearGradient.lerp(null, testGradient, 0.25);
|
|
|
|
expect(
|
|
actual,
|
|
_matchesLinearGradient(
|
|
const LinearGradient(
|
|
begin: Alignment.bottomRight,
|
|
end: Alignment(0.7, 1.0),
|
|
colors: <Color>[Color(0x00FFFFFF), Color(0x04777777), Color(0x11444444)],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('LinearGradient lerp test', () {
|
|
const testGradient1 = LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomLeft,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
);
|
|
const testGradient2 = LinearGradient(
|
|
begin: Alignment.topRight,
|
|
end: Alignment.topLeft,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
);
|
|
|
|
final LinearGradient? actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesLinearGradient(
|
|
const LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.centerLeft,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
|
|
stops: <double>[0, 1],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('LinearGradient.lerp identical a,b', () {
|
|
expect(LinearGradient.lerp(null, null, 0), null);
|
|
const gradient = LinearGradient(colors: <Color>[Color(0x33333333), Color(0x66666666)]);
|
|
expect(identical(LinearGradient.lerp(gradient, gradient, 0.5), gradient), true);
|
|
});
|
|
|
|
test('LinearGradient lerp test with stops', () {
|
|
const testGradient1 = LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomLeft,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0.0, 0.5],
|
|
);
|
|
const testGradient2 = LinearGradient(
|
|
begin: Alignment.topRight,
|
|
end: Alignment.topLeft,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
stops: <double>[0.5, 1.0],
|
|
);
|
|
|
|
final LinearGradient? actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesLinearGradient(
|
|
const LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.centerLeft,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x55555555), Color(0x77777777)],
|
|
stops: <double>[0.0, 0.5, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('LinearGradient lerp test with unequal number of colors', () {
|
|
const testGradient1 = LinearGradient(colors: <Color>[Color(0x22222222), Color(0x66666666)]);
|
|
const testGradient2 = LinearGradient(
|
|
colors: <Color>[Color(0x44444444), Color(0x66666666), Color(0x88888888)],
|
|
);
|
|
|
|
final LinearGradient? actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesLinearGradient(
|
|
const LinearGradient(
|
|
colors: <Color>[Color(0x33333333), Color(0x55555555), Color(0x77777777)],
|
|
stops: <double>[0.0, 0.5, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('LinearGradient lerp test with stops and unequal number of colors', () {
|
|
const testGradient1 = LinearGradient(
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0.0, 0.5],
|
|
);
|
|
const testGradient2 = LinearGradient(
|
|
colors: <Color>[Color(0x44444444), Color(0x48484848), Color(0x88888888)],
|
|
stops: <double>[0.5, 0.7, 1.0],
|
|
);
|
|
|
|
final LinearGradient? actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesLinearGradient(
|
|
const LinearGradient(
|
|
colors: <Color>[
|
|
Color(0x3B3B3B3B),
|
|
Color(0x55555555),
|
|
Color(0x57575757),
|
|
Color(0x77777777),
|
|
],
|
|
stops: <double>[0.0, 0.5, 0.7, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('LinearGradient lerp test with transforms', () {
|
|
const testGradient1 = LinearGradient(
|
|
transform: GradientRotation(math.pi / 4),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0, 1],
|
|
);
|
|
const testGradient2 = LinearGradient(
|
|
transform: GradientRotation(math.pi / 2),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0, 1],
|
|
);
|
|
|
|
final LinearGradient? actual0 = LinearGradient.lerp(testGradient1, testGradient2, 0.0);
|
|
final LinearGradient? actual1 = LinearGradient.lerp(testGradient1, testGradient2, 1.0);
|
|
final LinearGradient? actual2 = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(testGradient1, equals(actual0));
|
|
expect(testGradient2, equals(actual1));
|
|
expect(testGradient2, equals(actual2));
|
|
});
|
|
|
|
test('LinearGradient toString', () {
|
|
expect(
|
|
const LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomLeft,
|
|
transform: GradientRotation(1.6),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
).toString(),
|
|
equals(
|
|
'LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomLeft, colors: [${const Color(0x33333333)}, ${const Color(0x66666666)}], tileMode: TileMode.clamp, transform: GradientRotation(radians: 1.6))',
|
|
),
|
|
);
|
|
});
|
|
|
|
test('LinearGradient with different transforms', () {
|
|
const testGradient1 = LinearGradient(
|
|
transform: GradientRotation(math.pi / 4),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
);
|
|
const testGradient1Copy = LinearGradient(
|
|
transform: GradientRotation(math.pi / 4),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
);
|
|
const testGradient2 = LinearGradient(
|
|
transform: GradientRotation(math.pi / 2),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
);
|
|
|
|
expect(testGradient1, equals(testGradient1Copy));
|
|
expect(testGradient1, isNot(equals(testGradient2)));
|
|
});
|
|
|
|
test('LinearGradient with AlignmentDirectional', () {
|
|
expect(() {
|
|
return const LinearGradient(
|
|
begin: AlignmentDirectional.topStart,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
|
|
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
|
}, throwsAssertionError);
|
|
expect(() {
|
|
return const LinearGradient(
|
|
begin: AlignmentDirectional.topStart,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
|
|
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.rtl);
|
|
}, returnsNormally);
|
|
expect(() {
|
|
return const LinearGradient(
|
|
begin: AlignmentDirectional.topStart,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
|
|
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.ltr);
|
|
}, returnsNormally);
|
|
expect(() {
|
|
return const LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
|
|
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
|
}, returnsNormally);
|
|
});
|
|
|
|
test('LinearGradient withOpacity test', () {
|
|
const testGradient = LinearGradient(
|
|
begin: Alignment.bottomRight,
|
|
end: Alignment.topCenter,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
|
|
);
|
|
final LinearGradient actual = testGradient.withOpacity(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
const LinearGradient(
|
|
begin: Alignment.bottomRight,
|
|
end: Alignment.topCenter,
|
|
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
|
|
),
|
|
);
|
|
});
|
|
|
|
test('LinearGradient withOpacity() preserves transform', () {
|
|
const testGradient = LinearGradient(
|
|
begin: Alignment.bottomRight,
|
|
end: Alignment.topCenter,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
|
|
transform: GradientRotation(1),
|
|
);
|
|
final LinearGradient actual = testGradient.withOpacity(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
const LinearGradient(
|
|
begin: Alignment.bottomRight,
|
|
end: Alignment.topCenter,
|
|
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
|
|
transform: GradientRotation(1),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('LinearGradient.scale preserves transform', () {
|
|
const testGradient = LinearGradient(
|
|
begin: Alignment.bottomRight,
|
|
end: Alignment.topLeft,
|
|
stops: [0, 0.5, 1],
|
|
colors: <Color>[Color(0xFFFF0000), Color(0xFF00FF00), Color(0xFF0000FF)],
|
|
tileMode: TileMode.decal,
|
|
transform: GradientRotation(math.pi / 4),
|
|
);
|
|
final LinearGradient actual = testGradient.scale(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
_matchesLinearGradient(
|
|
const LinearGradient(
|
|
begin: Alignment.bottomRight,
|
|
end: Alignment.topLeft,
|
|
stops: [0, 0.5, 1],
|
|
colors: <Color>[Color(0x80FF0000), Color(0x8000FF00), Color(0x800000FF)],
|
|
tileMode: TileMode.decal,
|
|
transform: GradientRotation(math.pi / 4),
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('RadialGradient with AlignmentDirectional', () {
|
|
expect(() {
|
|
return const RadialGradient(
|
|
center: AlignmentDirectional.topStart,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
|
|
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
|
}, throwsAssertionError);
|
|
|
|
expect(() {
|
|
return const RadialGradient(
|
|
center: AlignmentDirectional.topStart,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
|
|
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.rtl);
|
|
}, returnsNormally);
|
|
expect(() {
|
|
return const RadialGradient(
|
|
center: AlignmentDirectional.topStart,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
|
|
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.ltr);
|
|
}, returnsNormally);
|
|
expect(() {
|
|
return const RadialGradient(
|
|
center: Alignment.topLeft,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xFFFFFFFF)],
|
|
).createShader(const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
|
}, returnsNormally);
|
|
});
|
|
|
|
test('RadialGradient lerp test', () {
|
|
const testGradient1 = RadialGradient(
|
|
center: Alignment.topLeft,
|
|
radius: 20.0,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
);
|
|
const testGradient2 = RadialGradient(
|
|
center: Alignment.topRight,
|
|
radius: 10.0,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
);
|
|
|
|
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesRadialGradient(
|
|
const RadialGradient(
|
|
center: Alignment.topCenter,
|
|
radius: 15.0,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
|
|
stops: <double>[0.0, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('RadialGradient.lerp identical a,b', () {
|
|
expect(RadialGradient.lerp(null, null, 0), null);
|
|
const gradient = RadialGradient(colors: <Color>[Color(0x33333333), Color(0x66666666)]);
|
|
expect(identical(RadialGradient.lerp(gradient, gradient, 0.5), gradient), true);
|
|
});
|
|
|
|
test('RadialGradient lerp test with stops', () {
|
|
const testGradient1 = RadialGradient(
|
|
center: Alignment.topLeft,
|
|
radius: 20.0,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0.0, 0.5],
|
|
);
|
|
const testGradient2 = RadialGradient(
|
|
center: Alignment.topRight,
|
|
radius: 10.0,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
stops: <double>[0.5, 1.0],
|
|
);
|
|
|
|
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
|
|
expect(
|
|
actual,
|
|
_matchesRadialGradient(
|
|
const RadialGradient(
|
|
center: Alignment.topCenter,
|
|
radius: 15.0,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x55555555), Color(0x77777777)],
|
|
stops: <double>[0.0, 0.5, 1.0],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(actual!.focal, isNull);
|
|
});
|
|
|
|
test('RadialGradient lerp test with unequal number of colors', () {
|
|
const testGradient1 = RadialGradient(colors: <Color>[Color(0x22222222), Color(0x66666666)]);
|
|
const testGradient2 = RadialGradient(
|
|
colors: <Color>[Color(0x44444444), Color(0x66666666), Color(0x88888888)],
|
|
);
|
|
|
|
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesRadialGradient(
|
|
const RadialGradient(
|
|
colors: <Color>[Color(0x33333333), Color(0x55555555), Color(0x77777777)],
|
|
stops: <double>[0.0, 0.5, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('RadialGradient lerp test with stops and unequal number of colors', () {
|
|
const testGradient1 = RadialGradient(
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0.0, 0.5],
|
|
);
|
|
const testGradient2 = RadialGradient(
|
|
colors: <Color>[Color(0x44444444), Color(0x48484848), Color(0x88888888)],
|
|
stops: <double>[0.5, 0.7, 1.0],
|
|
);
|
|
|
|
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesRadialGradient(
|
|
const RadialGradient(
|
|
colors: <Color>[
|
|
Color(0x3B3B3B3B),
|
|
Color(0x55555555),
|
|
Color(0x57575757),
|
|
Color(0x77777777),
|
|
],
|
|
stops: <double>[0.0, 0.5, 0.7, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('RadialGradient lerp test with transforms', () {
|
|
const testGradient1 = RadialGradient(
|
|
transform: GradientRotation(math.pi / 4),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0, 1],
|
|
);
|
|
const testGradient2 = RadialGradient(
|
|
transform: GradientRotation(math.pi / 2),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0, 1],
|
|
);
|
|
|
|
final RadialGradient? actual0 = RadialGradient.lerp(testGradient1, testGradient2, 0.0);
|
|
final RadialGradient? actual1 = RadialGradient.lerp(testGradient1, testGradient2, 1.0);
|
|
final RadialGradient? actual2 = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(testGradient1, equals(actual0));
|
|
expect(testGradient2, equals(actual1));
|
|
expect(testGradient2, equals(actual2));
|
|
});
|
|
|
|
test('RadialGradient lerp test with focal', () {
|
|
const testGradient1 = RadialGradient(
|
|
center: Alignment.topLeft,
|
|
focal: Alignment.centerLeft,
|
|
radius: 20.0,
|
|
focalRadius: 10.0,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
);
|
|
const testGradient2 = RadialGradient(
|
|
center: Alignment.topRight,
|
|
focal: Alignment.centerRight,
|
|
radius: 10.0,
|
|
focalRadius: 5.0,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
);
|
|
const testGradient3 = RadialGradient(
|
|
center: Alignment.topRight,
|
|
radius: 10.0,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
);
|
|
|
|
final RadialGradient? actual = RadialGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesRadialGradient(
|
|
const RadialGradient(
|
|
center: Alignment.topCenter,
|
|
focal: Alignment.center,
|
|
radius: 15.0,
|
|
focalRadius: 7.5,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
|
|
stops: <double>[0.0, 1.0],
|
|
),
|
|
),
|
|
);
|
|
|
|
final RadialGradient? actual2 = RadialGradient.lerp(testGradient1, testGradient3, 0.5);
|
|
expect(
|
|
actual2,
|
|
_matchesRadialGradient(
|
|
const RadialGradient(
|
|
center: Alignment.topCenter,
|
|
focal: Alignment(-0.5, 0.0),
|
|
radius: 15.0,
|
|
focalRadius: 5.0,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
|
|
stops: <double>[0.0, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('RadialGradient withOpacity test', () {
|
|
const testGradient = RadialGradient(
|
|
center: Alignment.topLeft,
|
|
focal: Alignment.centerLeft,
|
|
radius: 20.0,
|
|
focalRadius: 10.0,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
|
|
);
|
|
final RadialGradient actual = testGradient.withOpacity(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
const RadialGradient(
|
|
center: Alignment.topLeft,
|
|
focal: Alignment.centerLeft,
|
|
radius: 20.0,
|
|
focalRadius: 10.0,
|
|
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
|
|
),
|
|
);
|
|
});
|
|
|
|
test('RadialGradient withOpacity() preserves transform', () {
|
|
const testGradient = RadialGradient(
|
|
center: Alignment.topLeft,
|
|
focal: Alignment.centerLeft,
|
|
radius: 20.0,
|
|
focalRadius: 10.0,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
|
|
transform: GradientRotation(1),
|
|
);
|
|
final RadialGradient actual = testGradient.withOpacity(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
const RadialGradient(
|
|
center: Alignment.topLeft,
|
|
focal: Alignment.centerLeft,
|
|
radius: 20.0,
|
|
focalRadius: 10.0,
|
|
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
|
|
transform: GradientRotation(1),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('RadialGradient.scale preserves transform', () {
|
|
const testGradient = RadialGradient(
|
|
center: Alignment.topLeft,
|
|
focal: Alignment.centerLeft,
|
|
radius: 20.0,
|
|
focalRadius: 10.0,
|
|
stops: [0, 0.5, 1],
|
|
colors: <Color>[Color(0xFFFF0000), Color(0xFF00FF00), Color(0xFF0000FF)],
|
|
tileMode: TileMode.decal,
|
|
transform: GradientRotation(math.pi / 4),
|
|
);
|
|
final RadialGradient actual = testGradient.scale(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
_matchesRadialGradient(
|
|
const RadialGradient(
|
|
center: Alignment.topLeft,
|
|
focal: Alignment.centerLeft,
|
|
radius: 20.0,
|
|
focalRadius: 10.0,
|
|
stops: [0, 0.5, 1],
|
|
colors: <Color>[Color(0x80FF0000), Color(0x8000FF00), Color(0x800000FF)],
|
|
tileMode: TileMode.decal,
|
|
transform: GradientRotation(math.pi / 4),
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('SweepGradient lerp test', () {
|
|
const testGradient1 = SweepGradient(
|
|
center: Alignment.topLeft,
|
|
endAngle: math.pi / 2,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
);
|
|
const testGradient2 = SweepGradient(
|
|
center: Alignment.topRight,
|
|
startAngle: math.pi / 2,
|
|
endAngle: math.pi,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
);
|
|
|
|
final SweepGradient? actual = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesSweepGradient(
|
|
const SweepGradient(
|
|
center: Alignment.topCenter,
|
|
startAngle: math.pi / 4,
|
|
endAngle: math.pi * 3 / 4,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
|
|
stops: <double>[0.0, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('SweepGradient.lerp identical a,b', () {
|
|
expect(SweepGradient.lerp(null, null, 0), null);
|
|
const gradient = SweepGradient(colors: <Color>[Color(0x33333333), Color(0x66666666)]);
|
|
expect(identical(SweepGradient.lerp(gradient, gradient, 0.5), gradient), true);
|
|
});
|
|
|
|
test('SweepGradient lerp test with stops', () {
|
|
const testGradient1 = SweepGradient(
|
|
center: Alignment.topLeft,
|
|
endAngle: math.pi / 2,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0.0, 0.5],
|
|
);
|
|
const testGradient2 = SweepGradient(
|
|
center: Alignment.topRight,
|
|
startAngle: math.pi / 2,
|
|
endAngle: math.pi,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
stops: <double>[0.5, 1.0],
|
|
);
|
|
|
|
final SweepGradient? actual = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesSweepGradient(
|
|
const SweepGradient(
|
|
center: Alignment.topCenter,
|
|
startAngle: math.pi / 4,
|
|
endAngle: math.pi * 3 / 4,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x55555555), Color(0x77777777)],
|
|
stops: <double>[0.0, 0.5, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('SweepGradient lerp test with unequal number of colors', () {
|
|
const testGradient1 = SweepGradient(colors: <Color>[Color(0x22222222), Color(0x66666666)]);
|
|
const testGradient2 = SweepGradient(
|
|
colors: <Color>[Color(0x44444444), Color(0x66666666), Color(0x88888888)],
|
|
);
|
|
|
|
final SweepGradient? actual = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesSweepGradient(
|
|
const SweepGradient(
|
|
colors: <Color>[Color(0x33333333), Color(0x55555555), Color(0x77777777)],
|
|
stops: <double>[0.0, 0.5, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('SweepGradient lerp test with stops and unequal number of colors', () {
|
|
const testGradient1 = SweepGradient(
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0.0, 0.5],
|
|
);
|
|
const testGradient2 = SweepGradient(
|
|
colors: <Color>[Color(0x44444444), Color(0x48484848), Color(0x88888888)],
|
|
stops: <double>[0.5, 0.7, 1.0],
|
|
);
|
|
|
|
final SweepGradient? actual = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(
|
|
actual,
|
|
_matchesSweepGradient(
|
|
const SweepGradient(
|
|
colors: <Color>[
|
|
Color(0x3B3B3B3B),
|
|
Color(0x55555555),
|
|
Color(0x57575757),
|
|
Color(0x77777777),
|
|
],
|
|
stops: <double>[0.0, 0.5, 0.7, 1.0],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('SweepGradient lerp test with transforms', () {
|
|
const testGradient1 = SweepGradient(
|
|
transform: GradientRotation(math.pi / 4),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0, 1],
|
|
);
|
|
const testGradient2 = SweepGradient(
|
|
transform: GradientRotation(math.pi / 2),
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0, 1],
|
|
);
|
|
|
|
final SweepGradient? actual0 = SweepGradient.lerp(testGradient1, testGradient2, 0.0);
|
|
final SweepGradient? actual1 = SweepGradient.lerp(testGradient1, testGradient2, 1.0);
|
|
final SweepGradient? actual2 = SweepGradient.lerp(testGradient1, testGradient2, 0.5);
|
|
expect(testGradient1, equals(actual0));
|
|
expect(testGradient2, equals(actual1));
|
|
expect(testGradient2, equals(actual2));
|
|
});
|
|
|
|
test('SweepGradient scale test)', () {
|
|
const testGradient = SweepGradient(
|
|
center: Alignment.topLeft,
|
|
endAngle: math.pi / 2,
|
|
colors: <Color>[Color(0xff333333), Color(0xff666666)],
|
|
);
|
|
|
|
final SweepGradient actual = testGradient.scale(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
_matchesSweepGradient(
|
|
const SweepGradient(
|
|
center: Alignment.topLeft,
|
|
endAngle: math.pi / 2,
|
|
colors: <Color>[Color(0x80333333), Color(0x80666666)],
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('SweepGradient withOpacity test', () {
|
|
const testGradient = SweepGradient(
|
|
center: Alignment.topLeft,
|
|
endAngle: math.pi / 2,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
|
|
);
|
|
final SweepGradient actual = testGradient.withOpacity(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
const SweepGradient(
|
|
center: Alignment.topLeft,
|
|
endAngle: math.pi / 2,
|
|
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
|
|
),
|
|
);
|
|
});
|
|
|
|
test('SweepGradient withOpacity() preserves transform', () {
|
|
const testGradient = SweepGradient(
|
|
center: Alignment.topLeft,
|
|
endAngle: math.pi / 2,
|
|
colors: <Color>[Color(0xFFFFFFFF), Color(0xAF777777), Color(0x44444444)],
|
|
transform: GradientRotation(1),
|
|
);
|
|
final SweepGradient actual = testGradient.withOpacity(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
const SweepGradient(
|
|
center: Alignment.topLeft,
|
|
endAngle: math.pi / 2,
|
|
colors: <Color>[Color(0x80FFFFFF), Color(0x80777777), Color(0x80444444)],
|
|
transform: GradientRotation(1),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('SweepGradient.scale preserves transform', () {
|
|
const testGradient = SweepGradient(
|
|
center: Alignment.topLeft,
|
|
startAngle: math.pi / 4,
|
|
endAngle: math.pi * 3 / 4,
|
|
stops: [0, 0.5, 1],
|
|
colors: <Color>[Color(0xFFFF0000), Color(0xFF00FF00), Color(0xFF0000FF)],
|
|
tileMode: TileMode.decal,
|
|
transform: GradientRotation(math.pi / 4),
|
|
);
|
|
final SweepGradient actual = testGradient.scale(0.5);
|
|
|
|
expect(
|
|
actual,
|
|
_matchesSweepGradient(
|
|
const SweepGradient(
|
|
center: Alignment.topLeft,
|
|
startAngle: math.pi / 4,
|
|
endAngle: math.pi * 3 / 4,
|
|
stops: [0, 0.5, 1],
|
|
colors: <Color>[Color(0x80FF0000), Color(0x8000FF00), Color(0x800000FF)],
|
|
tileMode: TileMode.decal,
|
|
transform: GradientRotation(math.pi / 4),
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('Gradient lerp test (with RadialGradient)', () {
|
|
const testGradient1 = RadialGradient(
|
|
center: Alignment.topLeft,
|
|
radius: 20.0,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
stops: <double>[0.0, 1.0],
|
|
);
|
|
const testGradient2 = RadialGradient(
|
|
center: Alignment.topCenter,
|
|
radius: 15.0,
|
|
colors: <Color>[Color(0x3B3B3B3B), Color(0x77777777)],
|
|
stops: <double>[0.0, 1.0],
|
|
);
|
|
const testGradient3 = RadialGradient(
|
|
center: Alignment.topRight,
|
|
radius: 10.0,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
stops: <double>[0.0, 1.0],
|
|
);
|
|
|
|
expect(Gradient.lerp(testGradient1, testGradient3, 0.0), _matchesRadialGradient(testGradient1));
|
|
expect(Gradient.lerp(testGradient1, testGradient3, 0.5), _matchesRadialGradient(testGradient2));
|
|
expect(Gradient.lerp(testGradient1, testGradient3, 1.0), _matchesRadialGradient(testGradient3));
|
|
expect(Gradient.lerp(testGradient3, testGradient1, 0.0), _matchesRadialGradient(testGradient3));
|
|
expect(Gradient.lerp(testGradient3, testGradient1, 0.5), _matchesRadialGradient(testGradient2));
|
|
expect(Gradient.lerp(testGradient3, testGradient1, 1.0), _matchesRadialGradient(testGradient1));
|
|
});
|
|
|
|
test('Gradient lerp test (LinearGradient to RadialGradient)', () {
|
|
const testGradient1 = LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: <Color>[Color(0x33333333), Color(0x66666666)],
|
|
);
|
|
const testGradient2 = RadialGradient(
|
|
radius: 20.0,
|
|
colors: <Color>[Color(0x44444444), Color(0x88888888)],
|
|
);
|
|
|
|
expect(Gradient.lerp(testGradient1, testGradient2, 0.0), testGradient1);
|
|
expect(Gradient.lerp(testGradient1, testGradient2, 1.0), testGradient2);
|
|
expect(Gradient.lerp(testGradient1, testGradient2, 0.5), testGradient2.scale(0.0));
|
|
});
|
|
|
|
test('Gradients can handle missing stops and report mismatched stops', () {
|
|
const test1a = LinearGradient(
|
|
colors: <Color>[Color(0x11111111), Color(0x22222222), Color(0x33333333)],
|
|
);
|
|
const test1b = RadialGradient(
|
|
colors: <Color>[Color(0x11111111), Color(0x22222222), Color(0x33333333)],
|
|
);
|
|
const test2a = LinearGradient(
|
|
colors: <Color>[Color(0x11111111), Color(0x22222222), Color(0x33333333)],
|
|
stops: <double>[0.0, 1.0],
|
|
);
|
|
const test2b = RadialGradient(
|
|
colors: <Color>[Color(0x11111111), Color(0x22222222), Color(0x33333333)],
|
|
stops: <double>[0.0, 1.0],
|
|
);
|
|
const rect = Rect.fromLTWH(1.0, 2.0, 3.0, 4.0);
|
|
expect(test1a.createShader(rect), isNotNull);
|
|
expect(test1b.createShader(rect), isNotNull);
|
|
expect(() {
|
|
test2a.createShader(rect);
|
|
}, throwsArgumentError);
|
|
expect(() {
|
|
test2b.createShader(rect);
|
|
}, throwsArgumentError);
|
|
});
|
|
|
|
group('Transforms', () {
|
|
const colors = <Color>[Color(0xFFFFFFFF), Color(0xFF000088)];
|
|
const rect = Rect.fromLTWH(0.0, 0.0, 300.0, 400.0);
|
|
const gradients45 = <Gradient>[
|
|
LinearGradient(colors: colors, transform: GradientRotation(math.pi / 4)),
|
|
// A radial gradient won't be interesting to rotate unless the center is changed.
|
|
RadialGradient(
|
|
colors: colors,
|
|
center: Alignment.topCenter,
|
|
transform: GradientRotation(math.pi / 4),
|
|
),
|
|
SweepGradient(colors: colors, transform: GradientRotation(math.pi / 4)),
|
|
];
|
|
const gradients90 = <Gradient>[
|
|
LinearGradient(colors: colors, transform: GradientRotation(math.pi / 2)),
|
|
// A radial gradient won't be interesting to rotate unless the center is changed.
|
|
RadialGradient(
|
|
colors: colors,
|
|
center: Alignment.topCenter,
|
|
transform: GradientRotation(math.pi / 2),
|
|
),
|
|
SweepGradient(colors: colors, transform: GradientRotation(math.pi / 2)),
|
|
];
|
|
|
|
const gradientSnakeCase = <Type, String>{
|
|
LinearGradient: 'linear_gradient',
|
|
RadialGradient: 'radial_gradient',
|
|
SweepGradient: 'sweep_gradient',
|
|
};
|
|
|
|
Future<void> runTest(WidgetTester tester, Gradient gradient, double degrees) async {
|
|
final goldenName = '${gradientSnakeCase[gradient.runtimeType]}_$degrees.png';
|
|
final Shader shader = gradient.createShader(rect);
|
|
final Key painterKey = UniqueKey();
|
|
await tester.pumpWidget(
|
|
Center(
|
|
child: SizedBox.fromSize(
|
|
size: rect.size,
|
|
child: RepaintBoundary(
|
|
key: painterKey,
|
|
child: CustomPaint(painter: GradientPainter(shader, rect)),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await expectLater(find.byKey(painterKey), matchesGoldenFile(goldenName));
|
|
}
|
|
|
|
group('Gradients - 45 degrees', () {
|
|
for (final gradient in gradients45) {
|
|
testWidgets('$gradient', (WidgetTester tester) async {
|
|
await runTest(tester, gradient, 45);
|
|
});
|
|
}
|
|
});
|
|
|
|
group('Gradients - 90 degrees', () {
|
|
for (final gradient in gradients90) {
|
|
testWidgets('$gradient', (WidgetTester tester) async {
|
|
await runTest(tester, gradient, 90);
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
class GradientPainter extends CustomPainter {
|
|
const GradientPainter(this.shader, this.rect);
|
|
|
|
final Shader shader;
|
|
final Rect rect;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
canvas.drawRect(rect, Paint()..shader = shader);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(CustomPainter oldDelegate) => true;
|
|
}
|