From d1f7a906195b81daa8a5120f6c1a25a0cbd9fcdc Mon Sep 17 00:00:00 2001 From: sagudev <16504129+sagudev@users.noreply.github.com> Date: Thu, 1 May 2025 11:57:20 +0200 Subject: [PATCH] canvas: Move `CompositionOrBlending` and `ellipse()` from `RaqoteBackend` to `Backend` (#36790) Small fixes of abstraction. We do not need to generalize `CompositionOrBlending`, because it's from canvas_traits. Ellipse impl that uses arc is not backend specific, so it serves as good trait default. Reviewable per commit. Testing: Only refactoring, but there are WPT tests --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --- components/canvas/backend.rs | 58 ++++++++++++++++++++++++-- components/canvas/canvas_data.rs | 2 +- components/canvas/raqote_backend.rs | 64 ++--------------------------- 3 files changed, 58 insertions(+), 66 deletions(-) diff --git a/components/canvas/backend.rs b/components/canvas/backend.rs index c83eebe3bee..f94636079a6 100644 --- a/components/canvas/backend.rs +++ b/components/canvas/backend.rs @@ -2,8 +2,12 @@ * 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::{FillOrStrokeStyle, LineCapStyle, LineJoinStyle}; +use canvas_traits::canvas::{ + CompositionOrBlending, FillOrStrokeStyle, LineCapStyle, LineJoinStyle, +}; +use euclid::Angle; use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; +use lyon_geom::Arc; use style::color::AbsoluteColor; use crate::canvas_data::{CanvasPaintState, Filter, TextRun}; @@ -14,7 +18,6 @@ pub(crate) trait Backend: Clone + Sized { type Color: Clone; type DrawOptions: DrawOptionsHelpers + Clone; type CompositionOp; - type CompositionOrBlending; type DrawTarget: GenericDrawTarget; type PathBuilder: GenericPathBuilder; type SourceSurface; @@ -39,7 +42,7 @@ pub(crate) trait Backend: Clone + Sized { ); fn set_global_composition( &mut self, - op: Self::CompositionOrBlending, + op: CompositionOrBlending, state: &mut CanvasPaintState<'_, Self>, ); fn create_drawtarget(&self, size: Size2D) -> Self::DrawTarget; @@ -148,7 +151,54 @@ pub(crate) trait GenericPathBuilder { start_angle: f32, end_angle: f32, anticlockwise: bool, - ); + ) { + let mut start = Angle::radians(start_angle); + let mut end = Angle::radians(end_angle); + + // Wrap angles mod 2 * PI if necessary + if !anticlockwise && start > end + Angle::two_pi() || + anticlockwise && end > start + Angle::two_pi() + { + start = start.positive(); + end = end.positive(); + } + + // Calculate the total arc we're going to sweep. + let sweep = match anticlockwise { + true => { + if end - start == Angle::two_pi() { + -Angle::two_pi() + } else if end > start { + -(Angle::two_pi() - (end - start)) + } else { + -(start - end) + } + }, + false => { + if start - end == Angle::two_pi() { + Angle::two_pi() + } else if start > end { + Angle::two_pi() - (start - end) + } else { + end - start + } + }, + }; + + let arc: Arc = Arc { + center: origin, + radii: Vector2D::new(radius_x, radius_y), + start_angle: start, + sweep_angle: sweep, + x_rotation: Angle::radians(rotation_angle), + }; + + self.line_to(arc.from()); + + arc.for_each_quadratic_bezier(&mut |q| { + self.quadratic_curve_to(&q.ctrl, &q.to); + }); + } fn get_current_point(&mut self) -> Option>; fn line_to(&mut self, point: Point2D); fn move_to(&mut self, point: Point2D); diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 7d8b4a9cdbc..0856583cea3 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -1183,7 +1183,7 @@ impl<'a, B: Backend> CanvasData<'a, B> { self.state.draw_options.set_alpha(alpha); } - pub(crate) fn set_global_composition(&mut self, op: B::CompositionOrBlending) { + pub(crate) fn set_global_composition(&mut self, op: CompositionOrBlending) { self.backend.set_global_composition(op, &mut self.state); } diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index e88de701336..344d42dec6c 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -7,12 +7,10 @@ use std::collections::HashMap; use canvas_traits::canvas::*; use cssparser::color::clamp_unit_f32; -use euclid::Angle; use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; use font_kit::font::Font; use fonts::{ByteIndex, FontIdentifier, FontTemplateRefMethods}; use log::warn; -use lyon_geom::Arc; use range::Range; use raqote::PathOp; use style::color::AbsoluteColor; @@ -40,7 +38,6 @@ impl Backend for RaqoteBackend { type Color = raqote::SolidSource; type DrawOptions = raqote::DrawOptions; type CompositionOp = raqote::BlendMode; - type CompositionOrBlending = CompositionOrBlending; type DrawTarget = raqote::DrawTarget; type PathBuilder = PathBuilder; type SourceSurface = Vec; // TODO: See if we can avoid the alloc (probably?) @@ -84,7 +81,7 @@ impl Backend for RaqoteBackend { fn set_global_composition( &mut self, - op: Self::CompositionOrBlending, + op: CompositionOrBlending, state: &mut CanvasPaintState<'_, Self>, ) { state.draw_options.blend_mode = op.to_raqote_style(); @@ -701,6 +698,7 @@ impl GenericPathBuilder for PathBuilder { anticlockwise, ); } + fn bezier_curve_to( &mut self, control_point1: &Point2D, @@ -716,66 +714,10 @@ impl GenericPathBuilder for PathBuilder { control_point3.y, ); } + fn close(&mut self) { self.0.as_mut().unwrap().close(); } - fn ellipse( - &mut self, - origin: Point2D, - radius_x: f32, - radius_y: f32, - rotation_angle: f32, - start_angle: f32, - end_angle: f32, - anticlockwise: bool, - ) { - let mut start = Angle::radians(start_angle); - let mut end = Angle::radians(end_angle); - - // Wrap angles mod 2 * PI if necessary - if !anticlockwise && start > end + Angle::two_pi() || - anticlockwise && end > start + Angle::two_pi() - { - start = start.positive(); - end = end.positive(); - } - - // Calculate the total arc we're going to sweep. - let sweep = match anticlockwise { - true => { - if end - start == Angle::two_pi() { - -Angle::two_pi() - } else if end > start { - -(Angle::two_pi() - (end - start)) - } else { - -(start - end) - } - }, - false => { - if start - end == Angle::two_pi() { - Angle::two_pi() - } else if start > end { - Angle::two_pi() - (start - end) - } else { - end - start - } - }, - }; - - let arc: Arc = Arc { - center: origin, - radii: Vector2D::new(radius_x, radius_y), - start_angle: start, - sweep_angle: sweep, - x_rotation: Angle::radians(rotation_angle), - }; - - self.line_to(arc.from()); - - arc.for_each_quadratic_bezier(&mut |q| { - self.quadratic_curve_to(&q.ctrl, &q.to); - }); - } fn svg_arc( &mut self,