canvas: Gate raqote backend behind feature (enabled for now) (#38312)

We want to eventually remove raqote backend, but for now we can gate it
behind a feature (still enabled by default in servoshell) like the rest
of backends. `dom_canvas_backend=auto` will select first available
backend. Builds on top of https://github.com/servo/servo/pull/38310 to
support cases where no backend is available.

Testing: It compiles with or without feature

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
sagudev 2025-07-28 13:54:40 +02:00 committed by GitHub
parent 9da4c74a60
commit a67998b520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 53 additions and 11 deletions

View file

@ -14,6 +14,7 @@ path = "lib.rs"
[features] [features]
vello = ["dep:vello", "dep:pollster", "dep:futures-intrusive", "dep:peniko"] vello = ["dep:vello", "dep:pollster", "dep:futures-intrusive", "dep:peniko"]
vello_cpu = ["dep:vello_cpu", "dep:peniko"] vello_cpu = ["dep:vello_cpu", "dep:peniko"]
raqote = ["dep:raqote", "dep:font-kit"]
[dependencies] [dependencies]
app_units = { workspace = true } app_units = { workspace = true }
@ -23,7 +24,7 @@ compositing_traits = { workspace = true }
crossbeam-channel = { workspace = true } crossbeam-channel = { workspace = true }
cssparser = { workspace = true } cssparser = { workspace = true }
euclid = { workspace = true } euclid = { workspace = true }
font-kit = "0.14" font-kit = { version = "0.14", optional = true }
fonts = { path = "../fonts" } fonts = { path = "../fonts" }
ipc-channel = { workspace = true } ipc-channel = { workspace = true }
kurbo = { workspace = true } kurbo = { workspace = true }
@ -32,7 +33,7 @@ net_traits = { workspace = true }
peniko = { workspace = true, optional = true } peniko = { workspace = true, optional = true }
pixels = { path = "../pixels" } pixels = { path = "../pixels" }
range = { path = "../range" } range = { path = "../range" }
raqote = "0.8.5" raqote = { version = "0.8.5", optional = true }
servo_arc = { workspace = true } servo_arc = { workspace = true }
stylo = { workspace = true } stylo = { workspace = true }
unicode-script = { workspace = true } unicode-script = { workspace = true }

View file

@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
#![allow(unreachable_patterns)]
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::collections::HashMap; use std::collections::HashMap;
@ -292,6 +293,7 @@ impl CanvasPaintThread {
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
enum Canvas { enum Canvas {
#[cfg(feature = "raqote")]
Raqote(CanvasData<raqote::DrawTarget>), Raqote(CanvasData<raqote::DrawTarget>),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Vello(CanvasData<crate::vello_backend::VelloDrawTarget>), Vello(CanvasData<crate::vello_backend::VelloDrawTarget>),
@ -309,19 +311,20 @@ impl Canvas {
.to_lowercase() .to_lowercase()
.as_str() .as_str()
{ {
#[cfg(feature = "raqote")]
"" | "auto" | "raqote" => Some(Self::Raqote(CanvasData::new(
size,
compositor_api,
font_context,
))),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
"vello" => Some(Self::Vello(CanvasData::new( "" | "auto" | "vello" => Some(Self::Vello(CanvasData::new(
size, size,
compositor_api, compositor_api,
font_context, font_context,
))), ))),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
"vello_cpu" => Some(Self::VelloCPU(CanvasData::new( "" | "auto" | "vello_cpu" => Some(Self::VelloCPU(CanvasData::new(
size,
compositor_api,
font_context,
))),
"" | "auto" | "raqote" => Some(Self::Raqote(CanvasData::new(
size, size,
compositor_api, compositor_api,
font_context, font_context,
@ -335,21 +338,25 @@ impl Canvas {
fn image_key(&self) -> ImageKey { fn image_key(&self) -> ImageKey {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.image_key(), Canvas::Raqote(canvas_data) => canvas_data.image_key(),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.image_key(), Canvas::Vello(canvas_data) => canvas_data.image_key(),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.image_key(), Canvas::VelloCPU(canvas_data) => canvas_data.image_key(),
_ => unreachable!(),
} }
} }
fn pop_clip(&mut self) { fn pop_clip(&mut self) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.pop_clip(), Canvas::Raqote(canvas_data) => canvas_data.pop_clip(),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.pop_clip(), Canvas::Vello(canvas_data) => canvas_data.pop_clip(),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.pop_clip(), Canvas::VelloCPU(canvas_data) => canvas_data.pop_clip(),
_ => unreachable!(),
} }
} }
@ -367,6 +374,7 @@ impl Canvas {
transform: Transform2D<f32>, transform: Transform2D<f32>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.fill_text( Canvas::Raqote(canvas_data) => canvas_data.fill_text(
text, text,
x, x,
@ -405,6 +413,7 @@ impl Canvas {
composition_options, composition_options,
transform, transform,
), ),
_ => unreachable!(),
} }
} }
@ -417,6 +426,7 @@ impl Canvas {
transform: Transform2D<f32>, transform: Transform2D<f32>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => { Canvas::Raqote(canvas_data) => {
canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform) canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform)
}, },
@ -428,6 +438,7 @@ impl Canvas {
Canvas::VelloCPU(canvas_data) => { Canvas::VelloCPU(canvas_data) => {
canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform) canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform)
}, },
_ => unreachable!(),
} }
} }
@ -441,6 +452,7 @@ impl Canvas {
transform: Transform2D<f32>, transform: Transform2D<f32>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.stroke_rect( Canvas::Raqote(canvas_data) => canvas_data.stroke_rect(
rect, rect,
style, style,
@ -467,6 +479,7 @@ impl Canvas {
composition_options, composition_options,
transform, transform,
), ),
_ => unreachable!(),
} }
} }
@ -480,6 +493,7 @@ impl Canvas {
transform: Transform2D<f32>, transform: Transform2D<f32>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.fill_path( Canvas::Raqote(canvas_data) => canvas_data.fill_path(
path, path,
fill_rule, fill_rule,
@ -506,6 +520,7 @@ impl Canvas {
composition_options, composition_options,
transform, transform,
), ),
_ => unreachable!(),
} }
} }
@ -519,6 +534,7 @@ impl Canvas {
transform: Transform2D<f32>, transform: Transform2D<f32>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.stroke_path( Canvas::Raqote(canvas_data) => canvas_data.stroke_path(
path, path,
style, style,
@ -545,16 +561,19 @@ impl Canvas {
composition_options, composition_options,
transform, transform,
), ),
_ => unreachable!(),
} }
} }
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) { fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.clear_rect(rect, transform), Canvas::Raqote(canvas_data) => canvas_data.clear_rect(rect, transform),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.clear_rect(rect, transform), Canvas::Vello(canvas_data) => canvas_data.clear_rect(rect, transform),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.clear_rect(rect, transform), Canvas::VelloCPU(canvas_data) => canvas_data.clear_rect(rect, transform),
_ => unreachable!(),
} }
} }
@ -569,6 +588,7 @@ impl Canvas {
transform: Transform2D<f32>, transform: Transform2D<f32>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.draw_image( Canvas::Raqote(canvas_data) => canvas_data.draw_image(
snapshot, snapshot,
dest_rect, dest_rect,
@ -598,66 +618,79 @@ impl Canvas {
composition_options, composition_options,
transform, transform,
), ),
_ => unreachable!(),
} }
} }
fn read_pixels(&mut self, read_rect: Option<Rect<u32>>) -> Snapshot { fn read_pixels(&mut self, read_rect: Option<Rect<u32>>) -> Snapshot {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.read_pixels(read_rect), Canvas::Raqote(canvas_data) => canvas_data.read_pixels(read_rect),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.read_pixels(read_rect), Canvas::Vello(canvas_data) => canvas_data.read_pixels(read_rect),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.read_pixels(read_rect), Canvas::VelloCPU(canvas_data) => canvas_data.read_pixels(read_rect),
_ => unreachable!(),
} }
} }
fn measure_text(&mut self, text: String, text_options: TextOptions) -> TextMetrics { fn measure_text(&mut self, text: String, text_options: TextOptions) -> TextMetrics {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.measure_text(text, text_options), Canvas::Raqote(canvas_data) => canvas_data.measure_text(text, text_options),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.measure_text(text, text_options), Canvas::Vello(canvas_data) => canvas_data.measure_text(text, text_options),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.measure_text(text, text_options), Canvas::VelloCPU(canvas_data) => canvas_data.measure_text(text, text_options),
_ => unreachable!(),
} }
} }
fn clip_path(&mut self, path: &Path, fill_rule: FillRule, transform: Transform2D<f32>) { fn clip_path(&mut self, path: &Path, fill_rule: FillRule, transform: Transform2D<f32>) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.clip_path(path, fill_rule, transform), Canvas::Raqote(canvas_data) => canvas_data.clip_path(path, fill_rule, transform),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.clip_path(path, fill_rule, transform), Canvas::Vello(canvas_data) => canvas_data.clip_path(path, fill_rule, transform),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.clip_path(path, fill_rule, transform), Canvas::VelloCPU(canvas_data) => canvas_data.clip_path(path, fill_rule, transform),
_ => unreachable!(),
} }
} }
fn put_image_data(&mut self, snapshot: Snapshot, rect: Rect<u32>) { fn put_image_data(&mut self, snapshot: Snapshot, rect: Rect<u32>) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.put_image_data(snapshot, rect), Canvas::Raqote(canvas_data) => canvas_data.put_image_data(snapshot, rect),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.put_image_data(snapshot, rect), Canvas::Vello(canvas_data) => canvas_data.put_image_data(snapshot, rect),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.put_image_data(snapshot, rect), Canvas::VelloCPU(canvas_data) => canvas_data.put_image_data(snapshot, rect),
_ => unreachable!(),
} }
} }
fn update_image_rendering(&mut self) { fn update_image_rendering(&mut self) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.update_image_rendering(), Canvas::Raqote(canvas_data) => canvas_data.update_image_rendering(),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.update_image_rendering(), Canvas::Vello(canvas_data) => canvas_data.update_image_rendering(),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.update_image_rendering(), Canvas::VelloCPU(canvas_data) => canvas_data.update_image_rendering(),
_ => unreachable!(),
} }
} }
fn recreate(&mut self, size: Option<Size2D<u64>>) { fn recreate(&mut self, size: Option<Size2D<u64>>) {
match self { match self {
#[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.recreate(size), Canvas::Raqote(canvas_data) => canvas_data.recreate(size),
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
Canvas::Vello(canvas_data) => canvas_data.recreate(size), Canvas::Vello(canvas_data) => canvas_data.recreate(size),
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
Canvas::VelloCPU(canvas_data) => canvas_data.recreate(size), Canvas::VelloCPU(canvas_data) => canvas_data.recreate(size),
_ => unreachable!(),
} }
} }
} }

View file

@ -5,11 +5,16 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
mod backend; mod backend;
#[cfg(feature = "raqote")]
mod raqote_backend;
#[cfg(any(feature = "vello", feature = "vello_cpu"))] #[cfg(any(feature = "vello", feature = "vello_cpu"))]
mod peniko_conversions; mod peniko_conversions;
mod raqote_backend;
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
mod vello_backend; mod vello_backend;
#[cfg(feature = "vello_cpu")] #[cfg(feature = "vello_cpu")]
mod vello_cpu_backend; mod vello_cpu_backend;

View file

@ -18,6 +18,7 @@ tracing = ["dep:tracing"]
webgpu = ["script_traits/webgpu"] webgpu = ["script_traits/webgpu"]
vello = ["canvas/vello"] vello = ["canvas/vello"]
vello_cpu = ["canvas/vello_cpu"] vello_cpu = ["canvas/vello_cpu"]
raqote = ["canvas/raqote"]
[dependencies] [dependencies]
background_hang_monitor = { path = "../background_hang_monitor" } background_hang_monitor = { path = "../background_hang_monitor" }

View file

@ -21,7 +21,7 @@ bluetooth = [
"script/bluetooth", "script/bluetooth",
"script_traits/bluetooth", "script_traits/bluetooth",
] ]
default = ["clipboard"] default = ["clipboard", "raqote"]
clipboard = ["dep:arboard"] clipboard = ["dep:arboard"]
crown = ["script/crown"] crown = ["script/crown"]
debugmozjs = ["script/debugmozjs"] debugmozjs = ["script/debugmozjs"]
@ -64,6 +64,7 @@ webgpu = [
] ]
vello = ["constellation/vello"] vello = ["constellation/vello"]
vello_cpu = ["constellation/vello_cpu"] vello_cpu = ["constellation/vello_cpu"]
raqote = ["constellation/raqote"]
[dependencies] [dependencies]
background_hang_monitor = { path = "../background_hang_monitor" } background_hang_monitor = { path = "../background_hang_monitor" }

View file

@ -54,6 +54,7 @@ webgpu = ["libservo/webgpu"]
webxr = ["libservo/webxr"] webxr = ["libservo/webxr"]
vello = ["libservo/vello"] vello = ["libservo/vello"]
vello_cpu = ["libservo/vello_cpu"] vello_cpu = ["libservo/vello_cpu"]
raqote = ["libservo/raqote"]
[dependencies] [dependencies]
cfg-if = { workspace = true } cfg-if = { workspace = true }