| // Copyright 2025 the Vello Authors |
| // SPDX-License-Identifier: Apache-2.0 OR MIT |
| |
| use crate::renderer::Renderer; |
| use crate::util::{stops_blue_green_red_yellow, stops_green_blue}; |
| use smallvec::smallvec; |
| use vello_common::color::palette::css::{BLACK, BLUE, WHITE, YELLOW}; |
| use vello_common::color::{ColorSpaceTag, DynamicColor}; |
| use vello_common::kurbo::{Point, Rect}; |
| use vello_common::peniko::{ColorStop, ColorStops, Gradient, GradientKind}; |
| use vello_dev_macros::vello_test; |
| |
| pub(crate) const fn tan_45() -> f64 { |
| 1.0 |
| } |
| |
| #[vello_test(width = 600, height = 32)] |
| fn gradient_on_3_wide_tiles(ctx: &mut impl Renderer) { |
| let rect = Rect::new(4.0, 4.0, 596.0, 28.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(0.0, 0.0), |
| end: Point::new(600.0, 0.0), |
| }, |
| stops: stops_green_blue(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_with_global_alpha(ctx: &mut impl Renderer) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(10.0, 0.0), |
| end: Point::new(90.0, 0.0), |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| } |
| .multiply_alpha(0.5); |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| fn gradient_with_color_spaces(ctx: &mut impl Renderer, stops: ColorStops) { |
| const COLOR_SPACES: &[ColorSpaceTag] = &[ |
| ColorSpaceTag::Srgb, |
| ColorSpaceTag::LinearSrgb, |
| ColorSpaceTag::Oklab, |
| ]; |
| |
| let mut cur_y = 10.0; |
| |
| for cs in COLOR_SPACES { |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(10.0, 0.0), |
| end: Point::new(190.0, 0.0), |
| }, |
| stops: stops.clone(), |
| interpolation_cs: *cs, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&Rect::new(10.0, cur_y, 190.0, cur_y + 30.0)); |
| cur_y += 40.0; |
| } |
| } |
| |
| #[vello_test(width = 200, height = 130)] |
| fn gradient_with_color_spaces_1(ctx: &mut impl Renderer) { |
| let stops = ColorStops(smallvec![ |
| ColorStop { |
| offset: 0.0, |
| color: DynamicColor::from_alpha_color(BLACK), |
| }, |
| ColorStop { |
| offset: 1.0, |
| color: DynamicColor::from_alpha_color(WHITE), |
| }, |
| ]); |
| |
| gradient_with_color_spaces(ctx, stops); |
| } |
| |
| #[vello_test(width = 200, height = 130)] |
| fn gradient_with_color_spaces_2(ctx: &mut impl Renderer) { |
| let stops = ColorStops(smallvec![ |
| ColorStop { |
| offset: 0.0, |
| color: DynamicColor::from_alpha_color(BLUE), |
| }, |
| ColorStop { |
| offset: 1.0, |
| color: DynamicColor::from_alpha_color(YELLOW), |
| }, |
| ]); |
| |
| gradient_with_color_spaces(ctx, stops); |
| } |
| |
| #[vello_test(width = 200, height = 130)] |
| fn gradient_with_color_spaces_3(ctx: &mut impl Renderer) { |
| gradient_with_color_spaces(ctx, stops_blue_green_red_yellow()); |
| } |
| |
| mod linear { |
| use crate::gradient::tan_45; |
| use crate::renderer::Renderer; |
| use crate::util::{ |
| crossed_line_star, stops_blue_green_red_yellow, stops_green_blue, |
| stops_green_blue_with_alpha, |
| }; |
| use peniko::Extend; |
| use std::f64::consts::PI; |
| use vello_common::kurbo::{Affine, Point, Rect}; |
| use vello_common::peniko::{self, Gradient, GradientKind}; |
| use vello_dev_macros::vello_test; |
| |
| #[vello_test] |
| fn gradient_linear_2_stops(ctx: &mut impl Renderer) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(10.0, 0.0), |
| end: Point::new(90.0, 0.0), |
| }, |
| stops: stops_green_blue(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_2_stops_with_alpha(ctx: &mut impl Renderer) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(10.0, 0.0), |
| end: Point::new(90.0, 0.0), |
| }, |
| stops: stops_green_blue_with_alpha(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| fn directional(ctx: &mut impl Renderer, start: Point, end: Point) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { start, end }, |
| stops: stops_green_blue(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_negative_direction(ctx: &mut impl Renderer) { |
| directional(ctx, Point::new(90.0, 0.0), Point::new(10.0, 0.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_downward_y(ctx: &mut impl Renderer) { |
| directional(ctx, Point::new(20.0, 20.0), Point::new(80.0, 80.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_upward_y(ctx: &mut impl Renderer) { |
| directional(ctx, Point::new(20.0, 80.0), Point::new(80.0, 20.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_vertical(ctx: &mut impl Renderer) { |
| directional(ctx, Point::new(0.0, 10.0), Point::new(0.0, 90.0)); |
| } |
| |
| fn gradient_pad(ctx: &mut impl Renderer, extend: Extend) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(40.0, 40.0), |
| end: Point::new(60.0, 60.0), |
| }, |
| stops: stops_blue_green_red_yellow(), |
| extend, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_spread_method_pad(ctx: &mut impl Renderer) { |
| gradient_pad(ctx, Extend::Pad); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_spread_method_repeat(ctx: &mut impl Renderer) { |
| gradient_pad(ctx, Extend::Repeat); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_spread_method_reflect(ctx: &mut impl Renderer) { |
| gradient_pad(ctx, Extend::Reflect); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_4_stops(ctx: &mut impl Renderer) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(10.0, 0.0), |
| end: Point::new(90.0, 0.0), |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_complex_shape(ctx: &mut impl Renderer) { |
| let path = crossed_line_star(); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(0.0, 0.0), |
| end: Point::new(100.0, 0.0), |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_path(&path); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_y_repeat(ctx: &mut impl Renderer) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(47.5, 47.5), |
| end: Point::new(50.5, 52.5), |
| }, |
| stops: stops_blue_green_red_yellow(), |
| extend: Extend::Repeat, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_y_reflect(ctx: &mut impl Renderer) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(47.5, 47.5), |
| end: Point::new(50.5, 52.5), |
| }, |
| stops: stops_blue_green_red_yellow(), |
| extend: Extend::Reflect, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| fn gradient_with_transform( |
| ctx: &mut impl Renderer, |
| transform: Affine, |
| l: f64, |
| t: f64, |
| r: f64, |
| b: f64, |
| ) { |
| let rect = Rect::new(l, t, r, b); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Linear { |
| start: Point::new(l, t), |
| end: Point::new(r, b), |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_transform(transform); |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_identity(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::IDENTITY, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_translate(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::translate((25.0, 25.0)), 0.0, 0.0, 50.0, 50.0); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_scale(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::scale(2.0), 12.5, 12.5, 37.5, 37.5); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_negative_scale(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::translate((100.0, 100.0)) * Affine::scale(-2.0), |
| 12.5, |
| 12.5, |
| 37.5, |
| 37.5, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_scale_and_translate(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::new([2.0, 0.0, 0.0, 2.0, 25.0, 25.0]), |
| 0.0, |
| 0.0, |
| 25.0, |
| 25.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_rotate_1(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::rotate_about(PI / 4.0, Point::new(50.0, 50.0)), |
| 25.0, |
| 25.0, |
| 75.0, |
| 75.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_rotate_2(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::rotate_about(-PI / 4.0, Point::new(50.0, 50.0)), |
| 25.0, |
| 25.0, |
| 75.0, |
| 75.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_scaling_non_uniform(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::scale_non_uniform(1.0, 2.0), |
| 25.0, |
| 12.5, |
| 75.0, |
| 37.5, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_skew_x_1(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((-50.0, 0.0)) * Affine::skew(tan_45(), 0.0); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_skew_x_2(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((50.0, 0.0)) * Affine::skew(-tan_45(), 0.0); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_skew_y_1(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((0.0, 50.0)) * Affine::skew(0.0, -tan_45()); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_linear_with_transform_skew_y_2(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((0.0, -50.0)) * Affine::skew(0.0, tan_45()); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| } |
| |
| mod radial { |
| use crate::gradient::tan_45; |
| use crate::renderer::Renderer; |
| use crate::util::{ |
| crossed_line_star, stops_blue_green_red_yellow, stops_green_blue, |
| stops_green_blue_with_alpha, |
| }; |
| use peniko::Extend; |
| use std::f64::consts::PI; |
| use vello_common::kurbo::{Affine, Point, Rect}; |
| use vello_common::peniko::GradientKind::Radial; |
| use vello_common::peniko::{self, ColorStops, Gradient}; |
| use vello_dev_macros::vello_test; |
| |
| fn simple(ctx: &mut impl Renderer, stops: ColorStops) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: Radial { |
| start_center: Point::new(50.0, 50.0), |
| start_radius: 10.0, |
| end_center: Point::new(50.0, 50.0), |
| end_radius: 40.0, |
| }, |
| stops, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_2_stops(ctx: &mut impl Renderer) { |
| simple(ctx, stops_green_blue()); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_4_stops(ctx: &mut impl Renderer) { |
| simple(ctx, stops_blue_green_red_yellow()); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_2_stops_with_alpha(ctx: &mut impl Renderer) { |
| simple(ctx, stops_green_blue_with_alpha()); |
| } |
| |
| fn gradient_pad(ctx: &mut impl Renderer, extend: Extend) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: Radial { |
| start_center: Point::new(50.0, 50.0), |
| start_radius: 20.0, |
| end_center: Point::new(50.0, 50.0), |
| end_radius: 25.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| extend, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_spread_method_pad(ctx: &mut impl Renderer) { |
| gradient_pad(ctx, Extend::Pad); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_spread_method_reflect(ctx: &mut impl Renderer) { |
| gradient_pad(ctx, Extend::Reflect); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_spread_method_repeat(ctx: &mut impl Renderer) { |
| gradient_pad(ctx, Extend::Repeat); |
| } |
| |
| fn offset(ctx: &mut impl Renderer, point: Point) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: Radial { |
| start_center: point, |
| start_radius: 2.0, |
| end_center: Point::new(50.0, 50.0), |
| end_radius: 40.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| extend: Extend::Repeat, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_center_offset_top_left(ctx: &mut impl Renderer) { |
| offset(ctx, Point::new(30.0, 30.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_center_offset_top_right(ctx: &mut impl Renderer) { |
| offset(ctx, Point::new(70.0, 30.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_center_offset_bottom_left(ctx: &mut impl Renderer) { |
| offset(ctx, Point::new(30.0, 70.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_center_offset_bottom_right(ctx: &mut impl Renderer) { |
| offset(ctx, Point::new(70.0, 70.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_c0_bigger(ctx: &mut impl Renderer) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: Radial { |
| start_center: Point::new(50.0, 50.0), |
| start_radius: 40.0, |
| end_center: Point::new(50.0, 50.0), |
| end_radius: 10.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| fn non_overlapping(ctx: &mut impl Renderer, radius: f32) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: Radial { |
| start_center: Point::new(30.0, 50.0), |
| start_radius: radius, |
| end_center: Point::new(70.0, 50.0), |
| end_radius: 20.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_non_overlapping_same_size(ctx: &mut impl Renderer) { |
| non_overlapping(ctx, 20.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_non_overlapping_c0_smaller(ctx: &mut impl Renderer) { |
| non_overlapping(ctx, 15.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_non_overlapping_c0_larger(ctx: &mut impl Renderer) { |
| non_overlapping(ctx, 25.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_non_overlapping_cone(ctx: &mut impl Renderer) { |
| non_overlapping(ctx, 5.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_complex_shape(ctx: &mut impl Renderer) { |
| let path = crossed_line_star(); |
| |
| let gradient = Gradient { |
| kind: Radial { |
| start_center: Point::new(50.0, 50.0), |
| start_radius: 5.0, |
| end_center: Point::new(50.0, 50.0), |
| end_radius: 35.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_path(&path); |
| } |
| |
| fn gradient_with_transform( |
| ctx: &mut impl Renderer, |
| transform: Affine, |
| l: f64, |
| t: f64, |
| r: f64, |
| b: f64, |
| ) { |
| let rect = Rect::new(l, t, r, b); |
| let point = Point::new((l + r) / 2.0, (t + b) / 2.0); |
| |
| let gradient = Gradient { |
| kind: Radial { |
| start_center: point, |
| start_radius: 5.0, |
| end_center: point, |
| end_radius: 35.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_transform(transform); |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_identity(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::IDENTITY, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_translate(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::translate((25.0, 25.0)), 0.0, 0.0, 50.0, 50.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_scale(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::scale(2.0), 12.5, 12.5, 37.5, 37.5); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_negative_scale(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::translate((100.0, 100.0)) * Affine::scale(-2.0), |
| 12.5, |
| 12.5, |
| 37.5, |
| 37.5, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_scale_and_translate(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::new([2.0, 0.0, 0.0, 2.0, 25.0, 25.0]), |
| 0.0, |
| 0.0, |
| 25.0, |
| 25.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_rotate_1(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::rotate_about(PI / 4.0, Point::new(50.0, 50.0)), |
| 25.0, |
| 25.0, |
| 75.0, |
| 75.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_rotate_2(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::rotate_about(-PI / 4.0, Point::new(50.0, 50.0)), |
| 25.0, |
| 25.0, |
| 75.0, |
| 75.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_scale_non_uniform(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::scale_non_uniform(1.0, 2.0), |
| 25.0, |
| 12.5, |
| 75.0, |
| 37.5, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_skew_x_1(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((-50.0, 0.0)) * Affine::skew(tan_45(), 0.0); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_skew_x_2(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((50.0, 0.0)) * Affine::skew(-tan_45(), 0.0); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_skew_y_1(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((0.0, 50.0)) * Affine::skew(0.0, -tan_45()); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_radial_with_transform_skew_y_2(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((0.0, -50.0)) * Affine::skew(0.0, tan_45()); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| } |
| |
| mod sweep { |
| use crate::gradient::tan_45; |
| use crate::renderer::Renderer; |
| use crate::util::{ |
| crossed_line_star, stops_blue_green_red_yellow, stops_green_blue, |
| stops_green_blue_with_alpha, |
| }; |
| use peniko::Extend; |
| use std::f64::consts::PI; |
| use vello_common::kurbo::{Affine, Point, Rect}; |
| use vello_common::peniko::{self, ColorStops, Gradient, GradientKind}; |
| use vello_dev_macros::vello_test; |
| |
| fn basic(ctx: &mut impl Renderer, stops: ColorStops, center: Point) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Sweep { |
| center, |
| start_angle: 0.0, |
| end_angle: 360.0, |
| }, |
| stops, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_2_stops(ctx: &mut impl Renderer) { |
| basic(ctx, stops_green_blue(), Point::new(50.0, 50.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_2_stops_with_alpha(ctx: &mut impl Renderer) { |
| basic(ctx, stops_green_blue_with_alpha(), Point::new(50.0, 50.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_4_stops(ctx: &mut impl Renderer) { |
| basic(ctx, stops_blue_green_red_yellow(), Point::new(50.0, 50.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_not_in_center(ctx: &mut impl Renderer) { |
| basic(ctx, stops_green_blue(), Point::new(30.0, 30.0)); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_complex_shape(ctx: &mut impl Renderer) { |
| let path = crossed_line_star(); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Sweep { |
| center: Point::new(50.0, 50.0), |
| start_angle: 0.0, |
| end_angle: 360.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_path(&path); |
| } |
| |
| fn spread_method(ctx: &mut impl Renderer, extend: Extend) { |
| let rect = Rect::new(10.0, 10.0, 90.0, 90.0); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Sweep { |
| center: Point::new(50.0, 50.0), |
| start_angle: 150.0, |
| end_angle: 210.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| extend, |
| ..Default::default() |
| }; |
| |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_spread_method_pad(ctx: &mut impl Renderer) { |
| spread_method(ctx, Extend::Pad); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_spread_method_repeat(ctx: &mut impl Renderer) { |
| spread_method(ctx, Extend::Repeat); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_spread_method_reflect(ctx: &mut impl Renderer) { |
| spread_method(ctx, Extend::Reflect); |
| } |
| |
| fn gradient_with_transform( |
| ctx: &mut impl Renderer, |
| transform: Affine, |
| l: f64, |
| t: f64, |
| r: f64, |
| b: f64, |
| ) { |
| let rect = Rect::new(l, t, r, b); |
| |
| let gradient = Gradient { |
| kind: GradientKind::Sweep { |
| center: Point::new((l + r) / 2.0, (t + b) / 2.0), |
| start_angle: 150.0, |
| end_angle: 210.0, |
| }, |
| stops: stops_blue_green_red_yellow(), |
| ..Default::default() |
| }; |
| |
| ctx.set_transform(transform); |
| ctx.set_paint(gradient); |
| ctx.fill_rect(&rect); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_identity(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::IDENTITY, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_translate(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::translate((25.0, 25.0)), 0.0, 0.0, 50.0, 50.0); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_scale(ctx: &mut impl Renderer) { |
| gradient_with_transform(ctx, Affine::scale(2.0), 12.5, 12.5, 37.5, 37.5); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_negative_scale(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::translate((100.0, 100.0)) * Affine::scale(-2.0), |
| 12.5, |
| 12.5, |
| 37.5, |
| 37.5, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_scale_and_translate(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::new([2.0, 0.0, 0.0, 2.0, 25.0, 25.0]), |
| 0.0, |
| 0.0, |
| 25.0, |
| 25.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_rotate_1(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::rotate_about(PI / 4.0, Point::new(50.0, 50.0)), |
| 25.0, |
| 25.0, |
| 75.0, |
| 75.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_rotate_2(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::rotate_about(-PI / 4.0, Point::new(50.0, 50.0)), |
| 25.0, |
| 25.0, |
| 75.0, |
| 75.0, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_scale_non_uniform(ctx: &mut impl Renderer) { |
| gradient_with_transform( |
| ctx, |
| Affine::scale_non_uniform(1.0, 2.0), |
| 25.0, |
| 12.5, |
| 75.0, |
| 37.5, |
| ); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_skew_x_1(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((-50.0, 0.0)) * Affine::skew(tan_45(), 0.0); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_skew_x_2(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((50.0, 0.0)) * Affine::skew(-tan_45(), 0.0); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_skew_y_1(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((0.0, 50.0)) * Affine::skew(0.0, -tan_45()); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| |
| #[vello_test] |
| fn gradient_sweep_with_transform_skew_y_2(ctx: &mut impl Renderer) { |
| let transform = Affine::translate((0.0, -50.0)) * Affine::skew(0.0, tan_45()); |
| gradient_with_transform(ctx, transform, 25.0, 25.0, 75.0, 75.0); |
| } |
| } |