canvas: Use Transform2D<f64> instead of Transform2D<f32> (#38316)

I mostly did dumb replacement so please check that this is correct. In
addition, `canvas_data::draw_with_shadow` needs some a bit of a closer
look.

Testing: This is covered by existing tests, and it is likely that WPT
tests are unaffected by the precision of the transform, even though it
is technically more correct.
Fixes: #38256

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
This commit is contained in:
Narfinger 2025-08-11 18:46:25 +02:00 committed by GitHub
parent 4ff1e8dbd9
commit 3f7f9ba6cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 91 additions and 97 deletions

View file

@ -20,7 +20,7 @@ pub(crate) trait GenericDrawTarget {
fn new(size: Size2D<u32>) -> Self; fn new(size: Size2D<u32>) -> Self;
fn create_similar_draw_target(&self, size: &Size2D<i32>) -> Self; fn create_similar_draw_target(&self, size: &Size2D<i32>) -> Self;
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>); fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>);
fn copy_surface( fn copy_surface(
&mut self, &mut self,
surface: Self::SourceSurface, surface: Self::SourceSurface,
@ -35,7 +35,7 @@ pub(crate) trait GenericDrawTarget {
source: Rect<f64>, source: Rect<f64>,
filter: Filter, filter: Filter,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
); );
fn draw_surface_with_shadow( fn draw_surface_with_shadow(
&self, &self,
@ -50,7 +50,7 @@ pub(crate) trait GenericDrawTarget {
fill_rule: FillRule, fill_rule: FillRule,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
); );
fn fill_text( fn fill_text(
&mut self, &mut self,
@ -58,18 +58,18 @@ pub(crate) trait GenericDrawTarget {
start: Point2D<f32>, start: Point2D<f32>,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
); );
fn fill_rect( fn fill_rect(
&mut self, &mut self,
rect: &Rect<f32>, rect: &Rect<f32>,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
); );
fn get_size(&self) -> Size2D<i32>; fn get_size(&self) -> Size2D<i32>;
fn pop_clip(&mut self); fn pop_clip(&mut self);
fn push_clip(&mut self, path: &Path, fill_rule: FillRule, transform: Transform2D<f32>); fn push_clip(&mut self, path: &Path, fill_rule: FillRule, transform: Transform2D<f64>);
fn push_clip_rect(&mut self, rect: &Rect<i32>); fn push_clip_rect(&mut self, rect: &Rect<i32>);
fn stroke( fn stroke(
&mut self, &mut self,
@ -77,7 +77,7 @@ pub(crate) trait GenericDrawTarget {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
line_options: LineOptions, line_options: LineOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
); );
fn stroke_rect( fn stroke_rect(
&mut self, &mut self,
@ -85,7 +85,7 @@ pub(crate) trait GenericDrawTarget {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
line_options: LineOptions, line_options: LineOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
); );
fn surface(&mut self) -> Self::SourceSurface; fn surface(&mut self) -> Self::SourceSurface;
fn image_descriptor_and_serializable_data( fn image_descriptor_and_serializable_data(

View file

@ -141,7 +141,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
smoothing_enabled: bool, smoothing_enabled: bool,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
// We round up the floating pixel values to draw the pixels // We round up the floating pixel values to draw the pixels
let source_rect = source_rect.ceil(); let source_rect = source_rect.ceil();
@ -194,7 +194,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
text_options: &TextOptions, text_options: &TextOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
// > Step 2: Replace all ASCII whitespace in text with U+0020 SPACE characters. // > Step 2: Replace all ASCII whitespace in text with U+0020 SPACE characters.
let text = replace_ascii_whitespace(text); let text = replace_ascii_whitespace(text);
@ -299,7 +299,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
text_options: TextOptions, text_options: TextOptions,
_shadow_options: ShadowOptions, _shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
let Some(ref font_style) = text_options.font else { let Some(ref font_style) = text_options.font else {
return; return;
@ -481,7 +481,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
if style.is_zero_size_gradient() { if style.is_zero_size_gradient() {
return; // Paint nothing if gradient size is zero. return; // Paint nothing if gradient size is zero.
@ -512,7 +512,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
} }
} }
pub(crate) fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) { pub(crate) fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) {
self.drawtarget.clear_rect(rect, transform); self.drawtarget.clear_rect(rect, transform);
} }
@ -523,7 +523,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
line_options: LineOptions, line_options: LineOptions,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
if style.is_zero_size_gradient() { if style.is_zero_size_gradient() {
return; // Paint nothing if gradient size is zero. return; // Paint nothing if gradient size is zero.
@ -571,7 +571,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
_shadow_options: ShadowOptions, _shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
if style.is_zero_size_gradient() { if style.is_zero_size_gradient() {
return; // Paint nothing if gradient size is zero. return; // Paint nothing if gradient size is zero.
@ -597,7 +597,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
line_options: LineOptions, line_options: LineOptions,
_shadow_options: ShadowOptions, _shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
if style.is_zero_size_gradient() { if style.is_zero_size_gradient() {
return; // Paint nothing if gradient size is zero. return; // Paint nothing if gradient size is zero.
@ -620,7 +620,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
&mut self, &mut self,
path: &Path, path: &Path,
fill_rule: FillRule, fill_rule: FillRule,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.drawtarget.push_clip(path, fill_rule, transform); self.drawtarget.push_clip(path, fill_rule, transform);
} }
@ -673,21 +673,23 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
rect: &Rect<f32>, rect: &Rect<f32>,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
draw_shadow_source: F, draw_shadow_source: F,
) where ) where
F: FnOnce(&mut DrawTarget, Transform2D<f32>), F: FnOnce(&mut DrawTarget, Transform2D<f64>),
{ {
let shadow_src_rect = transform.outer_transformed_rect(rect); let shadow_src_rect = transform.outer_transformed_rect(&rect.cast());
let mut new_draw_target = self.create_draw_target_for_shadow(&shadow_src_rect); // Because this comes from the rect on f32 precision, casting it down should be ok.
let shadow_transform = transform.then( let mut new_draw_target = self.create_draw_target_for_shadow(&shadow_src_rect.cast());
&Transform2D::identity() let shadow_transform = transform
.pre_translate(-shadow_src_rect.origin.to_vector().cast::<f32>()), .then(&Transform2D::identity().pre_translate(-shadow_src_rect.origin.to_vector()));
);
draw_shadow_source(&mut new_draw_target, shadow_transform); draw_shadow_source(&mut new_draw_target, shadow_transform);
self.drawtarget.draw_surface_with_shadow( self.drawtarget.draw_surface_with_shadow(
new_draw_target.surface(), new_draw_target.surface(),
&Point2D::new(shadow_src_rect.origin.x, shadow_src_rect.origin.y), &Point2D::new(
shadow_src_rect.origin.x as f32,
shadow_src_rect.origin.y as f32,
),
shadow_options, shadow_options,
composition_options, composition_options,
); );
@ -700,7 +702,7 @@ impl<DrawTarget: GenericDrawTarget> CanvasData<DrawTarget> {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
path_bound_box: &Rect<f64>, path_bound_box: &Rect<f64>,
transform: Transform2D<f32>, transform: Transform2D<f64>,
draw_shape: F, draw_shape: F,
) where ) where
F: FnOnce(&mut Self, FillOrStrokeStyle), F: FnOnce(&mut Self, FillOrStrokeStyle),
@ -778,7 +780,7 @@ fn write_image<DrawTarget: GenericDrawTarget>(
dest_rect: Rect<f64>, dest_rect: Rect<f64>,
smoothing_enabled: bool, smoothing_enabled: bool,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
if snapshot.size().is_empty() { if snapshot.size().is_empty() {
return; return;

View file

@ -371,7 +371,7 @@ impl Canvas {
text_options: TextOptions, text_options: TextOptions,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")] #[cfg(feature = "raqote")]
@ -423,7 +423,7 @@ impl Canvas {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")] #[cfg(feature = "raqote")]
@ -449,7 +449,7 @@ impl Canvas {
line_options: LineOptions, line_options: LineOptions,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")] #[cfg(feature = "raqote")]
@ -490,7 +490,7 @@ impl Canvas {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")] #[cfg(feature = "raqote")]
@ -531,7 +531,7 @@ impl Canvas {
line_options: LineOptions, line_options: LineOptions,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")] #[cfg(feature = "raqote")]
@ -565,7 +565,7 @@ impl Canvas {
} }
} }
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) { fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) {
match self { match self {
#[cfg(feature = "raqote")] #[cfg(feature = "raqote")]
Canvas::Raqote(canvas_data) => canvas_data.clear_rect(rect, transform), Canvas::Raqote(canvas_data) => canvas_data.clear_rect(rect, transform),
@ -585,7 +585,7 @@ impl Canvas {
smoothing_enabled: bool, smoothing_enabled: bool,
shadow_options: ShadowOptions, shadow_options: ShadowOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
match self { match self {
#[cfg(feature = "raqote")] #[cfg(feature = "raqote")]
@ -646,7 +646,7 @@ impl Canvas {
} }
} }
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<f64>) {
match self { match self {
#[cfg(feature = "raqote")] #[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),

View file

@ -184,7 +184,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
raqote::DrawTarget::new(size.width as i32, size.height as i32) raqote::DrawTarget::new(size.width as i32, size.height as i32)
} }
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) { fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) {
<Self as GenericDrawTarget>::fill_rect( <Self as GenericDrawTarget>::fill_rect(
self, self,
rect, rect,
@ -230,7 +230,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
src: Rect<f64>, src: Rect<f64>,
filter: Filter, filter: Filter,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
let paint_transform = let paint_transform =
raqote::Transform::translation(-dest.origin.x as f32, -dest.origin.y as f32) raqote::Transform::translation(-dest.origin.x as f32, -dest.origin.y as f32)
@ -239,7 +239,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
src.size.height as f32 / dest.size.height as f32, src.size.height as f32 / dest.size.height as f32,
); );
self.set_transform(&transform); self.set_transform(&transform.cast());
let dest = dest.cast(); let dest = dest.cast();
let mut pb = raqote::PathBuilder::new(); let mut pb = raqote::PathBuilder::new();
pb.rect( pb.rect(
@ -280,9 +280,9 @@ impl GenericDrawTarget for raqote::DrawTarget {
fill_rule: FillRule, fill_rule: FillRule,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.set_transform(&transform); self.set_transform(&transform.cast());
let draw_options = draw_options(composition_options); let draw_options = draw_options(composition_options);
let pattern = style.to_raqote_pattern(); let pattern = style.to_raqote_pattern();
let mut path = to_path(path); let mut path = to_path(path);
@ -299,9 +299,9 @@ impl GenericDrawTarget for raqote::DrawTarget {
start: Point2D<f32>, start: Point2D<f32>,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.set_transform(&transform); self.set_transform(&transform.cast());
let draw_options = draw_options(composition_options); let draw_options = draw_options(composition_options);
let pattern = style.to_raqote_pattern(); let pattern = style.to_raqote_pattern();
let mut advance = 0.; let mut advance = 0.;
@ -362,7 +362,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
rect: &Rect<f32>, rect: &Rect<f32>,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
let rect = rect.cast(); let rect = rect.cast();
let mut pb = canvas_traits::canvas::Path::new(); let mut pb = canvas_traits::canvas::Path::new();
@ -392,9 +392,9 @@ impl GenericDrawTarget for raqote::DrawTarget {
&mut self, &mut self,
path: &canvas_traits::canvas::Path, path: &canvas_traits::canvas::Path,
fill_rule: FillRule, fill_rule: FillRule,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.set_transform(&transform); self.set_transform(&transform.cast());
let mut path = to_path(path); let mut path = to_path(path);
path.winding = match fill_rule { path.winding = match fill_rule {
FillRule::Nonzero => raqote::Winding::NonZero, FillRule::Nonzero => raqote::Winding::NonZero,
@ -414,11 +414,11 @@ impl GenericDrawTarget for raqote::DrawTarget {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
line_options: LineOptions, line_options: LineOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
let pattern = style.to_raqote_pattern(); let pattern = style.to_raqote_pattern();
let options = draw_options(composition_options); let options = draw_options(composition_options);
self.set_transform(&transform); self.set_transform(&transform.cast());
self.stroke( self.stroke(
&to_path(path), &to_path(path),
&source(&pattern), &source(&pattern),
@ -432,9 +432,9 @@ impl GenericDrawTarget for raqote::DrawTarget {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
line_options: LineOptions, line_options: LineOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.set_transform(&transform); self.set_transform(&transform.cast());
let pattern = style.to_raqote_pattern(); let pattern = style.to_raqote_pattern();
let options = draw_options(composition_options); let options = draw_options(composition_options);
let mut pb = raqote::PathBuilder::new(); let mut pb = raqote::PathBuilder::new();

View file

@ -169,8 +169,8 @@ impl VelloDrawTarget {
} }
} }
fn is_viewport_cleared(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) -> bool { fn is_viewport_cleared(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) -> bool {
let transformed_rect = transform.outer_transformed_rect(rect); let transformed_rect = transform.outer_transformed_rect(&rect.cast());
if transformed_rect.is_empty() { if transformed_rect.is_empty() {
return false; return false;
} }
@ -239,7 +239,7 @@ impl GenericDrawTarget for VelloDrawTarget {
Self::new_with_renderer(device, queue, Rc::new(RefCell::new(renderer)), size) Self::new_with_renderer(device, queue, Rc::new(RefCell::new(renderer)), size)
} }
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) { fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) {
// vello scene only ever grows, // vello scene only ever grows,
// so we use every opportunity to shrink it // so we use every opportunity to shrink it
if self.is_viewport_cleared(rect, transform) { if self.is_viewport_cleared(rect, transform) {
@ -250,7 +250,7 @@ impl GenericDrawTarget for VelloDrawTarget {
} }
self.ensure_drawing(); self.ensure_drawing();
let rect: kurbo::Rect = rect.cast().into(); let rect: kurbo::Rect = rect.cast().into();
let transform = transform.cast().into(); let transform = transform.into();
self.scene self.scene
.push_layer(peniko::Compose::Clear, 0.0, transform, &rect); .push_layer(peniko::Compose::Clear, 0.0, transform, &rect);
self.scene.fill( self.scene.fill(
@ -310,7 +310,7 @@ impl GenericDrawTarget for VelloDrawTarget {
source: Rect<f64>, source: Rect<f64>,
filter: Filter, filter: Filter,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
let scale_up = dest.size.width > source.size.width || dest.size.height > source.size.height; let scale_up = dest.size.width > source.size.width || dest.size.height > source.size.height;
@ -367,7 +367,7 @@ impl GenericDrawTarget for VelloDrawTarget {
fill_rule: FillRule, fill_rule: FillRule,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
self.with_composition(composition_options.composition_operation, |self_| { self.with_composition(composition_options.composition_operation, |self_| {
@ -387,7 +387,7 @@ impl GenericDrawTarget for VelloDrawTarget {
start: Point2D<f32>, start: Point2D<f32>,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
let pattern = convert_to_brush(style, composition_options); let pattern = convert_to_brush(style, composition_options);
@ -448,7 +448,7 @@ impl GenericDrawTarget for VelloDrawTarget {
rect: &Rect<f32>, rect: &Rect<f32>,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
let pattern = convert_to_brush(style, composition_options); let pattern = convert_to_brush(style, composition_options);
@ -471,7 +471,7 @@ impl GenericDrawTarget for VelloDrawTarget {
} }
} }
fn push_clip(&mut self, path: &Path, _fill_rule: FillRule, transform: Transform2D<f32>) { fn push_clip(&mut self, path: &Path, _fill_rule: FillRule, transform: Transform2D<f64>) {
self.scene self.scene
.push_layer(peniko::Mix::Clip, 1.0, transform.cast().into(), &path.0); .push_layer(peniko::Mix::Clip, 1.0, transform.cast().into(), &path.0);
let mut path = path.clone(); let mut path = path.clone();
@ -497,7 +497,7 @@ impl GenericDrawTarget for VelloDrawTarget {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
line_options: LineOptions, line_options: LineOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
self.with_composition(composition_options.composition_operation, |self_| { self.with_composition(composition_options.composition_operation, |self_| {
@ -517,7 +517,7 @@ impl GenericDrawTarget for VelloDrawTarget {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
line_options: LineOptions, line_options: LineOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
let rect: kurbo::Rect = rect.cast().into(); let rect: kurbo::Rect = rect.cast().into();

View file

@ -126,8 +126,8 @@ impl VelloCPUDrawTarget {
Size2D::new(self.ctx.width(), self.ctx.height()).cast() Size2D::new(self.ctx.width(), self.ctx.height()).cast()
} }
fn is_viewport_cleared(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) -> bool { fn is_viewport_cleared(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) -> bool {
let transformed_rect = transform.outer_transformed_rect(rect); let transformed_rect = transform.outer_transformed_rect(&rect.cast());
if transformed_rect.is_empty() { if transformed_rect.is_empty() {
return false; return false;
} }
@ -156,7 +156,7 @@ impl GenericDrawTarget for VelloCPUDrawTarget {
} }
} }
fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f32>) { fn clear_rect(&mut self, rect: &Rect<f32>, transform: Transform2D<f64>) {
// vello_cpu RenderingContext only ever grows, // vello_cpu RenderingContext only ever grows,
// so we need to use every opportunity to shrink it // so we need to use every opportunity to shrink it
if self.is_viewport_cleared(rect, transform) { if self.is_viewport_cleared(rect, transform) {
@ -217,7 +217,7 @@ impl GenericDrawTarget for VelloCPUDrawTarget {
source: Rect<f64>, source: Rect<f64>,
filter: Filter, filter: Filter,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
let scale_up = dest.size.width > source.size.width || dest.size.height > source.size.height; let scale_up = dest.size.width > source.size.width || dest.size.height > source.size.height;
@ -272,7 +272,7 @@ impl GenericDrawTarget for VelloCPUDrawTarget {
fill_rule: FillRule, fill_rule: FillRule,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
self.with_composition(composition_options.composition_operation, |self_| { self.with_composition(composition_options.composition_operation, |self_| {
@ -290,7 +290,7 @@ impl GenericDrawTarget for VelloCPUDrawTarget {
start: Point2D<f32>, start: Point2D<f32>,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
self.ctx.set_paint(paint(style, composition_options.alpha)); self.ctx.set_paint(paint(style, composition_options.alpha));
@ -348,7 +348,7 @@ impl GenericDrawTarget for VelloCPUDrawTarget {
rect: &Rect<f32>, rect: &Rect<f32>,
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
self.with_composition(composition_options.composition_operation, |self_| { self.with_composition(composition_options.composition_operation, |self_| {
@ -368,7 +368,7 @@ impl GenericDrawTarget for VelloCPUDrawTarget {
} }
} }
fn push_clip(&mut self, path: &Path, fill_rule: FillRule, transform: Transform2D<f32>) { fn push_clip(&mut self, path: &Path, fill_rule: FillRule, transform: Transform2D<f64>) {
self.ctx.set_transform(transform.cast().into()); self.ctx.set_transform(transform.cast().into());
let mut path = path.clone(); let mut path = path.clone();
path.transform(transform.cast()); path.transform(transform.cast());
@ -396,7 +396,7 @@ impl GenericDrawTarget for VelloCPUDrawTarget {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
line_options: LineOptions, line_options: LineOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
self.with_composition(composition_options.composition_operation, |self_| { self.with_composition(composition_options.composition_operation, |self_| {
@ -413,7 +413,7 @@ impl GenericDrawTarget for VelloCPUDrawTarget {
style: FillOrStrokeStyle, style: FillOrStrokeStyle,
line_options: LineOptions, line_options: LineOptions,
composition_options: CompositionOptions, composition_options: CompositionOptions,
transform: Transform2D<f32>, transform: Transform2D<f64>,
) { ) {
self.ensure_drawing(); self.ensure_drawing();
self.with_composition(composition_options.composition_operation, |self_| { self.with_composition(composition_options.composition_operation, |self_| {

View file

@ -105,7 +105,7 @@ pub(crate) struct CanvasContextState {
line_dash: Vec<f64>, line_dash: Vec<f64>,
line_dash_offset: f64, line_dash_offset: f64,
#[no_trace] #[no_trace]
transform: Transform2D<f32>, transform: Transform2D<f64>,
shadow_offset_x: f64, shadow_offset_x: f64,
shadow_offset_y: f64, shadow_offset_y: f64,
shadow_blur: f64, shadow_blur: f64,
@ -1005,7 +1005,7 @@ impl CanvasState {
(source_rect, dest_rect) (source_rect, dest_rect)
} }
fn update_transform(&self, transform: Transform2D<f32>) { fn update_transform(&self, transform: Transform2D<f64>) {
let mut state = self.state.borrow_mut(); let mut state = self.state.borrow_mut();
self.current_default_path self.current_default_path
.borrow_mut() .borrow_mut()
@ -1991,7 +1991,7 @@ impl CanvasState {
} }
let transform = self.state.borrow().transform; let transform = self.state.borrow().transform;
self.update_transform(transform.pre_scale(x as f32, y as f32)) self.update_transform(transform.pre_scale(x, y))
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-rotate // https://html.spec.whatwg.org/multipage/#dom-context-2d-rotate
@ -2002,10 +2002,7 @@ impl CanvasState {
let (sin, cos) = (angle.sin(), angle.cos()); let (sin, cos) = (angle.sin(), angle.cos());
let transform = self.state.borrow().transform; let transform = self.state.borrow().transform;
self.update_transform( self.update_transform(Transform2D::new(cos, sin, -sin, cos, 0.0, 0.0).then(&transform))
Transform2D::new(cos as f32, sin as f32, -sin as f32, cos as f32, 0.0, 0.0)
.then(&transform),
)
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-translate // https://html.spec.whatwg.org/multipage/#dom-context-2d-translate
@ -2015,7 +2012,7 @@ impl CanvasState {
} }
let transform = self.state.borrow().transform; let transform = self.state.borrow().transform;
self.update_transform(transform.pre_translate(vec2(x as f32, y as f32))) self.update_transform(transform.pre_translate(vec2(x, y)))
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-transform // https://html.spec.whatwg.org/multipage/#dom-context-2d-transform
@ -2031,16 +2028,13 @@ impl CanvasState {
} }
let transform = self.state.borrow().transform; let transform = self.state.borrow().transform;
self.update_transform( self.update_transform(Transform2D::new(a, b, c, d, e, f).then(&transform))
Transform2D::new(a as f32, b as f32, c as f32, d as f32, e as f32, f as f32)
.then(&transform),
)
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-gettransform // https://html.spec.whatwg.org/multipage/#dom-context-2d-gettransform
pub(crate) fn get_transform(&self, global: &GlobalScope, can_gc: CanGc) -> DomRoot<DOMMatrix> { pub(crate) fn get_transform(&self, global: &GlobalScope, can_gc: CanGc) -> DomRoot<DOMMatrix> {
let transform = self.state.borrow_mut().transform; let transform = self.state.borrow_mut().transform;
DOMMatrix::new(global, true, transform.cast::<f64>().to_3d(), can_gc) DOMMatrix::new(global, true, transform.to_3d(), can_gc)
} }
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform> /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform>
@ -2057,9 +2051,7 @@ impl CanvasState {
} }
// Step 2. Reset the current transformation matrix to the matrix described by: // Step 2. Reset the current transformation matrix to the matrix described by:
self.update_transform(Transform2D::new( self.update_transform(Transform2D::new(a, b, c, d, e, f))
a as f32, b as f32, c as f32, d as f32, e as f32, f as f32,
))
} }
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform-matrix> /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform-matrix>

View file

@ -462,7 +462,7 @@ pub enum Canvas2dMsg {
bool, bool,
ShadowOptions, ShadowOptions,
CompositionOptions, CompositionOptions,
Transform2D<f32>, Transform2D<f64>,
), ),
DrawEmptyImage( DrawEmptyImage(
Size2D<u32>, Size2D<u32>,
@ -470,7 +470,7 @@ pub enum Canvas2dMsg {
Rect<f64>, Rect<f64>,
ShadowOptions, ShadowOptions,
CompositionOptions, CompositionOptions,
Transform2D<f32>, Transform2D<f64>,
), ),
DrawImageInOther( DrawImageInOther(
CanvasId, CanvasId,
@ -479,10 +479,10 @@ pub enum Canvas2dMsg {
bool, bool,
ShadowOptions, ShadowOptions,
CompositionOptions, CompositionOptions,
Transform2D<f32>, Transform2D<f64>,
), ),
ClearRect(Rect<f32>, Transform2D<f32>), ClearRect(Rect<f32>, Transform2D<f64>),
ClipPath(Path, FillRule, Transform2D<f32>), ClipPath(Path, FillRule, Transform2D<f64>),
PopClips(usize), PopClips(usize),
FillPath( FillPath(
FillOrStrokeStyle, FillOrStrokeStyle,
@ -490,7 +490,7 @@ pub enum Canvas2dMsg {
FillRule, FillRule,
ShadowOptions, ShadowOptions,
CompositionOptions, CompositionOptions,
Transform2D<f32>, Transform2D<f64>,
), ),
FillText( FillText(
String, String,
@ -502,14 +502,14 @@ pub enum Canvas2dMsg {
TextOptions, TextOptions,
ShadowOptions, ShadowOptions,
CompositionOptions, CompositionOptions,
Transform2D<f32>, Transform2D<f64>,
), ),
FillRect( FillRect(
Rect<f32>, Rect<f32>,
FillOrStrokeStyle, FillOrStrokeStyle,
ShadowOptions, ShadowOptions,
CompositionOptions, CompositionOptions,
Transform2D<f32>, Transform2D<f64>,
), ),
GetImageData(Option<Rect<u32>>, IpcSender<IpcSnapshot>), GetImageData(Option<Rect<u32>>, IpcSender<IpcSnapshot>),
MeasureText(String, IpcSender<TextMetrics>, TextOptions), MeasureText(String, IpcSender<TextMetrics>, TextOptions),
@ -520,7 +520,7 @@ pub enum Canvas2dMsg {
LineOptions, LineOptions,
ShadowOptions, ShadowOptions,
CompositionOptions, CompositionOptions,
Transform2D<f32>, Transform2D<f64>,
), ),
StrokePath( StrokePath(
Path, Path,
@ -528,7 +528,7 @@ pub enum Canvas2dMsg {
LineOptions, LineOptions,
ShadowOptions, ShadowOptions,
CompositionOptions, CompositionOptions,
Transform2D<f32>, Transform2D<f64>,
), ),
UpdateImage(IpcSender<()>), UpdateImage(IpcSender<()>),
} }