mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
canvas: Move peniko/kurbo conversions in separate file (#38279)
This will allow reusing those conversions in vello_cpu backend. Testing: Just refactor Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
4d899ecba5
commit
daebb5a033
7 changed files with 224 additions and 210 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1076,6 +1076,7 @@ dependencies = [
|
|||
"kurbo",
|
||||
"log",
|
||||
"net_traits",
|
||||
"peniko",
|
||||
"pixels",
|
||||
"pollster",
|
||||
"range",
|
||||
|
|
|
@ -105,6 +105,7 @@ num-traits = "0.2"
|
|||
num_cpus = "1.17.0"
|
||||
openxr = "0.19"
|
||||
parking_lot = "0.12"
|
||||
peniko = "0.4"
|
||||
percent-encoding = "2.3"
|
||||
proc-macro2 = "1"
|
||||
profile_traits = { path = "components/shared/profile" }
|
||||
|
|
|
@ -12,7 +12,7 @@ name = "canvas"
|
|||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
vello = ["dep:vello", "dep:pollster", "dep:futures-intrusive"]
|
||||
vello = ["dep:vello", "dep:pollster", "dep:futures-intrusive", "dep:peniko"]
|
||||
|
||||
[dependencies]
|
||||
app_units = { workspace = true }
|
||||
|
@ -27,6 +27,7 @@ ipc-channel = { workspace = true }
|
|||
kurbo = { workspace = true }
|
||||
log = { workspace = true }
|
||||
net_traits = { workspace = true }
|
||||
peniko = { workspace = true, optional = true }
|
||||
pixels = { path = "../pixels" }
|
||||
range = { path = "../range" }
|
||||
raqote = "0.8.5"
|
||||
|
|
|
@ -92,3 +92,10 @@ pub(crate) trait GenericDrawTarget {
|
|||
) -> (ImageDescriptor, SerializableImageData);
|
||||
fn snapshot(&mut self) -> Snapshot;
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // used by gated backends
|
||||
/// A version of the `Into<T>` trait from the standard library that can be used
|
||||
/// to convert between two types that are not defined in the canvas crate.
|
||||
pub(crate) trait Convert<T> {
|
||||
fn convert(self) -> T;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#![deny(unsafe_code)]
|
||||
|
||||
mod backend;
|
||||
#[cfg(feature = "vello")]
|
||||
mod peniko_conversions;
|
||||
mod raqote_backend;
|
||||
#[cfg(feature = "vello")]
|
||||
mod vello_backend;
|
||||
|
|
209
components/canvas/peniko_conversions.rs
Normal file
209
components/canvas/peniko_conversions.rs
Normal file
|
@ -0,0 +1,209 @@
|
|||
/* 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 canvas_traits::canvas::*;
|
||||
use pixels::{SnapshotAlphaMode, SnapshotPixelFormat};
|
||||
use style::color::AbsoluteColor;
|
||||
|
||||
use crate::backend::Convert;
|
||||
use crate::canvas_data::Filter;
|
||||
|
||||
impl Convert<kurbo::Join> for LineJoinStyle {
|
||||
fn convert(self) -> kurbo::Join {
|
||||
match self {
|
||||
LineJoinStyle::Round => kurbo::Join::Round,
|
||||
LineJoinStyle::Bevel => kurbo::Join::Bevel,
|
||||
LineJoinStyle::Miter => kurbo::Join::Miter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<kurbo::Cap> for LineCapStyle {
|
||||
fn convert(self) -> kurbo::Cap {
|
||||
match self {
|
||||
LineCapStyle::Butt => kurbo::Cap::Butt,
|
||||
LineCapStyle::Round => kurbo::Cap::Round,
|
||||
LineCapStyle::Square => kurbo::Cap::Square,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::Color> for AbsoluteColor {
|
||||
fn convert(self) -> peniko::Color {
|
||||
let srgb = self.into_srgb_legacy();
|
||||
peniko::Color::new([
|
||||
srgb.components.0,
|
||||
srgb.components.1,
|
||||
srgb.components.2,
|
||||
srgb.alpha,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::BlendMode> for CompositionOrBlending {
|
||||
fn convert(self) -> peniko::BlendMode {
|
||||
match self {
|
||||
CompositionOrBlending::Composition(composition_style) => {
|
||||
composition_style.convert().into()
|
||||
},
|
||||
CompositionOrBlending::Blending(blending_style) => blending_style.convert().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::Compose> for CompositionStyle {
|
||||
fn convert(self) -> peniko::Compose {
|
||||
match self {
|
||||
CompositionStyle::SourceIn => peniko::Compose::SrcIn,
|
||||
CompositionStyle::SourceOut => peniko::Compose::SrcOut,
|
||||
CompositionStyle::SourceOver => peniko::Compose::SrcOver,
|
||||
CompositionStyle::SourceAtop => peniko::Compose::SrcAtop,
|
||||
CompositionStyle::DestinationIn => peniko::Compose::DestIn,
|
||||
CompositionStyle::DestinationOut => peniko::Compose::DestOut,
|
||||
CompositionStyle::DestinationOver => peniko::Compose::DestOver,
|
||||
CompositionStyle::DestinationAtop => peniko::Compose::DestAtop,
|
||||
CompositionStyle::Copy => peniko::Compose::Copy,
|
||||
CompositionStyle::Lighter => peniko::Compose::Plus,
|
||||
CompositionStyle::Xor => peniko::Compose::Xor,
|
||||
CompositionStyle::Clear => peniko::Compose::Clear,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::Mix> for BlendingStyle {
|
||||
fn convert(self) -> peniko::Mix {
|
||||
match self {
|
||||
BlendingStyle::Multiply => peniko::Mix::Multiply,
|
||||
BlendingStyle::Screen => peniko::Mix::Screen,
|
||||
BlendingStyle::Overlay => peniko::Mix::Overlay,
|
||||
BlendingStyle::Darken => peniko::Mix::Darken,
|
||||
BlendingStyle::Lighten => peniko::Mix::Lighten,
|
||||
BlendingStyle::ColorDodge => peniko::Mix::ColorDodge,
|
||||
BlendingStyle::ColorBurn => peniko::Mix::ColorBurn,
|
||||
BlendingStyle::HardLight => peniko::Mix::HardLight,
|
||||
BlendingStyle::SoftLight => peniko::Mix::SoftLight,
|
||||
BlendingStyle::Difference => peniko::Mix::Difference,
|
||||
BlendingStyle::Exclusion => peniko::Mix::Exclusion,
|
||||
BlendingStyle::Hue => peniko::Mix::Hue,
|
||||
BlendingStyle::Saturation => peniko::Mix::Saturation,
|
||||
BlendingStyle::Color => peniko::Mix::Color,
|
||||
BlendingStyle::Luminosity => peniko::Mix::Luminosity,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<kurbo::Stroke> for LineOptions {
|
||||
fn convert(self) -> kurbo::Stroke {
|
||||
let LineOptions {
|
||||
width,
|
||||
cap_style,
|
||||
join_style,
|
||||
miter_limit,
|
||||
dash,
|
||||
dash_offset,
|
||||
} = self;
|
||||
kurbo::Stroke {
|
||||
width,
|
||||
join: join_style.convert(),
|
||||
miter_limit,
|
||||
start_cap: cap_style.convert(),
|
||||
end_cap: cap_style.convert(),
|
||||
dash_pattern: dash.iter().map(|x| *x as f64).collect(),
|
||||
dash_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::Brush> for FillOrStrokeStyle {
|
||||
fn convert(self) -> peniko::Brush {
|
||||
use canvas_traits::canvas::FillOrStrokeStyle::*;
|
||||
match self {
|
||||
Color(absolute_color) => peniko::Brush::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();
|
||||
peniko::Brush::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();
|
||||
peniko::Brush::Gradient(gradient)
|
||||
},
|
||||
Surface(surface_style) => {
|
||||
let data = surface_style
|
||||
.surface_data
|
||||
.to_owned()
|
||||
.to_vec(
|
||||
Some(SnapshotAlphaMode::Transparent {
|
||||
premultiplied: false,
|
||||
}),
|
||||
Some(SnapshotPixelFormat::RGBA),
|
||||
)
|
||||
.0;
|
||||
peniko::Brush::Image(peniko::Image {
|
||||
data: peniko::Blob::from(data),
|
||||
format: peniko::ImageFormat::Rgba8,
|
||||
width: surface_style.surface_size.width,
|
||||
height: surface_style.surface_size.height,
|
||||
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,
|
||||
alpha: 1.0,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::color::DynamicColor> for AbsoluteColor {
|
||||
fn convert(self) -> peniko::color::DynamicColor {
|
||||
peniko::color::DynamicColor::from_alpha_color(self.convert())
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::ColorStop> for CanvasGradientStop {
|
||||
fn convert(self) -> peniko::ColorStop {
|
||||
peniko::ColorStop {
|
||||
offset: self.offset as f32,
|
||||
color: self.color.convert(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::ColorStops> for Vec<CanvasGradientStop> {
|
||||
fn convert(self) -> peniko::ColorStops {
|
||||
let mut stops = peniko::ColorStops(self.into_iter().map(|item| item.convert()).collect());
|
||||
// https://www.w3.org/html/test/results/2dcontext/annotated-spec/canvas.html#testrefs.2d.gradient.interpolate.overlap
|
||||
stops
|
||||
.0
|
||||
.sort_by(|a, b| a.offset.partial_cmp(&b.offset).unwrap());
|
||||
stops
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::ImageQuality> for Filter {
|
||||
fn convert(self) -> peniko::ImageQuality {
|
||||
match self {
|
||||
Filter::Bilinear => peniko::ImageQuality::Medium,
|
||||
Filter::Nearest => peniko::ImageQuality::Low,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,8 +17,7 @@ use std::num::NonZeroUsize;
|
|||
use std::rc::Rc;
|
||||
|
||||
use canvas_traits::canvas::{
|
||||
BlendingStyle, CanvasGradientStop, CompositionOptions, CompositionOrBlending, CompositionStyle,
|
||||
FillOrStrokeStyle, LineCapStyle, LineJoinStyle, LineOptions, Path, ShadowOptions,
|
||||
CompositionOptions, FillOrStrokeStyle, LineOptions, Path, ShadowOptions,
|
||||
};
|
||||
use compositing_traits::SerializableImageData;
|
||||
use euclid::default::{Point2D, Rect, Size2D, Transform2D};
|
||||
|
@ -26,7 +25,6 @@ use fonts::{ByteIndex, FontIdentifier, FontTemplateRefMethods as _};
|
|||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use pixels::{Snapshot, SnapshotAlphaMode, SnapshotPixelFormat};
|
||||
use range::Range;
|
||||
use style::color::AbsoluteColor;
|
||||
use vello::wgpu::{
|
||||
BackendOptions, Backends, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Device,
|
||||
Extent3d, Instance, InstanceDescriptor, InstanceFlags, MapMode, Queue, TexelCopyBufferInfo,
|
||||
|
@ -36,7 +34,7 @@ use vello::wgpu::{
|
|||
use vello::{kurbo, peniko};
|
||||
use webrender_api::{ImageDescriptor, ImageDescriptorFlags};
|
||||
|
||||
use crate::backend::GenericDrawTarget;
|
||||
use crate::backend::{Convert as _, GenericDrawTarget};
|
||||
use crate::canvas_data::{Filter, TextRun};
|
||||
|
||||
thread_local! {
|
||||
|
@ -545,208 +543,3 @@ impl GenericDrawTarget for VelloDrawTarget {
|
|||
Some(data)
|
||||
}
|
||||
}
|
||||
|
||||
/// A version of the `Into<T>` trait from the standard library that can be used
|
||||
/// to convert between two types that are not defined in the canvas crate.
|
||||
pub(crate) trait Convert<T> {
|
||||
fn convert(self) -> T;
|
||||
}
|
||||
|
||||
impl Convert<kurbo::Join> for LineJoinStyle {
|
||||
fn convert(self) -> kurbo::Join {
|
||||
match self {
|
||||
LineJoinStyle::Round => kurbo::Join::Round,
|
||||
LineJoinStyle::Bevel => kurbo::Join::Bevel,
|
||||
LineJoinStyle::Miter => kurbo::Join::Miter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<kurbo::Cap> for LineCapStyle {
|
||||
fn convert(self) -> kurbo::Cap {
|
||||
match self {
|
||||
LineCapStyle::Butt => kurbo::Cap::Butt,
|
||||
LineCapStyle::Round => kurbo::Cap::Round,
|
||||
LineCapStyle::Square => kurbo::Cap::Square,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::Color> for AbsoluteColor {
|
||||
fn convert(self) -> peniko::Color {
|
||||
let srgb = self.into_srgb_legacy();
|
||||
peniko::Color::new([
|
||||
srgb.components.0,
|
||||
srgb.components.1,
|
||||
srgb.components.2,
|
||||
srgb.alpha,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::BlendMode> for CompositionOrBlending {
|
||||
fn convert(self) -> peniko::BlendMode {
|
||||
match self {
|
||||
CompositionOrBlending::Composition(composition_style) => {
|
||||
composition_style.convert().into()
|
||||
},
|
||||
CompositionOrBlending::Blending(blending_style) => blending_style.convert().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::Compose> for CompositionStyle {
|
||||
fn convert(self) -> peniko::Compose {
|
||||
match self {
|
||||
CompositionStyle::SourceIn => peniko::Compose::SrcIn,
|
||||
CompositionStyle::SourceOut => peniko::Compose::SrcOut,
|
||||
CompositionStyle::SourceOver => peniko::Compose::SrcOver,
|
||||
CompositionStyle::SourceAtop => peniko::Compose::SrcAtop,
|
||||
CompositionStyle::DestinationIn => peniko::Compose::DestIn,
|
||||
CompositionStyle::DestinationOut => peniko::Compose::DestOut,
|
||||
CompositionStyle::DestinationOver => peniko::Compose::DestOver,
|
||||
CompositionStyle::DestinationAtop => peniko::Compose::DestAtop,
|
||||
CompositionStyle::Copy => peniko::Compose::Copy,
|
||||
CompositionStyle::Lighter => peniko::Compose::Plus,
|
||||
CompositionStyle::Xor => peniko::Compose::Xor,
|
||||
CompositionStyle::Clear => peniko::Compose::Clear,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::Mix> for BlendingStyle {
|
||||
fn convert(self) -> peniko::Mix {
|
||||
match self {
|
||||
BlendingStyle::Multiply => peniko::Mix::Multiply,
|
||||
BlendingStyle::Screen => peniko::Mix::Screen,
|
||||
BlendingStyle::Overlay => peniko::Mix::Overlay,
|
||||
BlendingStyle::Darken => peniko::Mix::Darken,
|
||||
BlendingStyle::Lighten => peniko::Mix::Lighten,
|
||||
BlendingStyle::ColorDodge => peniko::Mix::ColorDodge,
|
||||
BlendingStyle::ColorBurn => peniko::Mix::ColorBurn,
|
||||
BlendingStyle::HardLight => peniko::Mix::HardLight,
|
||||
BlendingStyle::SoftLight => peniko::Mix::SoftLight,
|
||||
BlendingStyle::Difference => peniko::Mix::Difference,
|
||||
BlendingStyle::Exclusion => peniko::Mix::Exclusion,
|
||||
BlendingStyle::Hue => peniko::Mix::Hue,
|
||||
BlendingStyle::Saturation => peniko::Mix::Saturation,
|
||||
BlendingStyle::Color => peniko::Mix::Color,
|
||||
BlendingStyle::Luminosity => peniko::Mix::Luminosity,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<kurbo::Stroke> for LineOptions {
|
||||
fn convert(self) -> kurbo::Stroke {
|
||||
let LineOptions {
|
||||
width,
|
||||
cap_style,
|
||||
join_style,
|
||||
miter_limit,
|
||||
dash,
|
||||
dash_offset,
|
||||
} = self;
|
||||
kurbo::Stroke {
|
||||
width,
|
||||
join: join_style.convert(),
|
||||
miter_limit,
|
||||
start_cap: cap_style.convert(),
|
||||
end_cap: cap_style.convert(),
|
||||
dash_pattern: dash.iter().map(|x| *x as f64).collect(),
|
||||
dash_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::Brush> for FillOrStrokeStyle {
|
||||
fn convert(self) -> peniko::Brush {
|
||||
use canvas_traits::canvas::FillOrStrokeStyle::*;
|
||||
match self {
|
||||
Color(absolute_color) => peniko::Brush::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();
|
||||
peniko::Brush::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();
|
||||
peniko::Brush::Gradient(gradient)
|
||||
},
|
||||
Surface(surface_style) => {
|
||||
let data = surface_style
|
||||
.surface_data
|
||||
.to_owned()
|
||||
.to_vec(
|
||||
Some(SnapshotAlphaMode::Transparent {
|
||||
premultiplied: false,
|
||||
}),
|
||||
Some(SnapshotPixelFormat::RGBA),
|
||||
)
|
||||
.0;
|
||||
peniko::Brush::Image(peniko::Image {
|
||||
data: peniko::Blob::from(data),
|
||||
format: peniko::ImageFormat::Rgba8,
|
||||
width: surface_style.surface_size.width,
|
||||
height: surface_style.surface_size.height,
|
||||
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,
|
||||
alpha: 1.0,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::color::DynamicColor> for AbsoluteColor {
|
||||
fn convert(self) -> peniko::color::DynamicColor {
|
||||
peniko::color::DynamicColor::from_alpha_color(self.convert())
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::ColorStop> for CanvasGradientStop {
|
||||
fn convert(self) -> peniko::ColorStop {
|
||||
peniko::ColorStop {
|
||||
offset: self.offset as f32,
|
||||
color: self.color.convert(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::ColorStops> for Vec<CanvasGradientStop> {
|
||||
fn convert(self) -> peniko::ColorStops {
|
||||
let mut stops = peniko::ColorStops(self.into_iter().map(|item| item.convert()).collect());
|
||||
// https://www.w3.org/html/test/results/2dcontext/annotated-spec/canvas.html#testrefs.2d.gradient.interpolate.overlap
|
||||
stops
|
||||
.0
|
||||
.sort_by(|a, b| a.offset.partial_cmp(&b.offset).unwrap());
|
||||
stops
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<peniko::ImageQuality> for Filter {
|
||||
fn convert(self) -> peniko::ImageQuality {
|
||||
match self {
|
||||
Filter::Bilinear => peniko::ImageQuality::Medium,
|
||||
Filter::Nearest => peniko::ImageQuality::Low,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue