Skip to content

Commit

Permalink
TwoPointConicGradients again (flutter#5299)
Browse files Browse the repository at this point in the history
* update docs for getBounds

* Add computeMetrics suggestion

* better explanation

* Support for TwoPointConical gradients
  • Loading branch information
dnfield authored May 18, 2018
1 parent 14c3d63 commit 0a74ef4
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 4 deletions.
26 changes: 23 additions & 3 deletions lib/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2310,25 +2310,45 @@ class Gradient extends Shader {
/// 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.
///
/// If `focal` is provided and not equal to `center` and `focalRadius` is
/// provided and not equal to 0.0, the generated shader will be a two point
/// conical radial gradient, with `focal` being the center of the focal
/// circle and `focalRadius` being the radius of that circle. If `focal` is
/// provided and not equal to `center`, at least one of the two offsets must
/// not be equal to [Offset.zero].
Gradient.radial(
Offset center,
double radius,
List<Color> colors, [
List<double> colorStops,
TileMode tileMode = TileMode.clamp,
Float64List matrix4
Float64List matrix4,
Offset focal,
double focalRadius = 0.0
]) : assert(_offsetIsValid(center)),
assert(colors != null),
assert(tileMode != null),
assert(matrix4 == null || _matrix4IsValid(matrix4)),
super._() {
focalRadius ??= 0.0;
_validateColorStops(colors, colorStops);
final Int32List colorsBuffer = _encodeColorList(colors);
final Float32List colorStopsBuffer = colorStops == null ? null : new Float32List.fromList(colorStops);
_constructor();
_initRadial(center.dx, center.dy, radius, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4);

// If focal is null or focal radius is null, this should be treated as a regular radial gradient
// If focal == center and the focal radius is 0.0, it's still a regular radial gradient
if (focal == null || (focal == center && focalRadius == 0.0)) {
_constructor();
_initRadial(center.dx, center.dy, radius, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4);
} else {
assert(center != Offset.zero || focal != Offset.zero); // will result in exception(s) in Skia side
_constructor();
_initConical(focal.dx, focal.dy, focalRadius, center.dx, center.dy, radius, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4);
}
}
void _initRadial(double centerX, double centerY, double radius, Int32List colors, Float32List colorStops, int tileMode, Float64List matrix4) native 'Gradient_initRadial';
void _initConical(double startX, double startY, double startRadius, double endX, double endY, double endRadius, Int32List colors, Float32List colorStops, int tileMode, Float64List matrix4) native 'Gradient_initTwoPointConical';

/// Creates a sweep gradient centered at `center` that starts at `startAngle`
/// and ends at `endAngle`.
Expand Down
32 changes: 31 additions & 1 deletion lib/ui/painting/gradient.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Gradient);
#define FOR_EACH_BINDING(V) \
V(Gradient, initLinear) \
V(Gradient, initRadial) \
V(Gradient, initSweep)
V(Gradient, initSweep) \
V(Gradient, initTwoPointConical)

FOR_EACH_BINDING(DART_NATIVE_CALLBACK)

Expand Down Expand Up @@ -109,6 +110,35 @@ void CanvasGradient::initSweep(double center_x,
has_matrix ? &sk_matrix : nullptr)));
}

void CanvasGradient::initTwoPointConical(double start_x,
double start_y,
double start_radius,
double end_x,
double end_y,
double end_radius,
const tonic::Int32List& colors,
const tonic::Float32List& color_stops,
SkShader::TileMode tile_mode,
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(UIDartState::CreateGPUObject(SkGradientShader::MakeTwoPointConical(
SkPoint::Make(start_x, start_y), start_radius,
SkPoint::Make(end_x, end_y), end_radius,
reinterpret_cast<const SkColor*>(colors.data()), color_stops.data(),
colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr)));
}

CanvasGradient::CanvasGradient() = default;

CanvasGradient::~CanvasGradient() = default;
Expand Down
11 changes: 11 additions & 0 deletions lib/ui/painting/gradient.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ class CanvasGradient : public Shader {
double end_angle,
const tonic::Float64List& matrix4);

void initTwoPointConical(double start_x,
double start_y,
double start_radius,
double end_x,
double end_y,
double end_radius,
const tonic::Int32List& colors,
const tonic::Float32List& color_stops,
SkShader::TileMode tile_mode,
const tonic::Float64List& matrix4);

static void RegisterNatives(tonic::DartLibraryNatives* natives);

private:
Expand Down
72 changes: 72 additions & 0 deletions testing/dart/gradient_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:typed_data' show Float64List;
import 'dart:ui';

import 'package:test/test.dart';

void main() {
test('Gradient.radial with no focal point', () {
expect(
new Gradient.radial(
Offset.zero,
null,
<Color>[const Color(0xFFFFFFFF), const Color(0xFFFFFFFF)],
<double>[0.0, 1.0],
TileMode.mirror),
isNotNull,
);
});

// this is just a radial gradient, focal point is discarded.
test('radial center and focal == Offset.zero and focalRadius == 0.0 is ok',
() {
expect(
() => new Gradient.radial(
Offset.zero,
0.0,
<Color>[const Color(0xFFFFFFFF), const Color(0xFFFFFFFF)],
<double>[0.0, 1.0],
TileMode.mirror,
null,
Offset.zero,
0.0,
),
isNotNull);
});

test('radial center != focal and focalRadius == 0.0 is ok', () {
expect(
() => new Gradient.radial(
Offset.zero,
0.0,
<Color>[const Color(0xFFFFFFFF), const Color(0xFFFFFFFF)],
<double>[0.0, 1.0],
TileMode.mirror,
null,
const Offset(2.0, 2.0),
0.0,
),
isNotNull);
});

// this would result in div/0 on skia side.
test('radial center and focal == Offset.zero and focalRadius != 0.0 assert',
() {
expect(
() => new Gradient.radial(
Offset.zero,
0.0,
<Color>[const Color(0xFFFFFFFF), const Color(0xFFFFFFFF)],
<double>[0.0, 1.0],
TileMode.mirror,
null,
Offset.zero,
1.0,
),
throwsA(const isInstanceOf<AssertionError>()),
);
});
}

0 comments on commit 0a74ef4

Please sign in to comment.