blob: d6996cbd032fcf685b9ee4b6641b9029f8568e16 [file]
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT
//! Tests for GitHub issues.
use crate::renderer::Renderer;
use vello_common::color::palette::css::{DARK_BLUE, LIME, REBECCA_PURPLE};
use vello_common::kurbo::{BezPath, Rect, Shape, Stroke};
use vello_common::peniko::{Color, ColorStop, Fill, Gradient};
use vello_cpu::color::palette::css::RED;
use vello_cpu::peniko::Compose;
use vello_dev_macros::vello_test;
#[vello_test(width = 8, height = 8)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/2
fn incorrect_filling_1(ctx: &mut impl Renderer) {
let mut p = BezPath::default();
p.move_to((4.0, 0.0));
p.line_to((8.0, 4.0));
p.line_to((4.0, 8.0));
p.line_to((0.0, 4.0));
p.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&p);
}
#[vello_test(width = 64, height = 64)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/2
fn incorrect_filling_2(ctx: &mut impl Renderer) {
let mut p = BezPath::default();
p.move_to((16.0, 16.0));
p.line_to((48.0, 16.0));
p.line_to((48.0, 48.0));
p.line_to((16.0, 48.0));
p.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&p);
}
#[vello_test(width = 9, height = 9)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/2
fn incorrect_filling_3(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((4.00001, 1e-45));
path.line_to((8.00001, 4.00001));
path.line_to((4.00001, 8.00001));
path.line_to((1e-45, 4.00001));
path.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 64, height = 64)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/2
fn incorrect_filling_4(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((16.000002, 8.));
path.line_to((20.000002, 8.));
path.line_to((24.000002, 8.));
path.line_to((28.000002, 8.));
path.line_to((32.000002, 8.));
path.line_to((32.000002, 9.));
path.line_to((28.000002, 9.));
path.line_to((24.000002, 9.));
path.line_to((20.000002, 9.));
path.line_to((16.000002, 9.));
path.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 32, height = 32)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/2
fn incorrect_filling_5(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((16., 8.));
path.line_to((16., 9.));
path.line_to((32., 9.));
path.line_to((32., 8.));
path.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 32, height = 32)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/2
fn incorrect_filling_6(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((16., 8.));
path.line_to((31.999998, 8.));
path.line_to((31.999998, 9.));
path.line_to((16., 9.));
path.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 32, height = 32)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/2
fn incorrect_filling_7(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((32.000002, 9.));
path.line_to((28., 9.));
path.line_to((28., 8.));
path.line_to((32.000002, 8.));
path.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 32, height = 32)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/2
fn incorrect_filling_8(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((16.000427, 8.));
path.line_to((20.000427, 8.));
path.line_to((24.000427, 8.));
path.line_to((28.000427, 8.));
path.line_to((32.000427, 8.));
path.line_to((32.000427, 9.));
path.line_to((28.000427, 9.));
path.line_to((24.000427, 9.));
path.line_to((20.000427, 9.));
path.line_to((16.000427, 9.));
path.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 256, height = 256, no_ref)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/11
fn out_of_bound_strip(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((258.0, 254.0));
path.line_to((265.0, 254.0));
let stroke = Stroke::new(1.0);
ctx.set_paint(DARK_BLUE);
ctx.set_stroke(stroke);
// Just make sure we don't panic.
ctx.stroke_path(&path);
}
#[vello_test]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/12
fn filling_unclosed_path_1(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((75.0, 25.0));
path.line_to((25.0, 25.0));
path.line_to((25.0, 75.0));
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/12
fn filling_unclosed_path_2(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((50.0, 0.0));
path.line_to((0.0, 0.0));
path.line_to((0.0, 50.0));
path.move_to((50.0, 50.0));
path.line_to((100.0, 50.0));
path.line_to((100.0, 100.0));
path.line_to((50.0, 100.0));
path.close_path();
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 15, height = 8)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/28
fn triangle_exceeding_viewport_1(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((5.0, 0.0));
path.line_to((12.0, 7.99));
path.line_to((-4.0, 7.99));
path.close_path();
ctx.set_fill_rule(Fill::EvenOdd);
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 15, height = 8)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/28
fn triangle_exceeding_viewport_2(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((4.0, 0.0));
path.line_to((11.0, 7.99));
path.line_to((-5.0, 7.99));
path.close_path();
ctx.set_fill_rule(Fill::EvenOdd);
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 256, height = 4, no_ref)]
// https://github.com/LaurenzV/cpu-sparse-experiments/issues/30
fn shape_at_wide_tile_boundary(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((248.0, 0.0));
path.line_to((257.0, 0.0));
path.line_to((257.0, 2.0));
path.line_to((248.0, 2.0));
path.close_path();
ctx.set_fill_rule(Fill::EvenOdd);
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 50, height = 50)]
fn eo_filling_missing_anti_aliasing(ctx: &mut impl Renderer) {
let mut path = BezPath::new();
path.move_to((0.0, 0.0));
path.line_to((50.0, 50.0));
path.line_to((0.0, 50.0));
path.line_to((50.0, 0.0));
path.close_path();
ctx.set_fill_rule(Fill::EvenOdd);
ctx.set_paint(LIME);
ctx.fill_path(&path);
}
#[vello_test(width = 600, height = 600, transparent)]
// https://github.com/linebender/vello/issues/906
fn fill_command_respects_clip_bounds(ctx: &mut impl Renderer) {
ctx.push_clip_layer(&Rect::new(400.0, 400.0, 500.0, 500.0).to_path(0.1));
ctx.set_paint(REBECCA_PURPLE);
ctx.fill_rect(&Rect::new(0.0, 0.0, 600.0, 600.0));
ctx.pop_layer();
}
#[vello_test(no_ref)]
fn out_of_viewport_clip(ctx: &mut impl Renderer) {
ctx.push_clip_layer(&Rect::new(-100.0, -100.0, 0.0, 0.0).to_path(0.1));
ctx.set_paint(REBECCA_PURPLE);
ctx.fill_rect(&Rect::new(0.0, 0.0, 100.0, 100.0));
ctx.pop_layer();
}
#[vello_test(no_ref, width = 300, height = 4)]
// https://github.com/linebender/vello/issues/1032
fn nested_clip_path_panic(ctx: &mut impl Renderer) {
let path1 = Rect::new(256.0, 0.0, 257.0, 2.0).to_path(0.1);
ctx.push_clip_layer(&path1);
let path2 = Rect::new(181.0, -200.0, 760.0, 618.0).to_path(0.1);
ctx.push_clip_layer(&path2);
ctx.pop_layer();
ctx.pop_layer();
}
#[vello_test(width = 512, height = 4)]
// https://github.com/linebender/vello/issues/1034
fn nested_clip_path_panic_2(ctx: &mut impl Renderer) {
let path1 = Rect::new(256.0, 0.0, 280.0, 2.0).to_path(0.1);
ctx.push_clip_layer(&path1);
let path2 = Rect::new(0.0, 0.0, 511.0, 4.0).to_path(0.1);
ctx.push_clip_layer(&path2);
ctx.set_paint(RED);
ctx.fill_path(&Rect::new(0.0, 0.0, 511.0, 4.0).to_path(0.1));
ctx.pop_layer();
ctx.pop_layer();
}
#[vello_test(no_ref, width = 10, height = 16)]
// https://github.com/linebender/vello/issues/1072
fn intersected_clip_bbox_with_x0_gt_x1(ctx: &mut impl Renderer) {
ctx.push_clip_layer(&Rect::new(0., 0., 4., 4.).to_path(0.1));
ctx.push_clip_layer(&Rect::new(0., 8., 260., 16.).to_path(0.1));
ctx.pop_layer();
ctx.pop_layer();
}
// https://github.com/web-platform-tests/wpt/blob/cfd9285284893e6d63d7770deae0789d7f7457d4/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside3.html
// See <https://github.com/linebender/vello/issues/1124>.
#[vello_test(width = 100, height = 50)]
fn gradient_radial_inside(ctx: &mut impl Renderer) {
ctx.set_paint(
Gradient::new_two_point_radial((50., 25.), 200., (50., 25.), 100.).with_stops([
ColorStop {
offset: 0.,
color: Color::from_rgb8(255, 0, 0).into(),
},
ColorStop {
offset: 0.993,
color: Color::from_rgb8(255, 0, 0).into(),
},
ColorStop {
offset: 1.,
color: Color::from_rgb8(0, 255, 0).into(),
},
]),
);
ctx.fill_rect(&Rect::new(0., 0., 100., 50.));
}
// https://github.com/web-platform-tests/wpt/blob/cfd9285284893e6d63d7770deae0789d7f7457d4/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside3.html
// See <https://github.com/linebender/vello/issues/1124>.
#[vello_test(width = 100, height = 50)]
fn gradient_radial_outside(ctx: &mut impl Renderer) {
ctx.set_paint(
Gradient::new_two_point_radial((200., 25.), 20., (200., 25.), 10.).with_stops([
ColorStop {
offset: 0.,
color: Color::from_rgb8(0, 255, 0).into(),
},
ColorStop {
offset: 0.001,
color: Color::from_rgb8(255, 0, 0).into(),
},
ColorStop {
offset: 1.,
color: Color::from_rgb8(255, 0, 0).into(),
},
]),
);
ctx.fill_rect(&Rect::new(0., 0., 100., 50.));
}
#[vello_test(no_ref)]
/// <https://github.com/linebender/vello/issues/1113>
fn do_not_panic_on_multiple_flushes(ctx: &mut impl Renderer) {
ctx.fill_rect(&Rect::new(0.0, 0.0, 4.0, 4.0));
ctx.flush();
ctx.fill_rect(&Rect::new(0.0, 0.0, 4.0, 4.0));
ctx.flush();
ctx.fill_rect(&Rect::new(0.0, 0.0, 4.0, 4.0));
}
/// <https://github.com/linebender/vello/issues/1119>
#[vello_test]
fn clip_clear(ctx: &mut impl Renderer) {
// initial coloring
ctx.set_paint(LIME);
ctx.fill_rect(&Rect::new(0.0, 0.0, 100.0, 100.0));
ctx.push_layer(
Some(&Rect::new(0., 0., 50., 50.).to_path(0.1)),
Some(Compose::Clear.into()),
None,
None,
);
ctx.pop_layer();
}
/// https://github.com/web-platform-tests/wpt/blob/18c64a74b1/html/canvas/element/fill-and-stroke-styles/2d.gradient.interpolate.coloralpha.html
/// See <https://github.com/linebender/vello/issues/1056>.
#[vello_test(width = 100, height = 50)]
fn gradient_color_alpha(ctx: &mut impl Renderer) {
let viewport = Rect::new(0., 0., 100., 50.);
ctx.set_paint(Gradient::new_linear((0., 0.), (100., 0.)).with_stops([
ColorStop {
offset: 0.,
color: Color::from_rgba8(255, 255, 0, 0).into(),
},
ColorStop {
offset: 1.,
color: Color::from_rgba8(0, 0, 255, 255).into(),
},
]));
ctx.fill_rect(&viewport);
}