diff --git a/AUTHORS b/AUTHORS index 5fdf752a2e37693328e01f2921399ad1b0716fca..cfae1d6367c4e3184c5dec3013fe980b975154bd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -8,3 +8,4 @@ Jim Simon Ali Bitek Jacob Greenfield Dan Field +Victor Choueiri diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 83e7a859474c395d1c0695e7c2161b03e62d0990..50b49647b1e9f9b81e570b5a25e1c0eb5c7f5121 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -2231,8 +2231,8 @@ Float32List _encodeTwoPoints(Offset pointA, Offset pointB) { /// A shader (as used by [Paint.shader]) that renders a color gradient. /// -/// There are two useful types of gradients, created by [new Gradient.linear] -/// and [new Gradient.radial]. +/// There are several types of gradients, represented by the various constructors +/// on this class. class Gradient extends Shader { void _constructor() native 'Gradient_constructor'; @@ -2306,9 +2306,8 @@ class Gradient extends Shader { ]) : assert(_offsetIsValid(center)), assert(colors != null), assert(tileMode != null), + assert(matrix4 == null || _matrix4IsValid(matrix4)), super._() { - if (matrix4 != null && matrix4.length != 16) - throw new ArgumentError('"matrix4" must have 16 entries.'); _validateColorStops(colors, colorStops); final Int32List colorsBuffer = _encodeColorList(colors); final Float32List colorStopsBuffer = colorStops == null ? null : new Float32List.fromList(colorStops); @@ -2317,6 +2316,56 @@ class Gradient extends Shader { } void _initRadial(double centerX, double centerY, double radius, Int32List colors, Float32List colorStops, int tileMode, Float64List matrix4) native 'Gradient_initRadial'; + /// Creates a sweep gradient centered at `center` that starts at `startAngle` + /// and ends at `endAngle`. + /// + /// `startAngle` and `endAngle` should be provided in radians, with zero + /// radians being the horizontal line to the right of the `center` and with + /// positive angles going clockwise around the `center`. + /// + /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0 + /// that specifies where `color[i]` begins in the gradient. If `colorStops` is + /// not provided, then only two stops, at 0.0 and 1.0, are implied (and + /// `color` must therefore only have two entries). + /// + /// The behavior before `startAngle` and after `endAngle` is described by the + /// `tileMode` argument. For details, see the [TileMode] enum. + /// + /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_clamp_sweep.png) + /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_mirror_sweep.png) + /// ![](https://flutter.github.io/assets-for-api-docs/dart-ui/tile_mode_repeated_sweep.png) + /// + /// If `center`, `colors`, `tileMode`, `startAngle`, or `endAngle` are null, + /// or if `colors` or `colorStops` contain null values, this constructor will + /// throw a [NoSuchMethodError]. + /// + /// If `matrix4` is provided, the gradient fill will be transformed by the + /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must + /// be a column-major matrix packed into a list of 16 values. + Gradient.sweep( + Offset center, + List colors, [ + List colorStops, + TileMode tileMode = TileMode.clamp, + double startAngle = 0.0, + double endAngle = math.pi * 2, + Float64List matrix4, + ]) : assert(_offsetIsValid(center)), + assert(colors != null), + assert(tileMode != null), + assert(startAngle != null), + assert(endAngle != null), + assert(startAngle < endAngle), + assert(matrix4 == null || _matrix4IsValid(matrix4)), + super._() { + _validateColorStops(colors, colorStops); + final Int32List colorsBuffer = _encodeColorList(colors); + final Float32List colorStopsBuffer = colorStops == null ? null : new Float32List.fromList(colorStops); + _constructor(); + _initSweep(center.dx, center.dy, colorsBuffer, colorStopsBuffer, tileMode.index, startAngle, endAngle, matrix4); + } + void _initSweep(double centerX, double centerY, Int32List colors, Float32List colorStops, int tileMode, double startAngle, double endAngle, Float64List matrix) native 'Gradient_initSweep'; + static void _validateColorStops(List colors, List colorStops) { if (colorStops == null) { if (colors.length != 2) diff --git a/lib/ui/painting/gradient.cc b/lib/ui/painting/gradient.cc index 52ccd63f3f5d334f034db74436b1890dffd76c77..702bed34280acea860202f54d4c32b90ed5793bf 100644 --- a/lib/ui/painting/gradient.cc +++ b/lib/ui/painting/gradient.cc @@ -22,7 +22,8 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Gradient); #define FOR_EACH_BINDING(V) \ V(Gradient, initLinear) \ - V(Gradient, initRadial) + V(Gradient, initRadial) \ + V(Gradient, initSweep) FOR_EACH_BINDING(DART_NATIVE_CALLBACK) @@ -79,6 +80,33 @@ void CanvasGradient::initRadial(double center_x, colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr))); } +void CanvasGradient::initSweep(double center_x, + double center_y, + const tonic::Int32List& colors, + const tonic::Float32List& color_stops, + SkShader::TileMode tile_mode, + double start_angle, + double end_angle, + const tonic::Float64List& matrix4) { + FXL_DCHECK(colors.num_elements() == color_stops.num_elements() || + color_stops.data() == nullptr); + + static_assert(sizeof(SkColor) == sizeof(int32_t), + "SkColor doesn't use int32_t."); + + SkMatrix sk_matrix; + bool has_matrix = matrix4.data() != nullptr; + if (has_matrix) { + sk_matrix = ToSkMatrix(matrix4); + } + + set_shader(SkGradientShader::MakeSweep( + center_x, center_y, reinterpret_cast(colors.data()), + color_stops.data(), colors.num_elements(), tile_mode, + start_angle * 180.0 / M_PI, end_angle * 180.0 / M_PI, 0, + has_matrix ? &sk_matrix : nullptr)); +} + CanvasGradient::CanvasGradient() = default; CanvasGradient::~CanvasGradient() = default; diff --git a/lib/ui/painting/gradient.h b/lib/ui/painting/gradient.h index 5f0580b178648e348cf672fc02d3aa75bb3ce22c..178c17fe9b41c5aa2d080e6d5a9100cea3511370 100644 --- a/lib/ui/painting/gradient.h +++ b/lib/ui/painting/gradient.h @@ -43,6 +43,15 @@ class CanvasGradient : public Shader { SkShader::TileMode tile_mode, const tonic::Float64List& matrix4); + void initSweep(double center_x, + double center_y, + const tonic::Int32List& colors, + const tonic::Float32List& color_stops, + SkShader::TileMode tile_mode, + double start_angle, + double end_angle, + const tonic::Float64List& matrix4); + static void RegisterNatives(tonic::DartLibraryNatives* natives); private: