From 056b1538c0324b4fdabf7d58a62506add9d10ef1 Mon Sep 17 00:00:00 2001 From: sagudev <16504129+sagudev@users.noreply.github.com> Date: Sun, 27 Jul 2025 21:56:38 +0200 Subject: [PATCH] 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> --- Cargo.lock | 48 +- Cargo.toml | 3 +- components/canvas/Cargo.toml | 2 + components/canvas/canvas_paint_thread.rs | 78 +++ components/canvas/lib.rs | 4 +- components/canvas/vello_cpu_backend.rs | 452 ++++++++++++++++++ components/config/prefs.rs | 3 + components/constellation/Cargo.toml | 1 + components/servo/Cargo.toml | 1 + ports/servoshell/Cargo.toml | 1 + python/servo/try_parser.py | 13 + .../2d.composite.clip.clear.html.ini | 4 + .../2d.composite.clip.copy.html.ini | 4 + ...d.composite.clip.destination-atop.html.ini | 4 + .../2d.composite.clip.destination-in.html.ini | 4 + .../2d.composite.clip.source-in.html.ini | 4 + .../2d.composite.clip.source-out.html.ini | 4 + ....composite.uncovered.pattern.copy.html.ini | 4 + ...ncovered.pattern.destination-atop.html.ini | 4 + ....uncovered.pattern.destination-in.html.ini | 4 + ...osite.uncovered.pattern.source-in.html.ini | 4 + ...site.uncovered.pattern.source-out.html.ini | 4 + .../2d.clearRect.clip.html.ini | 4 + .../2d.clearRect.shadow.html.ini | 4 + .../2d.clearRect.zero.html.ini | 4 + ...d.gradient.interpolate.coloralpha.html.ini | 1 + .../2d.gradient.radial.cone.front.html.ini | 4 + .../2d.gradient.radial.cone.top.html.ini | 4 + .../2d.gradient.radial.inside2.html.ini | 4 + .../2d.gradient.radial.inside3.html.ini | 4 + .../2d.gradient.radial.outside1.html.ini | 4 + .../2d.gradient.radial.outside3.html.ini | 1 + .../line-styles/2d.line.cross.html.ini | 1 + .../path-objects/2d.path.arc.scale.1.html.ini | 1 + .../2d.path.rect.selfintersect.html.ini | 3 +- .../2d.path.stroke.scale2.html.ini | 1 + .../2d.imageData.put.alpha.html.ini | 4 + .../2d.imageData.put.unchanged.html.ini | 3 +- tests/wpt/vello_cpu_canvas_subsuite.json | 8 + 39 files changed, 694 insertions(+), 11 deletions(-) create mode 100644 components/canvas/vello_cpu_backend.rs create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.clear.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.copy.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-atop.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-in.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-in.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-out.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.copy.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.destination-atop.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.destination-in.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.source-in.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.source-out.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.clip.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.shadow.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.zero.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.cone.front.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.cone.top.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside2.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside3.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside1.html.ini create mode 100644 tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.alpha.html.ini create mode 100644 tests/wpt/vello_cpu_canvas_subsuite.json diff --git a/Cargo.lock b/Cargo.lock index eef58c1decb..2c6c718a122 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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]] diff --git a/Cargo.toml b/Cargo.toml index 699190c2b94..d52806e6f64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 1df66df404c..89a2a310ee9 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -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 } diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 09e34bd3ed7..3f96af28179 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -296,6 +296,8 @@ enum Canvas { Raqote(CanvasData), #[cfg(feature = "vello")] Vello(CanvasData), + #[cfg(feature = "vello_cpu")] + VelloCPU(CanvasData), } 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), } } } diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index 00f0b1d5a8e..bbdc8bbab67 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -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; diff --git a/components/canvas/vello_cpu_backend.rs b/components/canvas/vello_cpu_backend.rs new file mode 100644 index 00000000000..d2fc3f36bae --- /dev/null +++ b/components/canvas/vello_cpu_backend.rs @@ -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> = 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, +} + +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 { + Size2D::new(self.ctx.width(), self.ctx.height()).cast() + } +} + +impl GenericDrawTarget for VelloCPUDrawTarget { + type SourceSurface = Arc; + + fn new(size: Size2D) -> 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, transform: Transform2D) { + 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, + destination: Point2D, + ) { + let destination: kurbo::Point = destination.cast::().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) -> Self { + Self::new(size.cast()) + } + + fn draw_surface( + &mut self, + surface: Self::SourceSurface, + dest: Rect, + source: Rect, + filter: Filter, + composition_options: CompositionOptions, + transform: Transform2D, + ) { + 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, + _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, + ) { + 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, + start: Point2D, + style: FillOrStrokeStyle, + composition_options: CompositionOptions, + transform: Transform2D, + ) { + 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, + style: FillOrStrokeStyle, + composition_options: CompositionOptions, + transform: Transform2D, + ) { + 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 { + 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) { + 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) { + 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, + ) { + 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, + style: FillOrStrokeStyle, + line_options: LineOptions, + composition_options: CompositionOptions, + transform: Transform2D, + ) { + 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 { + Some(snapshot_as_pixmap(data)) + } +} + +fn snapshot_as_pixmap(data: Snapshot) -> Arc { + 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 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, + }) + }, + } + } +} diff --git a/components/config/prefs.rs b/components/config/prefs.rs index 0ce2d76eb5f..fe375b618db 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -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, diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml index 0a615f7479a..f7b6e73cb66 100644 --- a/components/constellation/Cargo.toml +++ b/components/constellation/Cargo.toml @@ -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" } diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index b7a07b58913..4033b1ad489 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -63,6 +63,7 @@ webgpu = [ "constellation_traits/webgpu", ] vello = ["constellation/vello"] +vello_cpu = ["constellation/vello_cpu"] [dependencies] background_hang_monitor = { path = "../background_hang_monitor" } diff --git a/ports/servoshell/Cargo.toml b/ports/servoshell/Cargo.toml index 9a6a42b7866..ff1f292d8ff 100644 --- a/ports/servoshell/Cargo.toml +++ b/ports/servoshell/Cargo.toml @@ -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 } diff --git a/python/servo/try_parser.py b/python/servo/try_parser.py index bbaf8fe2c6f..c05a6f6ed8f 100644 --- a/python/servo/try_parser.py +++ b/python/servo/try_parser.py @@ -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", diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.clear.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.clear.html.ini new file mode 100644 index 00000000000..2308d9a7c9a --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.clear.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.copy.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.copy.html.ini new file mode 100644 index 00000000000..8c00e22528e --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.copy.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-atop.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-atop.html.ini new file mode 100644 index 00000000000..765e7767ce4 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-atop.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-in.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-in.html.ini new file mode 100644 index 00000000000..9bfe54a0950 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.destination-in.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-in.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-in.html.ini new file mode 100644 index 00000000000..c1aaa465e69 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-in.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-out.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-out.html.ini new file mode 100644 index 00000000000..f17b0e37338 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.clip.source-out.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.copy.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.copy.html.ini new file mode 100644 index 00000000000..9866506fd48 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.copy.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.destination-atop.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.destination-atop.html.ini new file mode 100644 index 00000000000..dd893014410 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.destination-atop.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.destination-in.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.destination-in.html.ini new file mode 100644 index 00000000000..5fcaf9e164f --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.destination-in.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.source-in.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.source-in.html.ini new file mode 100644 index 00000000000..776c24cbc17 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.source-in.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.source-out.html.ini b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.source-out.html.ini new file mode 100644 index 00000000000..2dcf65aba03 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/compositing/2d.composite.uncovered.pattern.source-out.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.clip.html.ini b/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.clip.html.ini new file mode 100644 index 00000000000..cba3e72d6a1 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.clip.html.ini @@ -0,0 +1,4 @@ +[2d.clearRect.clip.html] + [clearRect is affected by clipping regions] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.shadow.html.ini b/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.shadow.html.ini new file mode 100644 index 00000000000..8e379529c99 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.shadow.html.ini @@ -0,0 +1,4 @@ +[2d.clearRect.shadow.html] + [clearRect does not draw shadows] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.zero.html.ini b/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.zero.html.ini new file mode 100644 index 00000000000..44b93d83457 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/drawing-rectangles-to-the-canvas/2d.clearRect.zero.html.ini @@ -0,0 +1,4 @@ +[2d.clearRect.zero.html] + [clearRect of zero pixels has no effect] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.interpolate.coloralpha.html.ini b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.interpolate.coloralpha.html.ini index 45482761b5d..9b8c5c40112 100644 --- a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.interpolate.coloralpha.html.ini +++ b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.interpolate.coloralpha.html.ini @@ -3,3 +3,4 @@ bug: https://github.com/linebender/vello/issues/1056 expected: if subsuite == "vello_canvas": FAIL + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.cone.front.html.ini b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.cone.front.html.ini new file mode 100644 index 00000000000..c36ccbdf128 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.cone.front.html.ini @@ -0,0 +1,4 @@ +[2d.gradient.radial.cone.front.html] + [Canvas test: 2d.gradient.radial.cone.front] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.cone.top.html.ini b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.cone.top.html.ini new file mode 100644 index 00000000000..96d94db7802 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.cone.top.html.ini @@ -0,0 +1,4 @@ +[2d.gradient.radial.cone.top.html] + [Canvas test: 2d.gradient.radial.cone.top] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside2.html.ini b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside2.html.ini new file mode 100644 index 00000000000..9ad9e462939 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside2.html.ini @@ -0,0 +1,4 @@ +[2d.gradient.radial.inside2.html] + [Canvas test: 2d.gradient.radial.inside2] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside3.html.ini b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside3.html.ini new file mode 100644 index 00000000000..7296e891037 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.inside3.html.ini @@ -0,0 +1,4 @@ +[2d.gradient.radial.inside3.html] + [Canvas test: 2d.gradient.radial.inside3] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside1.html.ini b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside1.html.ini new file mode 100644 index 00000000000..24714c7ae88 --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside1.html.ini @@ -0,0 +1,4 @@ +[2d.gradient.radial.outside1.html] + [Canvas test: 2d.gradient.radial.outside1] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside3.html.ini b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside3.html.ini index 4786f083031..9205277c4dc 100644 --- a/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside3.html.ini +++ b/tests/wpt/meta/html/canvas/element/fill-and-stroke-styles/2d.gradient.radial.outside3.html.ini @@ -2,3 +2,4 @@ [Canvas test: 2d.gradient.radial.outside3] expected: if subsuite == "": FAIL + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/line-styles/2d.line.cross.html.ini b/tests/wpt/meta/html/canvas/element/line-styles/2d.line.cross.html.ini index 9fc308d6baa..f838bfd07f1 100644 --- a/tests/wpt/meta/html/canvas/element/line-styles/2d.line.cross.html.ini +++ b/tests/wpt/meta/html/canvas/element/line-styles/2d.line.cross.html.ini @@ -3,3 +3,4 @@ bug: https://github.com/linebender/vello/issues/1063 expected: if subsuite == "vello_canvas": FAIL + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/path-objects/2d.path.arc.scale.1.html.ini b/tests/wpt/meta/html/canvas/element/path-objects/2d.path.arc.scale.1.html.ini index ed3b9b0e199..be3f56ccf83 100644 --- a/tests/wpt/meta/html/canvas/element/path-objects/2d.path.arc.scale.1.html.ini +++ b/tests/wpt/meta/html/canvas/element/path-objects/2d.path.arc.scale.1.html.ini @@ -2,3 +2,4 @@ [Non-uniformly scaled arcs are the right shape] expected: if subsuite == "vello_canvas": FAIL + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/path-objects/2d.path.rect.selfintersect.html.ini b/tests/wpt/meta/html/canvas/element/path-objects/2d.path.rect.selfintersect.html.ini index 5ac5b9c8bcc..b18bf07387f 100644 --- a/tests/wpt/meta/html/canvas/element/path-objects/2d.path.rect.selfintersect.html.ini +++ b/tests/wpt/meta/html/canvas/element/path-objects/2d.path.rect.selfintersect.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/path-objects/2d.path.stroke.scale2.html.ini b/tests/wpt/meta/html/canvas/element/path-objects/2d.path.stroke.scale2.html.ini index ecde0bfb25d..a19300881ff 100644 --- a/tests/wpt/meta/html/canvas/element/path-objects/2d.path.stroke.scale2.html.ini +++ b/tests/wpt/meta/html/canvas/element/path-objects/2d.path.stroke.scale2.html.ini @@ -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 diff --git a/tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.alpha.html.ini b/tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.alpha.html.ini new file mode 100644 index 00000000000..52a87f20e0c --- /dev/null +++ b/tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.alpha.html.ini @@ -0,0 +1,4 @@ +[2d.imageData.put.alpha.html] + [putImageData() puts non-solid image data correctly] + expected: + if subsuite == "vello_cpu_canvas": FAIL diff --git a/tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.unchanged.html.ini b/tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.unchanged.html.ini index bcc95019e98..124b05bd597 100644 --- a/tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.unchanged.html.ini +++ b/tests/wpt/meta/html/canvas/element/pixel-manipulation/2d.imageData.put.unchanged.html.ini @@ -1,4 +1,3 @@ [2d.imageData.put.unchanged.html] [putImageData(getImageData(...), ...) has no effect] - expected: - if subsuite == "": FAIL + expected: FAIL diff --git a/tests/wpt/vello_cpu_canvas_subsuite.json b/tests/wpt/vello_cpu_canvas_subsuite.json new file mode 100644 index 00000000000..a01f8c2b766 --- /dev/null +++ b/tests/wpt/vello_cpu_canvas_subsuite.json @@ -0,0 +1,8 @@ +{ + "vello_cpu_canvas": { + "config": { + "binary_args": ["--pref", "dom_canvas_vello_cpu_enabled"] + }, + "include": ["/html/canvas/element"] + } +}