mirror of
https://github.com/servo/servo.git
synced 2025-09-04 12:08:21 +01:00
canvas: Remove the raqote
backend (#38962)
In general, `raqote` is essentially umaintained and has issues with quality (for instance text rendering has lots of issues) and removing it finally lets us remove our dependency on `font-kit`. Although, `vello_cpu` performance is not yet equal to raqote, rendering quality is a lot better. It's expected that `vello` and `vello_cpu` performance will keep improving. Testing: This is covered by existing WPT tests. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
0089e652c5
commit
de69040e47
13 changed files with 5 additions and 982 deletions
99
Cargo.lock
generated
99
Cargo.lock
generated
|
@ -1143,7 +1143,6 @@ dependencies = [
|
|||
"crossbeam-channel",
|
||||
"cssparser",
|
||||
"euclid",
|
||||
"font-kit",
|
||||
"fonts",
|
||||
"futures-intrusive",
|
||||
"ipc-channel",
|
||||
|
@ -1154,7 +1153,6 @@ dependencies = [
|
|||
"pixels",
|
||||
"pollster",
|
||||
"range",
|
||||
"raqote",
|
||||
"servo-tracing",
|
||||
"servo_arc",
|
||||
"servo_config",
|
||||
|
@ -2677,12 +2675,6 @@ version = "0.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
||||
|
||||
[[package]]
|
||||
name = "float-ord"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -2695,31 +2687,6 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "font-kit"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c7e611d49285d4c4b2e1727b72cf05353558885cc5252f93707b845dfcaf3d3"
|
||||
dependencies = [
|
||||
"bitflags 2.9.3",
|
||||
"byteorder",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics",
|
||||
"core-text",
|
||||
"dirs",
|
||||
"dwrote",
|
||||
"float-ord",
|
||||
"freetype-sys",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"pathfinder_geometry",
|
||||
"pathfinder_simd",
|
||||
"walkdir",
|
||||
"winapi",
|
||||
"yeslogic-fontconfig-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "font-types"
|
||||
version = "0.9.0"
|
||||
|
@ -5166,17 +5133,6 @@ dependencies = [
|
|||
"imgref",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lyon_geom"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8af69edc087272df438b3ee436c4bb6d7c04aa8af665cfd398feae627dbd8570"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"euclid",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mac"
|
||||
version = "0.1.1"
|
||||
|
@ -6402,25 +6358,6 @@ version = "1.0.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_geometry"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pathfinder_simd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_simd"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf9027960355bf3afff9841918474a81a5f972ac6d226d518060bba758b5ad57"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peek-poke"
|
||||
version = "0.3.0"
|
||||
|
@ -6980,21 +6917,6 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
|
||||
|
||||
[[package]]
|
||||
name = "raqote"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "324990858d2a5df9ccd30b2e8b474030bd503297378a3fc0944c37af00eb8903"
|
||||
dependencies = [
|
||||
"euclid",
|
||||
"font-kit",
|
||||
"lyon_geom",
|
||||
"pathfinder_geometry",
|
||||
"png",
|
||||
"sw-composite",
|
||||
"typed-arena",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rav1e"
|
||||
version = "0.7.1"
|
||||
|
@ -7260,15 +7182,6 @@ version = "2.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
|
@ -8623,12 +8536,6 @@ dependencies = [
|
|||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sw-composite"
|
||||
version = "0.7.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ac8fb7895b4afa060ad731a32860db8755da3449a47e796d5ecf758db2671d4"
|
||||
|
||||
[[package]]
|
||||
name = "swapper"
|
||||
version = "0.1.0"
|
||||
|
@ -9238,12 +9145,6 @@ dependencies = [
|
|||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
version = "1.0.3"
|
||||
|
|
|
@ -14,7 +14,6 @@ path = "lib.rs"
|
|||
[features]
|
||||
vello = ["dep:vello", "dep:pollster", "dep:futures-intrusive", "dep:peniko"]
|
||||
vello_cpu = ["dep:vello_cpu", "dep:peniko"]
|
||||
raqote = ["dep:raqote", "dep:font-kit"]
|
||||
tracing = ["dep:tracing"]
|
||||
|
||||
[dependencies]
|
||||
|
@ -25,7 +24,6 @@ compositing_traits = { workspace = true }
|
|||
crossbeam-channel = { workspace = true }
|
||||
cssparser = { workspace = true }
|
||||
euclid = { workspace = true }
|
||||
font-kit = { version = "0.14", optional = true }
|
||||
fonts = { path = "../fonts" }
|
||||
ipc-channel = { workspace = true }
|
||||
kurbo = { workspace = true }
|
||||
|
@ -34,7 +32,6 @@ net_traits = { workspace = true }
|
|||
peniko = { workspace = true, optional = true }
|
||||
pixels = { path = "../pixels" }
|
||||
range = { path = "../range" }
|
||||
raqote = { version = "0.8.5", optional = true }
|
||||
servo_arc = { workspace = true }
|
||||
stylo = { workspace = true }
|
||||
unicode-script = { workspace = true }
|
||||
|
|
|
@ -12,8 +12,8 @@ use webrender_api::ImageDescriptor;
|
|||
|
||||
use crate::canvas_data::{Filter, TextRun};
|
||||
|
||||
// This defines required methods for a DrawTarget (currently only implemented for raqote). The
|
||||
// prototypes are derived from the now-removed Azure backend's methods.
|
||||
// This defines required methods for a DrawTarget. The prototypes are derived from the now-removed
|
||||
// Azure backend's methods.
|
||||
pub(crate) trait GenericDrawTarget {
|
||||
type SourceSurface;
|
||||
|
||||
|
|
|
@ -169,7 +169,6 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
|
|||
Size2D::new(dest_rect.size.width as f32, dest_rect.size.height as f32),
|
||||
);
|
||||
|
||||
// TODO(pylbrecht) pass another closure for raqote
|
||||
self.draw_with_shadow(
|
||||
&rect,
|
||||
shadow_options,
|
||||
|
@ -411,8 +410,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
|
|||
let mut current_text_run_start_index = 0;
|
||||
|
||||
for (index, character) in text.char_indices() {
|
||||
// TODO: This should ultimately handle emoji variation selectors, but raqote does not yet
|
||||
// have support for color glyphs.
|
||||
// TODO: This should ultimately handle emoji variation selectors.
|
||||
let script = Script::from(character);
|
||||
let font = font_group.find_by_codepoint(&self.font_context, character, None, None);
|
||||
|
||||
|
|
|
@ -295,8 +295,6 @@ impl CanvasPaintThread {
|
|||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum Canvas {
|
||||
#[cfg(feature = "raqote")]
|
||||
Raqote(CanvasData<raqote::DrawTarget>),
|
||||
#[cfg(feature = "vello")]
|
||||
Vello(CanvasData<crate::vello_backend::VelloDrawTarget>),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
|
@ -319,12 +317,6 @@ impl Canvas {
|
|||
compositor_api,
|
||||
font_context,
|
||||
))),
|
||||
#[cfg(feature = "raqote")]
|
||||
"" | "auto" | "raqote" => Some(Self::Raqote(CanvasData::new(
|
||||
size,
|
||||
compositor_api,
|
||||
font_context,
|
||||
))),
|
||||
#[cfg(feature = "vello")]
|
||||
"" | "auto" | "vello" => Some(Self::Vello(CanvasData::new(
|
||||
size,
|
||||
|
@ -340,8 +332,6 @@ impl Canvas {
|
|||
|
||||
fn image_key(&self) -> ImageKey {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => canvas_data.image_key(),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.image_key(),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
|
@ -351,8 +341,6 @@ impl Canvas {
|
|||
|
||||
fn pop_clips(&mut self, clips: usize) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => canvas_data.pop_clips(clips),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.pop_clips(clips),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
|
@ -375,19 +363,6 @@ impl Canvas {
|
|||
transform: Transform2D<f64>,
|
||||
) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => canvas_data.fill_text(
|
||||
text,
|
||||
x,
|
||||
y,
|
||||
max_width,
|
||||
is_rtl,
|
||||
style,
|
||||
text_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.fill_text(
|
||||
text,
|
||||
|
@ -426,10 +401,6 @@ impl Canvas {
|
|||
transform: Transform2D<f64>,
|
||||
) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => {
|
||||
canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform)
|
||||
},
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => {
|
||||
canvas_data.fill_rect(rect, style, shadow_options, composition_options, transform)
|
||||
|
@ -451,15 +422,6 @@ impl Canvas {
|
|||
transform: Transform2D<f64>,
|
||||
) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => canvas_data.stroke_rect(
|
||||
rect,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.stroke_rect(
|
||||
rect,
|
||||
|
@ -491,15 +453,6 @@ impl Canvas {
|
|||
transform: Transform2D<f64>,
|
||||
) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => canvas_data.fill_path(
|
||||
path,
|
||||
fill_rule,
|
||||
style,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.fill_path(
|
||||
path,
|
||||
|
@ -531,15 +484,6 @@ impl Canvas {
|
|||
transform: Transform2D<f64>,
|
||||
) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => canvas_data.stroke_path(
|
||||
path,
|
||||
style,
|
||||
line_options,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.stroke_path(
|
||||
path,
|
||||
|
@ -563,8 +507,6 @@ impl Canvas {
|
|||
|
||||
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
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")]
|
||||
|
@ -584,16 +526,6 @@ impl Canvas {
|
|||
transform: Transform2D<f64>,
|
||||
) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => canvas_data.draw_image(
|
||||
snapshot,
|
||||
dest_rect,
|
||||
source_rect,
|
||||
smoothing_enabled,
|
||||
shadow_options,
|
||||
composition_options,
|
||||
transform,
|
||||
),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.draw_image(
|
||||
snapshot,
|
||||
|
@ -619,8 +551,6 @@ impl Canvas {
|
|||
|
||||
fn read_pixels(&mut self, read_rect: Option<Rect<u32>>) -> Snapshot {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
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")]
|
||||
|
@ -630,8 +560,6 @@ impl Canvas {
|
|||
|
||||
fn measure_text(&mut self, text: String, text_options: TextOptions) -> TextMetrics {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
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")]
|
||||
|
@ -641,8 +569,6 @@ impl Canvas {
|
|||
|
||||
fn clip_path(&mut self, path: &Path, fill_rule: FillRule, transform: Transform2D<f64>) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
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")]
|
||||
|
@ -652,8 +578,6 @@ impl Canvas {
|
|||
|
||||
fn put_image_data(&mut self, snapshot: Snapshot, rect: Rect<u32>) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
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")]
|
||||
|
@ -663,8 +587,6 @@ impl Canvas {
|
|||
|
||||
fn update_image_rendering(&mut self) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
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")]
|
||||
|
@ -674,8 +596,6 @@ impl Canvas {
|
|||
|
||||
fn recreate(&mut self, size: Option<Size2D<u64>>) {
|
||||
match self {
|
||||
#[cfg(feature = "raqote")]
|
||||
Canvas::Raqote(canvas_data) => canvas_data.recreate(size),
|
||||
#[cfg(feature = "vello")]
|
||||
Canvas::Vello(canvas_data) => canvas_data.recreate(size),
|
||||
#[cfg(feature = "vello_cpu")]
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
|
||||
mod backend;
|
||||
|
||||
#[cfg(feature = "raqote")]
|
||||
mod raqote_backend;
|
||||
|
||||
#[cfg(any(feature = "vello", feature = "vello_cpu"))]
|
||||
mod peniko_conversions;
|
||||
|
||||
|
|
|
@ -1,780 +0,0 @@
|
|||
/* 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::{Cell, RefCell};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use canvas_traits::canvas::*;
|
||||
use compositing_traits::SerializableImageData;
|
||||
use cssparser::color::clamp_unit_f32;
|
||||
use euclid::default::{Point2D, Rect, Size2D, Transform2D};
|
||||
use font_kit::font::Font;
|
||||
use fonts::{ByteIndex, FontIdentifier, FontTemplateRefMethods};
|
||||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use log::warn;
|
||||
use pixels::{Snapshot, SnapshotAlphaMode, SnapshotPixelFormat};
|
||||
use range::Range;
|
||||
use raqote::{DrawOptions, PathBuilder, StrokeStyle};
|
||||
use style::color::AbsoluteColor;
|
||||
use webrender_api::{ImageDescriptor, ImageDescriptorFlags, ImageFormat};
|
||||
|
||||
use crate::backend::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, Font>> = RefCell::default();
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Pattern {
|
||||
// argb
|
||||
Color(u8, u8, u8, u8),
|
||||
LinearGradient(LinearGradientPattern),
|
||||
RadialGradient(RadialGradientPattern),
|
||||
Surface(SurfacePattern),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LinearGradientPattern {
|
||||
gradient: raqote::Gradient,
|
||||
start: Point2D<f32>,
|
||||
end: Point2D<f32>,
|
||||
}
|
||||
|
||||
impl LinearGradientPattern {
|
||||
fn new(start: Point2D<f32>, end: Point2D<f32>, stops: Vec<raqote::GradientStop>) -> Self {
|
||||
LinearGradientPattern {
|
||||
gradient: raqote::Gradient { stops },
|
||||
start,
|
||||
end,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RadialGradientPattern {
|
||||
gradient: raqote::Gradient,
|
||||
center1: Point2D<f32>,
|
||||
radius1: f32,
|
||||
center2: Point2D<f32>,
|
||||
radius2: f32,
|
||||
}
|
||||
|
||||
impl RadialGradientPattern {
|
||||
fn new(
|
||||
center1: Point2D<f32>,
|
||||
radius1: f32,
|
||||
center2: Point2D<f32>,
|
||||
radius2: f32,
|
||||
stops: Vec<raqote::GradientStop>,
|
||||
) -> Self {
|
||||
RadialGradientPattern {
|
||||
gradient: raqote::Gradient { stops },
|
||||
center1,
|
||||
radius1,
|
||||
center2,
|
||||
radius2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SurfacePattern {
|
||||
image: Snapshot,
|
||||
filter: raqote::FilterMode,
|
||||
extend: raqote::ExtendMode,
|
||||
transform: Transform2D<f32>,
|
||||
}
|
||||
|
||||
impl SurfacePattern {
|
||||
fn new(
|
||||
image: Snapshot,
|
||||
filter: raqote::FilterMode,
|
||||
repeat: Repetition,
|
||||
transform: Transform2D<f32>,
|
||||
) -> Self {
|
||||
let extend = match repeat {
|
||||
Repetition::NoRepeat => raqote::ExtendMode::Pad,
|
||||
Repetition::RepeatX | Repetition::RepeatY | Repetition::Repeat => {
|
||||
raqote::ExtendMode::Repeat
|
||||
},
|
||||
};
|
||||
SurfacePattern {
|
||||
image,
|
||||
filter,
|
||||
extend,
|
||||
transform,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Repetition {
|
||||
Repeat,
|
||||
RepeatX,
|
||||
RepeatY,
|
||||
NoRepeat,
|
||||
}
|
||||
|
||||
impl Repetition {
|
||||
fn from_xy(repeat_x: bool, repeat_y: bool) -> Self {
|
||||
if repeat_x && repeat_y {
|
||||
Repetition::Repeat
|
||||
} else if repeat_x {
|
||||
Repetition::RepeatX
|
||||
} else if repeat_y {
|
||||
Repetition::RepeatY
|
||||
} else {
|
||||
Repetition::NoRepeat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source(pattern: &Pattern) -> raqote::Source<'_> {
|
||||
match pattern {
|
||||
Pattern::Color(a, r, g, b) => raqote::Source::Solid(
|
||||
raqote::SolidSource::from_unpremultiplied_argb(*a, *r, *g, *b),
|
||||
),
|
||||
Pattern::LinearGradient(pattern) => raqote::Source::new_linear_gradient(
|
||||
pattern.gradient.clone(),
|
||||
pattern.start,
|
||||
pattern.end,
|
||||
raqote::Spread::Pad,
|
||||
),
|
||||
Pattern::RadialGradient(pattern) => raqote::Source::new_two_circle_radial_gradient(
|
||||
pattern.gradient.clone(),
|
||||
pattern.center1,
|
||||
pattern.radius1,
|
||||
pattern.center2,
|
||||
pattern.radius2,
|
||||
raqote::Spread::Pad,
|
||||
),
|
||||
Pattern::Surface(pattern) => raqote::Source::Image(
|
||||
raqote::Image {
|
||||
width: pattern.image.size().width as i32,
|
||||
height: pattern.image.size().height as i32,
|
||||
data: bytemuck::cast_slice(pattern.image.as_raw_bytes()),
|
||||
},
|
||||
pattern.extend,
|
||||
pattern.filter,
|
||||
pattern.transform,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_gradient_stops(gradient_stops: Vec<CanvasGradientStop>) -> Vec<raqote::GradientStop> {
|
||||
let mut stops = gradient_stops
|
||||
.into_iter()
|
||||
.map(|item| item.to_raqote())
|
||||
.collect::<Vec<raqote::GradientStop>>();
|
||||
// https://www.w3.org/html/test/results/2dcontext/annotated-spec/canvas.html#testrefs.2d.gradient.interpolate.overlap
|
||||
stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
|
||||
stops
|
||||
}
|
||||
|
||||
impl GenericDrawTarget for raqote::DrawTarget {
|
||||
type SourceSurface = Vec<u32>; // TODO: See if we can avoid the alloc (probably?)
|
||||
|
||||
fn new(size: Size2D<u32>) -> Self {
|
||||
raqote::DrawTarget::new(size.width as i32, size.height as i32)
|
||||
}
|
||||
|
||||
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) {
|
||||
<Self as GenericDrawTarget>::fill_rect(
|
||||
self,
|
||||
rect,
|
||||
FillOrStrokeStyle::Color(AbsoluteColor::TRANSPARENT_BLACK),
|
||||
CompositionOptions {
|
||||
alpha: 1.0,
|
||||
composition_operation: CompositionOrBlending::Composition(CompositionStyle::Clear),
|
||||
},
|
||||
transform,
|
||||
);
|
||||
}
|
||||
fn copy_surface(
|
||||
&mut self,
|
||||
surface: Self::SourceSurface,
|
||||
source: Rect<i32>,
|
||||
destination: Point2D<i32>,
|
||||
) {
|
||||
let dt = raqote::DrawTarget::from_vec(source.size.width, source.size.height, surface);
|
||||
raqote::DrawTarget::copy_surface(self, &dt, source.to_box2d(), destination);
|
||||
}
|
||||
|
||||
fn create_similar_draw_target(&self, size: &Size2D<i32>) -> Self {
|
||||
raqote::DrawTarget::new(size.width, size.height)
|
||||
}
|
||||
fn create_source_surface_from_data(&self, data: Snapshot) -> Option<Self::SourceSurface> {
|
||||
Some(
|
||||
bytemuck::try_cast_vec(
|
||||
data.to_vec(
|
||||
Some(SnapshotAlphaMode::Transparent {
|
||||
premultiplied: true,
|
||||
}),
|
||||
Some(SnapshotPixelFormat::BGRA),
|
||||
)
|
||||
.0,
|
||||
)
|
||||
.unwrap_or_else(|(_, surface)| bytemuck::pod_collect_to_vec(&surface)),
|
||||
)
|
||||
}
|
||||
fn draw_surface(
|
||||
&mut self,
|
||||
surface: Self::SourceSurface,
|
||||
dest: Rect<f64>,
|
||||
src: Rect<f64>,
|
||||
filter: Filter,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f64>,
|
||||
) {
|
||||
let paint_transform =
|
||||
raqote::Transform::translation(-dest.origin.x as f32, -dest.origin.y as f32)
|
||||
.then_scale(
|
||||
src.size.width as f32 / dest.size.width as f32,
|
||||
src.size.height as f32 / dest.size.height as f32,
|
||||
);
|
||||
|
||||
self.set_transform(&transform.cast());
|
||||
let dest = dest.cast();
|
||||
let mut pb = raqote::PathBuilder::new();
|
||||
pb.rect(
|
||||
dest.origin.x,
|
||||
dest.origin.y,
|
||||
dest.size.width,
|
||||
dest.size.height,
|
||||
);
|
||||
let size = src.size.cast();
|
||||
fill_draw_target(
|
||||
self,
|
||||
draw_options(composition_options),
|
||||
&raqote::Source::Image(
|
||||
raqote::Image {
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
data: &surface,
|
||||
},
|
||||
raqote::ExtendMode::Pad,
|
||||
filter.to_raqote(),
|
||||
paint_transform,
|
||||
),
|
||||
pb.finish(),
|
||||
);
|
||||
}
|
||||
fn draw_surface_with_shadow(
|
||||
&self,
|
||||
_surface: Self::SourceSurface,
|
||||
_dest: &Point2D<f32>,
|
||||
_shadow_options: ShadowOptions,
|
||||
_composition_options: CompositionOptions,
|
||||
) {
|
||||
warn!("no support for drawing shadows");
|
||||
}
|
||||
fn fill(
|
||||
&mut self,
|
||||
path: &canvas_traits::canvas::Path,
|
||||
fill_rule: FillRule,
|
||||
style: FillOrStrokeStyle,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f64>,
|
||||
) {
|
||||
self.set_transform(&transform.cast());
|
||||
let draw_options = draw_options(composition_options);
|
||||
let pattern = style.to_raqote_pattern();
|
||||
let mut path = to_path(path);
|
||||
path.winding = match fill_rule {
|
||||
FillRule::Nonzero => raqote::Winding::NonZero,
|
||||
FillRule::Evenodd => raqote::Winding::EvenOdd,
|
||||
};
|
||||
fill_draw_target(self, draw_options, &source(&pattern), path);
|
||||
}
|
||||
|
||||
fn fill_text(
|
||||
&mut self,
|
||||
text_runs: Vec<TextRun>,
|
||||
start: Point2D<f32>,
|
||||
style: FillOrStrokeStyle,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f64>,
|
||||
) {
|
||||
self.set_transform(&transform.cast());
|
||||
let draw_options = draw_options(composition_options);
|
||||
let pattern = style.to_raqote_pattern();
|
||||
let mut advance = 0.;
|
||||
for run in text_runs.iter() {
|
||||
let mut positions = Vec::new();
|
||||
let glyphs = &run.glyphs;
|
||||
let ids: Vec<_> = glyphs
|
||||
.iter_glyphs_for_byte_range(&Range::new(ByteIndex(0), glyphs.len()))
|
||||
.map(|glyph| {
|
||||
let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
|
||||
positions.push(Point2D::new(
|
||||
advance + start.x + glyph_offset.x.to_f32_px(),
|
||||
start.y + glyph_offset.y.to_f32_px(),
|
||||
));
|
||||
advance += glyph.advance().to_f32_px();
|
||||
glyph.id()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// TODO: raqote uses font-kit to rasterize glyphs, but font-kit fails an assertion when
|
||||
// using color bitmap fonts in the FreeType backend. For now, simply do not render these
|
||||
// type of fonts.
|
||||
if run.font.has_color_bitmap_or_colr_table() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let template = &run.font.template;
|
||||
|
||||
SHARED_FONT_CACHE.with(|font_cache| {
|
||||
let identifier = template.identifier();
|
||||
if !font_cache.borrow().contains_key(&identifier) {
|
||||
let Ok(font_data_and_index) = run.font.font_data_and_index() else {
|
||||
return;
|
||||
};
|
||||
let data = std::sync::Arc::new(font_data_and_index.data.as_ref().to_vec());
|
||||
let Ok(font) = Font::from_bytes(data, font_data_and_index.index) else {
|
||||
return;
|
||||
};
|
||||
font_cache.borrow_mut().insert(identifier.clone(), font);
|
||||
}
|
||||
|
||||
let font_cache = font_cache.borrow();
|
||||
let Some(font) = font_cache.get(&identifier) else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.draw_glyphs(
|
||||
font,
|
||||
run.font.descriptor.pt_size.to_f32_px(),
|
||||
&ids,
|
||||
&positions,
|
||||
&source(&pattern),
|
||||
&draw_options,
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_rect(
|
||||
&mut self,
|
||||
rect: &Rect<f32>,
|
||||
style: FillOrStrokeStyle,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f64>,
|
||||
) {
|
||||
let rect = rect.cast();
|
||||
let mut pb = canvas_traits::canvas::Path::new();
|
||||
pb.rect(
|
||||
rect.origin.x,
|
||||
rect.origin.y,
|
||||
rect.size.width,
|
||||
rect.size.height,
|
||||
);
|
||||
|
||||
<Self as GenericDrawTarget>::fill(
|
||||
self,
|
||||
&pb,
|
||||
FillRule::Nonzero,
|
||||
style,
|
||||
composition_options,
|
||||
transform,
|
||||
);
|
||||
}
|
||||
fn get_size(&self) -> Size2D<i32> {
|
||||
Size2D::new(self.width(), self.height())
|
||||
}
|
||||
fn pop_clip(&mut self) {
|
||||
self.pop_clip();
|
||||
}
|
||||
fn push_clip(
|
||||
&mut self,
|
||||
path: &canvas_traits::canvas::Path,
|
||||
fill_rule: FillRule,
|
||||
transform: Transform2D<f64>,
|
||||
) {
|
||||
self.set_transform(&transform.cast());
|
||||
let mut path = to_path(path);
|
||||
path.winding = match fill_rule {
|
||||
FillRule::Nonzero => raqote::Winding::NonZero,
|
||||
FillRule::Evenodd => raqote::Winding::EvenOdd,
|
||||
};
|
||||
self.push_clip(&path);
|
||||
}
|
||||
fn push_clip_rect(&mut self, rect: &Rect<i32>) {
|
||||
self.push_clip_rect(rect.to_box2d());
|
||||
}
|
||||
fn surface(&mut self) -> Self::SourceSurface {
|
||||
self.get_data().to_vec()
|
||||
}
|
||||
fn stroke(
|
||||
&mut self,
|
||||
path: &canvas_traits::canvas::Path,
|
||||
style: FillOrStrokeStyle,
|
||||
line_options: LineOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f64>,
|
||||
) {
|
||||
let pattern = style.to_raqote_pattern();
|
||||
let options = draw_options(composition_options);
|
||||
self.set_transform(&transform.cast());
|
||||
self.stroke(
|
||||
&to_path(path),
|
||||
&source(&pattern),
|
||||
&line_options.to_raqote_style(),
|
||||
&options,
|
||||
);
|
||||
}
|
||||
fn stroke_rect(
|
||||
&mut self,
|
||||
rect: &Rect<f32>,
|
||||
style: FillOrStrokeStyle,
|
||||
line_options: LineOptions,
|
||||
composition_options: CompositionOptions,
|
||||
transform: Transform2D<f64>,
|
||||
) {
|
||||
self.set_transform(&transform.cast());
|
||||
let pattern = style.to_raqote_pattern();
|
||||
let options = draw_options(composition_options);
|
||||
let mut pb = raqote::PathBuilder::new();
|
||||
pb.rect(
|
||||
rect.origin.x,
|
||||
rect.origin.y,
|
||||
rect.size.width,
|
||||
rect.size.height,
|
||||
);
|
||||
|
||||
self.stroke(
|
||||
&pb.finish(),
|
||||
&source(&pattern),
|
||||
&line_options.to_raqote_style(),
|
||||
&options,
|
||||
);
|
||||
}
|
||||
|
||||
fn image_descriptor_and_serializable_data(
|
||||
&mut self,
|
||||
) -> (
|
||||
webrender_api::ImageDescriptor,
|
||||
compositing_traits::SerializableImageData,
|
||||
) {
|
||||
let descriptor = ImageDescriptor {
|
||||
size: self.get_size().cast_unit(),
|
||||
stride: None,
|
||||
format: ImageFormat::BGRA8,
|
||||
offset: 0,
|
||||
flags: ImageDescriptorFlags::empty(),
|
||||
};
|
||||
let data = SerializableImageData::Raw(IpcSharedMemory::from_bytes(self.get_data_u8()));
|
||||
(descriptor, data)
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> Snapshot {
|
||||
Snapshot::from_vec(
|
||||
self.get_size().cast(),
|
||||
SnapshotPixelFormat::BGRA,
|
||||
SnapshotAlphaMode::Transparent {
|
||||
premultiplied: true,
|
||||
},
|
||||
self.get_data_u8().to_vec(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_draw_target(
|
||||
draw_target: &mut raqote::DrawTarget,
|
||||
draw_options: DrawOptions,
|
||||
source: &raqote::Source<'_>,
|
||||
path: raqote::Path,
|
||||
) {
|
||||
match draw_options.blend_mode {
|
||||
raqote::BlendMode::Src => {
|
||||
draw_target.clear(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0));
|
||||
draw_target.fill(&path, source, &draw_options);
|
||||
},
|
||||
raqote::BlendMode::Clear |
|
||||
raqote::BlendMode::SrcAtop |
|
||||
raqote::BlendMode::DstOut |
|
||||
raqote::BlendMode::Add |
|
||||
raqote::BlendMode::Xor |
|
||||
raqote::BlendMode::DstOver |
|
||||
raqote::BlendMode::SrcOver => {
|
||||
draw_target.fill(&path, source, &draw_options);
|
||||
},
|
||||
raqote::BlendMode::SrcIn |
|
||||
raqote::BlendMode::SrcOut |
|
||||
raqote::BlendMode::DstIn |
|
||||
raqote::BlendMode::DstAtop => {
|
||||
let mut options = draw_options;
|
||||
draw_target.push_layer_with_blend(1., options.blend_mode);
|
||||
options.blend_mode = raqote::BlendMode::SrcOver;
|
||||
draw_target.fill(&path, source, &options);
|
||||
draw_target.pop_layer();
|
||||
},
|
||||
_ => warn!("unrecognized blend mode: {:?}", draw_options.blend_mode),
|
||||
}
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
fn to_raqote(self) -> raqote::FilterMode {
|
||||
match self {
|
||||
Filter::Bilinear => raqote::FilterMode::Bilinear,
|
||||
Filter::Nearest => raqote::FilterMode::Nearest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Path(Cell<raqote::PathBuilder>);
|
||||
|
||||
impl From<raqote::PathBuilder> for Path {
|
||||
fn from(path_builder: raqote::PathBuilder) -> Self {
|
||||
Self(Cell::new(path_builder))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Path> for raqote::Path {
|
||||
fn from(path: &Path) -> Self {
|
||||
path.clone().0.into_inner().finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Path {
|
||||
fn clone(&self) -> Self {
|
||||
let path_builder = self.0.replace(raqote::PathBuilder::new());
|
||||
let path = path_builder.finish();
|
||||
self.0.set(path.clone().into());
|
||||
Self(Cell::new(path.into()))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToRaqoteStyle {
|
||||
type Target;
|
||||
|
||||
fn to_raqote_style(self) -> Self::Target;
|
||||
}
|
||||
|
||||
impl ToRaqoteStyle for LineOptions {
|
||||
type Target = StrokeStyle;
|
||||
|
||||
fn to_raqote_style(self) -> Self::Target {
|
||||
let LineOptions {
|
||||
width,
|
||||
cap_style,
|
||||
join_style,
|
||||
miter_limit,
|
||||
dash,
|
||||
dash_offset,
|
||||
} = self;
|
||||
StrokeStyle {
|
||||
width: width as f32,
|
||||
cap: cap_style.to_raqote_style(),
|
||||
join: join_style.to_raqote_style(),
|
||||
miter_limit: miter_limit as f32,
|
||||
dash_array: dash,
|
||||
dash_offset: dash_offset as f32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRaqoteStyle for LineJoinStyle {
|
||||
type Target = raqote::LineJoin;
|
||||
|
||||
fn to_raqote_style(self) -> raqote::LineJoin {
|
||||
match self {
|
||||
LineJoinStyle::Round => raqote::LineJoin::Round,
|
||||
LineJoinStyle::Bevel => raqote::LineJoin::Bevel,
|
||||
LineJoinStyle::Miter => raqote::LineJoin::Miter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRaqoteStyle for LineCapStyle {
|
||||
type Target = raqote::LineCap;
|
||||
|
||||
fn to_raqote_style(self) -> raqote::LineCap {
|
||||
match self {
|
||||
LineCapStyle::Butt => raqote::LineCap::Butt,
|
||||
LineCapStyle::Round => raqote::LineCap::Round,
|
||||
LineCapStyle::Square => raqote::LineCap::Square,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToRaqotePattern {
|
||||
fn to_raqote_pattern(self) -> Pattern;
|
||||
}
|
||||
|
||||
pub trait ToRaqoteGradientStop {
|
||||
fn to_raqote(self) -> raqote::GradientStop;
|
||||
}
|
||||
|
||||
impl ToRaqoteGradientStop for CanvasGradientStop {
|
||||
fn to_raqote(self) -> raqote::GradientStop {
|
||||
let srgb = self.color.into_srgb_legacy();
|
||||
let color = raqote::Color::new(
|
||||
clamp_unit_f32(srgb.alpha),
|
||||
clamp_unit_f32(srgb.components.0),
|
||||
clamp_unit_f32(srgb.components.1),
|
||||
clamp_unit_f32(srgb.components.2),
|
||||
);
|
||||
let position = self.offset as f32;
|
||||
raqote::GradientStop { position, color }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRaqotePattern for FillOrStrokeStyle {
|
||||
fn to_raqote_pattern(self) -> Pattern {
|
||||
use canvas_traits::canvas::FillOrStrokeStyle::*;
|
||||
|
||||
match self {
|
||||
Color(color) => {
|
||||
let srgb = color.into_srgb_legacy();
|
||||
Pattern::Color(
|
||||
clamp_unit_f32(srgb.alpha),
|
||||
clamp_unit_f32(srgb.components.0),
|
||||
clamp_unit_f32(srgb.components.1),
|
||||
clamp_unit_f32(srgb.components.2),
|
||||
)
|
||||
},
|
||||
LinearGradient(style) => {
|
||||
let start = Point2D::new(style.x0 as f32, style.y0 as f32);
|
||||
let end = Point2D::new(style.x1 as f32, style.y1 as f32);
|
||||
let stops = create_gradient_stops(style.stops);
|
||||
Pattern::LinearGradient(LinearGradientPattern::new(start, end, stops))
|
||||
},
|
||||
RadialGradient(style) => {
|
||||
let center1 = Point2D::new(style.x0 as f32, style.y0 as f32);
|
||||
let center2 = Point2D::new(style.x1 as f32, style.y1 as f32);
|
||||
let stops = create_gradient_stops(style.stops);
|
||||
Pattern::RadialGradient(RadialGradientPattern::new(
|
||||
center1,
|
||||
style.r0 as f32,
|
||||
center2,
|
||||
style.r1 as f32,
|
||||
stops,
|
||||
))
|
||||
},
|
||||
Surface(style) => {
|
||||
let repeat = Repetition::from_xy(style.repeat_x, style.repeat_y);
|
||||
let mut snapshot = style.surface_data.to_owned();
|
||||
snapshot.transform(
|
||||
SnapshotAlphaMode::Transparent {
|
||||
premultiplied: true,
|
||||
},
|
||||
SnapshotPixelFormat::BGRA,
|
||||
);
|
||||
Pattern::Surface(SurfacePattern::new(
|
||||
snapshot,
|
||||
raqote::FilterMode::Nearest,
|
||||
repeat,
|
||||
style.transform,
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRaqoteStyle for AbsoluteColor {
|
||||
type Target = raqote::SolidSource;
|
||||
|
||||
fn to_raqote_style(self) -> Self::Target {
|
||||
let srgb = self.into_srgb_legacy();
|
||||
raqote::SolidSource::from_unpremultiplied_argb(
|
||||
clamp_unit_f32(srgb.alpha),
|
||||
clamp_unit_f32(srgb.components.0),
|
||||
clamp_unit_f32(srgb.components.1),
|
||||
clamp_unit_f32(srgb.components.2),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRaqoteStyle for CompositionOrBlending {
|
||||
type Target = raqote::BlendMode;
|
||||
|
||||
fn to_raqote_style(self) -> Self::Target {
|
||||
match self {
|
||||
CompositionOrBlending::Composition(op) => op.to_raqote_style(),
|
||||
CompositionOrBlending::Blending(op) => op.to_raqote_style(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRaqoteStyle for BlendingStyle {
|
||||
type Target = raqote::BlendMode;
|
||||
|
||||
fn to_raqote_style(self) -> Self::Target {
|
||||
match self {
|
||||
BlendingStyle::Multiply => raqote::BlendMode::Multiply,
|
||||
BlendingStyle::Screen => raqote::BlendMode::Screen,
|
||||
BlendingStyle::Overlay => raqote::BlendMode::Overlay,
|
||||
BlendingStyle::Darken => raqote::BlendMode::Darken,
|
||||
BlendingStyle::Lighten => raqote::BlendMode::Lighten,
|
||||
BlendingStyle::ColorDodge => raqote::BlendMode::ColorDodge,
|
||||
BlendingStyle::HardLight => raqote::BlendMode::HardLight,
|
||||
BlendingStyle::SoftLight => raqote::BlendMode::SoftLight,
|
||||
BlendingStyle::Difference => raqote::BlendMode::Difference,
|
||||
BlendingStyle::Exclusion => raqote::BlendMode::Exclusion,
|
||||
BlendingStyle::Hue => raqote::BlendMode::Hue,
|
||||
BlendingStyle::Saturation => raqote::BlendMode::Saturation,
|
||||
BlendingStyle::Color => raqote::BlendMode::Color,
|
||||
BlendingStyle::Luminosity => raqote::BlendMode::Luminosity,
|
||||
BlendingStyle::ColorBurn => raqote::BlendMode::ColorBurn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRaqoteStyle for CompositionStyle {
|
||||
type Target = raqote::BlendMode;
|
||||
|
||||
fn to_raqote_style(self) -> Self::Target {
|
||||
match self {
|
||||
CompositionStyle::SourceIn => raqote::BlendMode::SrcIn,
|
||||
CompositionStyle::SourceOut => raqote::BlendMode::SrcOut,
|
||||
CompositionStyle::SourceOver => raqote::BlendMode::SrcOver,
|
||||
CompositionStyle::SourceAtop => raqote::BlendMode::SrcAtop,
|
||||
CompositionStyle::DestinationIn => raqote::BlendMode::DstIn,
|
||||
CompositionStyle::DestinationOut => raqote::BlendMode::DstOut,
|
||||
CompositionStyle::DestinationOver => raqote::BlendMode::DstOver,
|
||||
CompositionStyle::DestinationAtop => raqote::BlendMode::DstAtop,
|
||||
CompositionStyle::Copy => raqote::BlendMode::Src,
|
||||
CompositionStyle::Lighter => raqote::BlendMode::Add,
|
||||
CompositionStyle::Xor => raqote::BlendMode::Xor,
|
||||
CompositionStyle::Clear => raqote::BlendMode::Clear,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_path(path: &canvas_traits::canvas::Path) -> raqote::Path {
|
||||
let mut pb = PathBuilder::new();
|
||||
for cmd in &path.0 {
|
||||
match cmd {
|
||||
kurbo::PathEl::MoveTo(kurbo::Point { x, y }) => pb.move_to(x as f32, y as f32),
|
||||
kurbo::PathEl::LineTo(kurbo::Point { x, y }) => pb.line_to(x as f32, y as f32),
|
||||
kurbo::PathEl::QuadTo(cp, p) => {
|
||||
pb.quad_to(cp.x as f32, cp.y as f32, p.x as f32, p.y as f32)
|
||||
},
|
||||
kurbo::PathEl::CurveTo(cp1, cp2, p) => pb.cubic_to(
|
||||
cp1.x as f32,
|
||||
cp1.y as f32,
|
||||
cp2.x as f32,
|
||||
cp2.y as f32,
|
||||
p.x as f32,
|
||||
p.y as f32,
|
||||
),
|
||||
kurbo::PathEl::ClosePath => pb.close(),
|
||||
}
|
||||
}
|
||||
pb.finish()
|
||||
}
|
||||
|
||||
fn draw_options(composition_options: CompositionOptions) -> DrawOptions {
|
||||
DrawOptions {
|
||||
blend_mode: composition_options.composition_operation.to_raqote_style(),
|
||||
alpha: composition_options.alpha as f32,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
|
@ -41,10 +41,7 @@ use crate::backend::{Convert as _, 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.
|
||||
/// The shared font cache used by all canvases that render on a thread.
|
||||
static SHARED_FONT_CACHE: RefCell<HashMap<FontIdentifier, peniko::Font>> = RefCell::default();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,7 @@ 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.
|
||||
/// The shared font cache used by all canvases that render on a thread.
|
||||
static SHARED_FONT_CACHE: RefCell<HashMap<FontIdentifier, peniko::Font>> = RefCell::default();
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,6 @@ pub struct Preferences {
|
|||
///
|
||||
/// Available values:
|
||||
/// - ` `/`auto`
|
||||
/// - raqote
|
||||
/// - vello
|
||||
/// - vello_cpu
|
||||
pub dom_canvas_backend: String,
|
||||
|
|
|
@ -18,7 +18,6 @@ tracing = ["dep:tracing", "canvas/tracing"]
|
|||
webgpu = ["script_traits/webgpu"]
|
||||
vello = ["canvas/vello"]
|
||||
vello_cpu = ["canvas/vello_cpu"]
|
||||
raqote = ["canvas/raqote"]
|
||||
|
||||
[lints.clippy]
|
||||
unwrap_used = "deny"
|
||||
|
|
|
@ -63,7 +63,6 @@ webgpu = [
|
|||
]
|
||||
vello = ["constellation/vello"]
|
||||
vello_cpu = ["constellation/vello_cpu"]
|
||||
raqote = ["constellation/raqote"]
|
||||
|
||||
[dependencies]
|
||||
background_hang_monitor = { path = "../background_hang_monitor" }
|
||||
|
|
|
@ -53,7 +53,6 @@ webgpu = ["libservo/webgpu"]
|
|||
webxr = ["libservo/webxr"]
|
||||
vello = ["libservo/vello"]
|
||||
vello_cpu = ["libservo/vello_cpu"]
|
||||
raqote = ["libservo/raqote"]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = { workspace = true }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue