mirror of
https://github.com/servo/servo.git
synced 2025-08-02 04:00:32 +01:00
canvas: Add vello_cpu backend (#38282)
vello_cpu does not have any tests timeouts, because we do not need download stuff from GPU as all work happens on CPU. So performance wise it's better then classic vello at least for our usecase. There are some vello bugs, but I think we will be able to sort them out within upstream, eventually. Interestingly enough there are no new PASS like they were with classic vello. Difference with raqote can be observed here: https://github.com/sagudev/servo/actions/runs/16549241085/attempts/1#summary-46802486798 ## Known vello problems: - https://github.com/linebender/vello/issues/1119 - https://github.com/linebender/vello/issues/1056 - `/html/canvas/element/fill-and-stroke-styles/2d.gradient.interpolate.coloralpha.html` - `kurbo::Cap::Butt` is defect (only visible with big lineWidth) https://github.com/linebender/vello/issues/1063 - `/html/canvas/element/line-styles/2d.line.cross.html` - `/html/canvas/element/line-styles/2d.line.miter.acute.html` - other lack of strong correct problems (https://github.com/linebender/vello/issues/1063#issuecomment-2998084736): - `/html/canvas/element/path-objects/2d.path.rect.selfintersect.html` - `putImageData(getImageData(...), ...)` is lossy (precision problems, might be due to ImageData being unmultiplied) - `/html/canvas/element/pixel-manipulation/2d.imageData.put.unchanged.html` Testing: Tested using vello_cpu_canvas subsuite --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
15be75f955
commit
056b1538c0
39 changed files with 694 additions and 11 deletions
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -1087,6 +1087,7 @@ dependencies = [
|
|||
"stylo",
|
||||
"unicode-script",
|
||||
"vello",
|
||||
"vello_cpu",
|
||||
"webrender_api",
|
||||
]
|
||||
|
||||
|
@ -1335,6 +1336,9 @@ name = "color"
|
|||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ae467d04a8a8aea5d9a49018a6ade2e4221d92968e8ce55a48c0b1164e5f698"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
|
@ -1355,7 +1359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2464,6 +2468,14 @@ dependencies = [
|
|||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fearless_simd"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/linebender/fearless_simd?rev=3d1a77c#3d1a77cfb4515c0da307d50dc782c08840b90c70"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.25"
|
||||
|
@ -4833,7 +4845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.48.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6220,6 +6232,7 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f9529efd019889b2a205193c14ffb6e2839b54ed9d2720674f10f4b04d87ac9"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"color",
|
||||
"kurbo",
|
||||
"smallvec",
|
||||
|
@ -9135,7 +9148,7 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
|||
[[package]]
|
||||
name = "vello"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/linebender/vello?rev=ecf6b282dba01e5dc50e9463b87b6baeccdb3094#ecf6b282dba01e5dc50e9463b87b6baeccdb3094"
|
||||
source = "git+https://github.com/linebender/vello?rev=daf940230a24cbb123a458b6de95721af47aef98#daf940230a24cbb123a458b6de95721af47aef98"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"futures-intrusive",
|
||||
|
@ -9150,10 +9163,33 @@ dependencies = [
|
|||
"wgpu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vello_common"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/linebender/vello?rev=daf940230a24cbb123a458b6de95721af47aef98#daf940230a24cbb123a458b6de95721af47aef98"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"fearless_simd",
|
||||
"log",
|
||||
"peniko",
|
||||
"png",
|
||||
"skrifa",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vello_cpu"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/linebender/vello?rev=daf940230a24cbb123a458b6de95721af47aef98#daf940230a24cbb123a458b6de95721af47aef98"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"vello_common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vello_encoding"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/linebender/vello?rev=ecf6b282dba01e5dc50e9463b87b6baeccdb3094#ecf6b282dba01e5dc50e9463b87b6baeccdb3094"
|
||||
source = "git+https://github.com/linebender/vello?rev=daf940230a24cbb123a458b6de95721af47aef98#daf940230a24cbb123a458b6de95721af47aef98"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"guillotiere",
|
||||
|
@ -9165,7 +9201,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "vello_shaders"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/linebender/vello?rev=ecf6b282dba01e5dc50e9463b87b6baeccdb3094#ecf6b282dba01e5dc50e9463b87b6baeccdb3094"
|
||||
source = "git+https://github.com/linebender/vello?rev=daf940230a24cbb123a458b6de95721af47aef98#daf940230a24cbb123a458b6de95721af47aef98"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"log",
|
||||
|
@ -9885,7 +9921,7 @@ version = "0.1.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -168,7 +168,8 @@ unicode-segmentation = "1.12.0"
|
|||
url = "2.5"
|
||||
urlpattern = "0.3"
|
||||
uuid = { version = "1.12.1", features = ["v4"] }
|
||||
vello = { git = "https://github.com/linebender/vello", rev = "ecf6b282dba01e5dc50e9463b87b6baeccdb3094" }
|
||||
vello = { git = "https://github.com/linebender/vello", rev = "daf940230a24cbb123a458b6de95721af47aef98" }
|
||||
vello_cpu = { git = "https://github.com/linebender/vello", rev = "daf940230a24cbb123a458b6de95721af47aef98" }
|
||||
webdriver = "0.53.0"
|
||||
webgpu_traits = { path = "components/shared/webgpu" }
|
||||
webpki-roots = "1.0"
|
||||
|
|
|
@ -13,6 +13,7 @@ path = "lib.rs"
|
|||
|
||||
[features]
|
||||
vello = ["dep:vello", "dep:pollster", "dep:futures-intrusive", "dep:peniko"]
|
||||
vello_cpu = ["dep:vello_cpu", "dep:peniko"]
|
||||
|
||||
[dependencies]
|
||||
app_units = { workspace = true }
|
||||
|
@ -38,5 +39,6 @@ unicode-script = { workspace = true }
|
|||
webrender_api = { workspace = true }
|
||||
servo_config = { path = "../config" }
|
||||
vello = { workspace = true, optional = true }
|
||||
vello_cpu = { workspace = true, optional = true }
|
||||
pollster = { version = "0.4", optional = true }
|
||||
futures-intrusive = { version = "0.5", optional = true }
|
||||
|
|
|
@ -296,6 +296,8 @@ enum Canvas {
|
|||
Raqote(CanvasData<raqote::DrawTarget>),
|
||||
#[cfg(feature = "vello")]
|
||||
Vello(CanvasData<crate::vello_backend::VelloDrawTarget>),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
VelloCPU(CanvasData<crate::vello_cpu_backend::VelloCPUDrawTarget>),
|
||||
}
|
||||
|
||||
impl Canvas {
|
||||
|
@ -308,6 +310,10 @@ impl Canvas {
|
|||
if servo_config::pref!(dom_canvas_vello_enabled) {
|
||||
return Self::Vello(CanvasData::new(size, compositor_api, font_context));
|
||||
}
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
if servo_config::pref!(dom_canvas_vello_cpu_enabled) {
|
||||
return Self::VelloCPU(CanvasData::new(size, compositor_api, font_context));
|
||||
}
|
||||
Self::Raqote(CanvasData::new(size, compositor_api, font_context))
|
||||
}
|
||||
|
||||
|
@ -316,6 +322,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.image_key(),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.image_key(),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.image_key(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,6 +332,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.pop_clip(),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.pop_clip(),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.pop_clip(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,6 +376,19 @@ impl Canvas {
|
|||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.fill_text(
|
||||
text,
|
||||
x,
|
||||
y,
|
||||
max_width,
|
||||
is_rtl,
|
||||
style,
|
||||
text_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,6 +408,10 @@ impl Canvas {
|
|||
Canvas::Vello(canvas_data) => {
|
||||
canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform)
|
||||
},
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => {
|
||||
canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,6 +442,15 @@ impl Canvas {
|
|||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.stroke_rect(
|
||||
rect,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,6 +481,15 @@ impl Canvas {
|
|||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.fill_path(
|
||||
path,
|
||||
fill_rule,
|
||||
style,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -475,6 +520,15 @@ impl Canvas {
|
|||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.stroke_path(
|
||||
path,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,6 +537,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.clear_rect(rect, transform),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.clear_rect(rect, transform),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.clear_rect(rect, transform),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,6 +572,16 @@ impl Canvas {
|
|||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.draw_image(
|
||||
snapshot,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,6 +590,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.read_pixels(read_rect),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.read_pixels(read_rect),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.read_pixels(read_rect),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -532,6 +600,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.measure_text(text, text_options),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.measure_text(text, text_options),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.measure_text(text, text_options),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,6 +610,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.clip_path(path, fill_rule, transform),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.clip_path(path, fill_rule, transform),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.clip_path(path, fill_rule, transform),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -548,6 +620,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.put_image_data(snapshot, rect),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.put_image_data(snapshot, rect),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.put_image_data(snapshot, rect),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,6 +630,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.update_image_rendering(),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.update_image_rendering(),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.update_image_rendering(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,6 +640,8 @@ impl Canvas {
|
|||
Canvas::Raqote(canvas_data) => canvas_data.recreate(size),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.recreate(size),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
Canvas::VelloCPU(canvas_data) => canvas_data.recreate(size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
#![deny(unsafe_code)]
|
||||
|
||||
mod backend;
|
||||
#[cfg(feature = "vello")]
|
||||
#[cfg(any(feature = "vello", feature = "vello_cpu"))]
|
||||
mod peniko_conversions;
|
||||
mod raqote_backend;
|
||||
#[cfg(feature = "vello")]
|
||||
mod vello_backend;
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
mod vello_cpu_backend;
|
||||
|
||||
pub mod canvas_data;
|
||||
pub mod canvas_paint_thread;
|
||||
|
|
452
components/canvas/vello_cpu_backend.rs
Normal file
452
components/canvas/vello_cpu_backend.rs
Normal file
|
@ -0,0 +1,452 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use canvas_traits::canvas::{
|
||||
CompositionOptions, FillOrStrokeStyle, FillRule, LineOptions, Path, ShadowOptions,
|
||||
};
|
||||
use compositing_traits::SerializableImageData;
|
||||
use euclid::default::{Point2D, Rect, Size2D, Transform2D};
|
||||
use fonts::{ByteIndex, FontIdentifier, FontTemplateRefMethods as _};
|
||||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use kurbo::Shape;
|
||||
use pixels::{Snapshot, SnapshotAlphaMode, SnapshotPixelFormat};
|
||||
use range::Range;
|
||||
use vello_cpu::{kurbo, peniko};
|
||||
use webrender_api::{ImageDescriptor, ImageDescriptorFlags};
|
||||
|
||||
use crate::backend::{Convert, GenericDrawTarget};
|
||||
use crate::canvas_data::{Filter, TextRun};
|
||||
|
||||
thread_local! {
|
||||
/// The shared font cache used by all canvases that render on a thread. It would be nicer
|
||||
/// to have a global cache, but it looks like font-kit uses a per-thread FreeType, so
|
||||
/// in order to ensure that fonts are particular to a thread we have to make our own
|
||||
/// cache thread local as well.
|
||||
static SHARED_FONT_CACHE: RefCell<HashMap<FontIdentifier, peniko::Font>> = RefCell::default();
|
||||
}
|
||||
|
||||
pub(crate) struct VelloCPUDrawTarget {
|
||||
/// Because this is stateful context
|
||||
/// caller cannot assume anything about transform, paint, stroke,
|
||||
/// so it should provide it's own used by each command
|
||||
/// but it can assume paint_transform to be identity
|
||||
/// and fill rule to be `peniko::Fill::NonZero`
|
||||
///
|
||||
/// This is because paint_transform is rarely set,
|
||||
/// so it's cheaper to always reset it after use.
|
||||
ctx: vello_cpu::RenderContext,
|
||||
pixmap: vello_cpu::Pixmap,
|
||||
clips: Vec<Path>,
|
||||
}
|
||||
|
||||
impl VelloCPUDrawTarget {
|
||||
fn with_composition(
|
||||
&mut self,
|
||||
composition_options: &CompositionOptions,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
self.ctx.push_layer(
|
||||
None,
|
||||
Some(composition_options.composition_operation.convert()),
|
||||
Some(composition_options.alpha as f32),
|
||||
None,
|
||||
);
|
||||
f(self);
|
||||
self.ctx.pop_layer();
|
||||
}
|
||||
|
||||
fn ignore_clips(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
// pop all clip layers
|
||||
for _ in &self.clips {
|
||||
self.ctx.pop_layer();
|
||||
}
|
||||
f(self);
|
||||
// push all clip layers back
|
||||
for path in &self.clips {
|
||||
self.ctx.push_clip_layer(&path.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn pixmap(&mut self) -> &[u8] {
|
||||
self.ignore_clips(|self_| {
|
||||
self_.ctx.flush();
|
||||
self_
|
||||
.ctx
|
||||
.render_to_pixmap(&mut self_.pixmap, vello_cpu::RenderMode::OptimizeQuality)
|
||||
});
|
||||
|
||||
self.pixmap.data_as_u8_slice()
|
||||
}
|
||||
|
||||
fn size(&self) -> Size2D<u32> {
|
||||
Size2D::new(self.ctx.width(), self.ctx.height()).cast()
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericDrawTarget for VelloCPUDrawTarget {
|
||||
type SourceSurface = Arc<vello_cpu::Pixmap>;
|
||||
|
||||
fn new(size: Size2D<u32>) -> Self {
|
||||
let size = size.cast();
|
||||
Self {
|
||||
ctx: vello_cpu::RenderContext::new(size.width, size.height),
|
||||
pixmap: vello_cpu::Pixmap::new(size.width, size.height),
|
||||
clips: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) {
|
||||
let rect: kurbo::Rect = rect.cast().into();
|
||||
let mut clip_path = rect.to_path(0.1);
|
||||
clip_path.apply_affine(transform.cast().into());
|
||||
let blend_mode = peniko::Compose::Clear;
|
||||
self.ctx.push_layer(
|
||||
Some(&clip_path.to_path(0.1)),
|
||||
Some(blend_mode.into()),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
self.ctx.pop_layer();
|
||||
}
|
||||
|
||||
fn copy_surface(
|
||||
&mut self,
|
||||
surface: Self::SourceSurface,
|
||||
source: Rect<i32>,
|
||||
destination: Point2D<i32>,
|
||||
) {
|
||||
let destination: kurbo::Point = destination.cast::<f64>().into();
|
||||
let rect = kurbo::Rect::from_origin_size(destination, source.size.cast());
|
||||
self.ctx.set_transform(kurbo::Affine::IDENTITY);
|
||||
self.ignore_clips(|self_| {
|
||||
// Clipped blending does not work correctly:
|
||||
// https://github.com/linebender/vello/issues/1119
|
||||
//self_.push_layer(Some(rect.to_path(0.1)), Some(peniko::Compose::Copy.into()), None, None);
|
||||
|
||||
self_.ctx.set_paint(vello_cpu::Image {
|
||||
source: vello_cpu::ImageSource::Pixmap(surface),
|
||||
x_extend: peniko::Extend::Pad,
|
||||
y_extend: peniko::Extend::Pad,
|
||||
quality: peniko::ImageQuality::Low,
|
||||
});
|
||||
self_.ctx.fill_rect(&rect);
|
||||
|
||||
//self_.ctx.pop_layer();
|
||||
});
|
||||
}
|
||||
|
||||
fn create_similar_draw_target(&self, size: &Size2D<i32>) -> Self {
|
||||
Self::new(size.cast())
|
||||
}
|
||||
|
||||
fn draw_surface(
|
||||
&mut self,
|
||||
surface: Self::SourceSurface,
|
||||
dest: Rect<f64>,
|
||||
source: Rect<f64>,
|
||||
filter: Filter,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
let scale_up = dest.size.width > source.size.width || dest.size.height > source.size.height;
|
||||
self.with_composition(&composition_options, move |self_| {
|
||||
self_.ctx.set_transform(transform.cast().into());
|
||||
self_.ctx.set_paint(vello_cpu::Image {
|
||||
source: vello_cpu::ImageSource::Pixmap(surface),
|
||||
x_extend: peniko::Extend::Pad,
|
||||
y_extend: peniko::Extend::Pad,
|
||||
// we should only do bicubic when scaling up
|
||||
quality: if scale_up {
|
||||
filter.convert()
|
||||
} else {
|
||||
peniko::ImageQuality::Low
|
||||
},
|
||||
});
|
||||
self_.ctx.set_paint_transform(
|
||||
kurbo::Affine::translate((dest.origin.x, dest.origin.y)).pre_scale_non_uniform(
|
||||
dest.size.width / source.size.width,
|
||||
dest.size.height / source.size.height,
|
||||
),
|
||||
);
|
||||
self_.ctx.fill_rect(&dest.into());
|
||||
self_.ctx.reset_paint_transform();
|
||||
})
|
||||
}
|
||||
|
||||
fn draw_surface_with_shadow(
|
||||
&self,
|
||||
_surface: Self::SourceSurface,
|
||||
_dest: &Point2D<f32>,
|
||||
_shadow_options: ShadowOptions,
|
||||
_composition_options: CompositionOptions,
|
||||
) {
|
||||
log::warn!("no support for drawing shadows");
|
||||
/*
|
||||
We will need to do some changes to support drawing shadows with vello, as current abstraction is made for azure.
|
||||
In vello we do not need new draw target (we will use layers) and we need to pass whole rect.
|
||||
offsets will be applied to rect directly. shadow blur will be passed directly to let backend do transforms.
|
||||
*/
|
||||
//self_.scene.draw_blurred_rounded_rect(self_.transform, rect, color, 0.0, sigma);
|
||||
}
|
||||
|
||||
fn fill(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
fill_rule: FillRule,
|
||||
style: FillOrStrokeStyle,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
let paint: vello_cpu::PaintType = style.convert();
|
||||
self.with_composition(&composition_options, |self_| {
|
||||
self_.ctx.set_transform(transform.cast().into());
|
||||
self_.ctx.set_fill_rule(fill_rule.convert());
|
||||
self_.ctx.set_paint(paint);
|
||||
self_.ctx.fill_path(&path.0);
|
||||
});
|
||||
self.ctx.set_fill_rule(peniko::Fill::NonZero);
|
||||
}
|
||||
|
||||
fn fill_text(
|
||||
&mut self,
|
||||
text_runs: Vec<TextRun>,
|
||||
start: Point2D<f32>,
|
||||
style: FillOrStrokeStyle,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
let style: vello_cpu::PaintType = style.convert();
|
||||
self.ctx.set_paint(style);
|
||||
self.ctx.set_transform(transform.cast().into());
|
||||
self.with_composition(&composition_options, |self_| {
|
||||
let mut advance = 0.;
|
||||
for run in text_runs.iter() {
|
||||
let glyphs = &run.glyphs;
|
||||
|
||||
let template = &run.font.template;
|
||||
|
||||
SHARED_FONT_CACHE.with(|font_cache| {
|
||||
let identifier = template.identifier();
|
||||
if !font_cache.borrow().contains_key(&identifier) {
|
||||
font_cache.borrow_mut().insert(
|
||||
identifier.clone(),
|
||||
peniko::Font::new(
|
||||
peniko::Blob::from(run.font.data().as_ref().to_vec()),
|
||||
identifier.index(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
let font_cache = font_cache.borrow();
|
||||
let Some(font) = font_cache.get(&identifier) else {
|
||||
return;
|
||||
};
|
||||
|
||||
self_
|
||||
.ctx
|
||||
.glyph_run(font)
|
||||
.font_size(run.font.descriptor.pt_size.to_f32_px())
|
||||
.fill_glyphs(
|
||||
glyphs
|
||||
.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), glyphs.len()))
|
||||
.map(|glyph| {
|
||||
let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
|
||||
let x = advance + start.x + glyph_offset.x.to_f32_px();
|
||||
let y = start.y + glyph_offset.y.to_f32_px();
|
||||
advance += glyph.advance().to_f32_px();
|
||||
vello_cpu::Glyph {
|
||||
id: glyph.id(),
|
||||
x,
|
||||
y,
|
||||
}
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn fill_rect(
|
||||
&mut self,
|
||||
rect: &Rect<f32>,
|
||||
style: FillOrStrokeStyle,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
let paint: vello_cpu::PaintType = style.convert();
|
||||
self.with_composition(&composition_options, |self_| {
|
||||
self_.ctx.set_transform(transform.cast().into());
|
||||
self_.ctx.set_paint(paint);
|
||||
self_.ctx.fill_rect(&rect.cast().into());
|
||||
})
|
||||
}
|
||||
|
||||
fn get_size(&self) -> Size2D<i32> {
|
||||
self.size().cast()
|
||||
}
|
||||
|
||||
fn pop_clip(&mut self) {
|
||||
if self.clips.pop().is_some() {
|
||||
self.ctx.pop_layer();
|
||||
}
|
||||
}
|
||||
|
||||
fn push_clip(&mut self, path: &Path, fill_rule: FillRule, transform: Transform2D<f32>) {
|
||||
self.ctx.set_transform(transform.cast().into());
|
||||
let mut path = path.clone();
|
||||
path.transform(transform.cast());
|
||||
self.ctx.set_fill_rule(fill_rule.convert());
|
||||
self.ctx.push_clip_layer(&path.0);
|
||||
self.clips.push(path);
|
||||
self.ctx.set_fill_rule(peniko::Fill::NonZero);
|
||||
}
|
||||
|
||||
fn push_clip_rect(&mut self, rect: &Rect<i32>) {
|
||||
let mut path = Path::new();
|
||||
let rect = rect.cast();
|
||||
path.rect(
|
||||
rect.origin.x,
|
||||
rect.origin.y,
|
||||
rect.size.width,
|
||||
rect.size.height,
|
||||
);
|
||||
self.push_clip(&path, FillRule::Nonzero, Transform2D::identity());
|
||||
}
|
||||
|
||||
fn stroke(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
style: FillOrStrokeStyle,
|
||||
line_options: LineOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
let paint: vello_cpu::PaintType = style.convert();
|
||||
self.with_composition(&composition_options, |self_| {
|
||||
self_.ctx.set_transform(transform.cast().into());
|
||||
self_.ctx.set_paint(paint);
|
||||
self_.ctx.set_stroke(line_options.convert());
|
||||
self_.ctx.stroke_path(&path.0);
|
||||
})
|
||||
}
|
||||
|
||||
fn stroke_rect(
|
||||
&mut self,
|
||||
rect: &Rect<f32>,
|
||||
style: FillOrStrokeStyle,
|
||||
line_options: LineOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f32>,
|
||||
) {
|
||||
let paint: vello_cpu::PaintType = style.convert();
|
||||
self.with_composition(&composition_options, |self_| {
|
||||
self_.ctx.set_transform(transform.cast().into());
|
||||
self_.ctx.set_paint(paint);
|
||||
self_.ctx.set_stroke(line_options.convert());
|
||||
self_.ctx.stroke_rect(&rect.cast().into());
|
||||
})
|
||||
}
|
||||
|
||||
fn image_descriptor_and_serializable_data(
|
||||
&mut self,
|
||||
) -> (ImageDescriptor, SerializableImageData) {
|
||||
let image_desc = ImageDescriptor {
|
||||
format: webrender_api::ImageFormat::RGBA8,
|
||||
size: self.size().cast().cast_unit(),
|
||||
stride: None,
|
||||
offset: 0,
|
||||
flags: ImageDescriptorFlags::empty(),
|
||||
};
|
||||
let data = SerializableImageData::Raw(IpcSharedMemory::from_bytes(self.pixmap()));
|
||||
(image_desc, data)
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> pixels::Snapshot {
|
||||
Snapshot::from_vec(
|
||||
self.size().cast(),
|
||||
SnapshotPixelFormat::RGBA,
|
||||
SnapshotAlphaMode::Transparent {
|
||||
premultiplied: true,
|
||||
},
|
||||
self.pixmap().to_vec(),
|
||||
)
|
||||
}
|
||||
|
||||
fn surface(&mut self) -> Self::SourceSurface {
|
||||
self.pixmap(); // sync pixmap
|
||||
Arc::new(vello_cpu::Pixmap::from_parts(
|
||||
self.pixmap.clone().take(),
|
||||
self.pixmap.width(),
|
||||
self.pixmap.height(),
|
||||
))
|
||||
}
|
||||
|
||||
fn create_source_surface_from_data(&self, data: Snapshot) -> Option<Self::SourceSurface> {
|
||||
Some(snapshot_as_pixmap(data))
|
||||
}
|
||||
}
|
||||
|
||||
fn snapshot_as_pixmap(data: Snapshot) -> Arc<vello_cpu::Pixmap> {
|
||||
let size = data.size().cast();
|
||||
let (data, _, _) = data.to_vec(
|
||||
Some(SnapshotAlphaMode::Transparent {
|
||||
premultiplied: true,
|
||||
}),
|
||||
Some(SnapshotPixelFormat::RGBA),
|
||||
);
|
||||
Arc::new(vello_cpu::Pixmap::from_parts(
|
||||
bytemuck::cast_vec(data),
|
||||
size.width,
|
||||
size.height,
|
||||
))
|
||||
}
|
||||
|
||||
impl Convert<vello_cpu::PaintType> for FillOrStrokeStyle {
|
||||
fn convert(self) -> vello_cpu::PaintType {
|
||||
use canvas_traits::canvas::FillOrStrokeStyle::*;
|
||||
match self {
|
||||
Color(absolute_color) => vello_cpu::PaintType::Solid(absolute_color.convert()),
|
||||
LinearGradient(style) => {
|
||||
let start = kurbo::Point::new(style.x0, style.y0);
|
||||
let end = kurbo::Point::new(style.x1, style.y1);
|
||||
let mut gradient = peniko::Gradient::new_linear(start, end);
|
||||
gradient.stops = style.stops.convert();
|
||||
vello_cpu::PaintType::Gradient(gradient)
|
||||
},
|
||||
RadialGradient(style) => {
|
||||
let center1 = kurbo::Point::new(style.x0, style.y0);
|
||||
let center2 = kurbo::Point::new(style.x1, style.y1);
|
||||
let mut gradient = peniko::Gradient::new_two_point_radial(
|
||||
center1,
|
||||
style.r0 as f32,
|
||||
center2,
|
||||
style.r1 as f32,
|
||||
);
|
||||
gradient.stops = style.stops.convert();
|
||||
vello_cpu::PaintType::Gradient(gradient)
|
||||
},
|
||||
Surface(surface_style) => {
|
||||
let pixmap = snapshot_as_pixmap(surface_style.surface_data.to_owned());
|
||||
vello_cpu::PaintType::Image(vello_cpu::Image {
|
||||
source: vello_cpu::ImageSource::Pixmap(pixmap),
|
||||
x_extend: if surface_style.repeat_x {
|
||||
peniko::Extend::Repeat
|
||||
} else {
|
||||
peniko::Extend::Pad
|
||||
},
|
||||
y_extend: if surface_style.repeat_y {
|
||||
peniko::Extend::Repeat
|
||||
} else {
|
||||
peniko::Extend::Pad
|
||||
},
|
||||
quality: peniko::ImageQuality::Low,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
|
@ -78,6 +78,8 @@ pub struct Preferences {
|
|||
pub dom_canvas_text_enabled: bool,
|
||||
/// Uses vello as canvas backend
|
||||
pub dom_canvas_vello_enabled: bool,
|
||||
/// Uses vello_cpu as canvas backend
|
||||
pub dom_canvas_vello_cpu_enabled: bool,
|
||||
pub dom_clipboardevent_enabled: bool,
|
||||
pub dom_composition_event_enabled: bool,
|
||||
pub dom_cookiestore_enabled: bool,
|
||||
|
@ -258,6 +260,7 @@ impl Preferences {
|
|||
dom_canvas_capture_enabled: false,
|
||||
dom_canvas_text_enabled: true,
|
||||
dom_canvas_vello_enabled: false,
|
||||
dom_canvas_vello_cpu_enabled: false,
|
||||
dom_clipboardevent_enabled: true,
|
||||
dom_composition_event_enabled: false,
|
||||
dom_cookiestore_enabled: false,
|
||||
|
|
|
@ -17,6 +17,7 @@ default = []
|
|||
tracing = ["dep:tracing"]
|
||||
webgpu = ["script_traits/webgpu"]
|
||||
vello = ["canvas/vello"]
|
||||
vello_cpu = ["canvas/vello_cpu"]
|
||||
|
||||
[dependencies]
|
||||
background_hang_monitor = { path = "../background_hang_monitor" }
|
||||
|
|
|
@ -63,6 +63,7 @@ webgpu = [
|
|||
"constellation_traits/webgpu",
|
||||
]
|
||||
vello = ["constellation/vello"]
|
||||
vello_cpu = ["constellation/vello_cpu"]
|
||||
|
||||
[dependencies]
|
||||
background_hang_monitor = { path = "../background_hang_monitor" }
|
||||
|
|
|
@ -53,6 +53,7 @@ webgl_backtrace = ["libservo/webgl_backtrace"]
|
|||
webgpu = ["libservo/webgpu"]
|
||||
webxr = ["libservo/webxr"]
|
||||
vello = ["libservo/vello"]
|
||||
vello_cpu = ["libservo/vello_cpu"]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = { workspace = true }
|
||||
|
|
|
@ -125,6 +125,19 @@ def handle_preset(s: str) -> Optional[JobConfig]:
|
|||
unit_tests=False,
|
||||
number_of_wpt_chunks=2,
|
||||
)
|
||||
elif any(word in s for word in ["vello-cpu", "vello_cpu"]):
|
||||
return JobConfig(
|
||||
"Vello-CPU WPT",
|
||||
Workflow.LINUX,
|
||||
wpt=True,
|
||||
wpt_args=" ".join(
|
||||
[
|
||||
"--subsuite-file ./tests/wpt/vello_cpu_canvas_subsuite.json",
|
||||
"--subsuite vello_cpu_canvas",
|
||||
]
|
||||
),
|
||||
build_args="--features 'vello_cpu'",
|
||||
)
|
||||
elif any(word in s for word in ["vello"]):
|
||||
return JobConfig(
|
||||
"Vello WPT",
|
||||
|
|
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.clear.html.ini
vendored
Normal file
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.clear.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.clip.clear.html]
|
||||
[fill() does not affect pixels outside the clip region.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.copy.html.ini
vendored
Normal file
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.copy.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.clip.copy.html]
|
||||
[fill() does not affect pixels outside the clip region.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-atop.html.ini
vendored
Normal file
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-atop.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.clip.destination-atop.html]
|
||||
[fill() does not affect pixels outside the clip region.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-in.html.ini
vendored
Normal file
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-in.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.clip.destination-in.html]
|
||||
[fill() does not affect pixels outside the clip region.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-in.html.ini
vendored
Normal file
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-in.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.clip.source-in.html]
|
||||
[fill() does not affect pixels outside the clip region.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-out.html.ini
vendored
Normal file
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-out.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.clip.source-out.html]
|
||||
[fill() does not affect pixels outside the clip region.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.copy.html.ini
vendored
Normal file
4
tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.copy.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.uncovered.pattern.copy.html]
|
||||
[Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.uncovered.pattern.destination-atop.html]
|
||||
[Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.uncovered.pattern.destination-in.html]
|
||||
[Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.uncovered.pattern.source-in.html]
|
||||
[Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.composite.uncovered.pattern.source-out.html]
|
||||
[Pattern fill() draws pixels not covered by the source object as (0,0,0,0), and does not leave the pixels unchanged.]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.clearRect.clip.html]
|
||||
[clearRect is affected by clipping regions]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.clearRect.shadow.html]
|
||||
[clearRect does not draw shadows]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.clearRect.zero.html]
|
||||
[clearRect of zero pixels has no effect]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -3,3 +3,4 @@
|
|||
bug: https://github.com/linebender/vello/issues/1056
|
||||
expected:
|
||||
if subsuite == "vello_canvas": FAIL
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[2d.gradient.radial.cone.front.html]
|
||||
[Canvas test: 2d.gradient.radial.cone.front]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.gradient.radial.cone.top.html]
|
||||
[Canvas test: 2d.gradient.radial.cone.top]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.gradient.radial.inside2.html]
|
||||
[Canvas test: 2d.gradient.radial.inside2]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.gradient.radial.inside3.html]
|
||||
[Canvas test: 2d.gradient.radial.inside3]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -0,0 +1,4 @@
|
|||
[2d.gradient.radial.outside1.html]
|
||||
[Canvas test: 2d.gradient.radial.outside1]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -2,3 +2,4 @@
|
|||
[Canvas test: 2d.gradient.radial.outside3]
|
||||
expected:
|
||||
if subsuite == "": FAIL
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
bug: https://github.com/linebender/vello/issues/1063
|
||||
expected:
|
||||
if subsuite == "vello_canvas": FAIL
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
[Non-uniformly scaled arcs are the right shape]
|
||||
expected:
|
||||
if subsuite == "vello_canvas": FAIL
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[2d.path.rect.selfintersect.html]
|
||||
[Canvas test: 2d.path.rect.selfintersect]
|
||||
bug: https://github.com/linebender/vello/issues/1063#issuecomment-2998084736
|
||||
bug: https://github.com/linebender/vello/issues/1063 #issuecomment-2998084736
|
||||
expected:
|
||||
if subsuite == "vello_canvas": FAIL
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
[Stroke line widths are scaled by the current transformation matrix]
|
||||
expected:
|
||||
if subsuite == "vello_canvas": FAIL
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
||||
|
|
4
tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.alpha.html.ini
vendored
Normal file
4
tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.alpha.html.ini
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[2d.imageData.put.alpha.html]
|
||||
[putImageData() puts non-solid image data correctly]
|
||||
expected:
|
||||
if subsuite == "vello_cpu_canvas": FAIL
|
|
@ -1,4 +1,3 @@
|
|||
[2d.imageData.put.unchanged.html]
|
||||
[putImageData(getImageData(...), ...) has no effect]
|
||||
expected:
|
||||
if subsuite == "": FAIL
|
||||
expected: FAIL
|
||||
|
|
8
tests/wpt/vello_cpu_canvas_subsuite.json
vendored
Normal file
8
tests/wpt/vello_cpu_canvas_subsuite.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"vello_cpu_canvas": {
|
||||
"config": {
|
||||
"binary_args": ["--pref", "dom_canvas_vello_cpu_enabled"]
|
||||
},
|
||||
"include": ["/html/canvas/element"]
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue