From 420a5a64a7d485d5eeb9259952c271e7883ddb36 Mon Sep 17 00:00:00 2001 From: sagudev <16504129+sagudev@users.noreply.github.com> Date: Fri, 25 Jul 2025 14:05:03 +0200 Subject: [PATCH] canvas: Remove `Backend` trait (#38262) After #38214 `Backend` trait is only used as DrawTarget builder and as type holder. By moving types and DrawTarget creation into `GenericDrawTarget` trait, we can completely remove `Backend` trait. Testing: Just refactor, but code is covered by WPT tests. Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --- components/canvas/backend.rs | 25 ++++++------ components/canvas/canvas_data.rs | 37 ++++++++---------- components/canvas/canvas_paint_thread.rs | 11 ++---- components/canvas/raqote_backend.rs | 50 ++++++++---------------- 4 files changed, 46 insertions(+), 77 deletions(-) diff --git a/components/canvas/backend.rs b/components/canvas/backend.rs index be31e6ed982..be2d0158870 100644 --- a/components/canvas/backend.rs +++ b/components/canvas/backend.rs @@ -12,28 +12,25 @@ use webrender_api::ImageDescriptor; use crate::canvas_data::{Filter, TextRun}; -pub(crate) trait Backend: Clone + Sized { - type DrawTarget: GenericDrawTarget; - type SourceSurface; - - fn create_drawtarget(&self, size: Size2D) -> Self::DrawTarget; -} - // This defines required methods for a DrawTarget (currently only implemented for raqote). The // prototypes are derived from the now-removed Azure backend's methods. -pub(crate) trait GenericDrawTarget { +pub(crate) trait GenericDrawTarget { + type SourceSurface; + + fn new(size: Size2D) -> Self; + fn create_similar_draw_target(&self, size: &Size2D) -> Self; + fn clear_rect(&mut self, rect: &Rect, transform: Transform2D); fn copy_surface( &mut self, - surface: B::SourceSurface, + surface: Self::SourceSurface, source: Rect, destination: Point2D, ); - fn create_similar_draw_target(&self, size: &Size2D) -> Self; - fn create_source_surface_from_data(&self, data: Snapshot) -> Option; + fn create_source_surface_from_data(&self, data: Snapshot) -> Option; fn draw_surface( &mut self, - surface: B::SourceSurface, + surface: Self::SourceSurface, dest: Rect, source: Rect, filter: Filter, @@ -42,7 +39,7 @@ pub(crate) trait GenericDrawTarget { ); fn draw_surface_with_shadow( &self, - surface: B::SourceSurface, + surface: Self::SourceSurface, dest: &Point2D, shadow_options: ShadowOptions, composition_options: CompositionOptions, @@ -89,7 +86,7 @@ pub(crate) trait GenericDrawTarget { composition_options: CompositionOptions, transform: Transform2D, ); - fn surface(&self) -> B::SourceSurface; + fn surface(&self) -> Self::SourceSurface; fn image_descriptor_and_serializable_data(&self) -> (ImageDescriptor, SerializableImageData); fn snapshot(&self) -> Snapshot; } diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 594d2777fd2..2f98dbc4ff0 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -20,7 +20,7 @@ use range::Range; use unicode_script::Script; use webrender_api::ImageKey; -use crate::backend::{Backend, GenericDrawTarget as _}; +use crate::backend::GenericDrawTarget; // Asserts on WR texture cache update for zero sized image with raw data. // https://github.com/servo/webrender/blob/main/webrender/src/texture_cache.rs#L1475 @@ -102,28 +102,25 @@ pub(crate) enum Filter { Nearest, } -pub(crate) struct CanvasData { - backend: B, - drawtarget: B::DrawTarget, +pub(crate) struct CanvasData { + drawtarget: DrawTarget, compositor_api: CrossProcessCompositorApi, image_key: ImageKey, font_context: Arc, } -impl CanvasData { +impl CanvasData { pub(crate) fn new( size: Size2D, compositor_api: CrossProcessCompositorApi, font_context: Arc, - backend: B, - ) -> CanvasData { + ) -> CanvasData { let size = size.max(MIN_WR_IMAGE_SIZE); - let draw_target = backend.create_drawtarget(size); + let draw_target = DrawTarget::new(size.cast()); let image_key = compositor_api.generate_image_key_blocking().unwrap(); let (descriptor, data) = draw_target.image_descriptor_and_serializable_data(); compositor_api.add_image(image_key, descriptor, data); CanvasData { - backend, drawtarget: draw_target, compositor_api, image_key, @@ -155,8 +152,8 @@ impl CanvasData { snapshot }; - let writer = |draw_target: &mut B::DrawTarget, transform| { - write_image::( + let writer = |draw_target: &mut DrawTarget, transform| { + write_image::( draw_target, snapshot, dest_rect, @@ -496,7 +493,7 @@ impl CanvasData { shadow_options, composition_options, transform, - |new_draw_target: &mut B::DrawTarget, transform| { + |new_draw_target, transform| { new_draw_target.fill_rect(rect, style, composition_options, transform); }, ); @@ -538,7 +535,7 @@ impl CanvasData { shadow_options, composition_options, transform, - |new_draw_target: &mut B::DrawTarget, transform| { + |new_draw_target, transform| { new_draw_target.stroke_rect( rect, style, @@ -629,9 +626,7 @@ impl CanvasData { .max(MIN_WR_IMAGE_SIZE); // Step 1. Clear canvas's bitmap to transparent black. - self.drawtarget = self - .backend - .create_drawtarget(Size2D::new(size.width, size.height)); + self.drawtarget = DrawTarget::new(Size2D::new(size.width, size.height).cast()); self.update_image_rendering(); } @@ -658,7 +653,7 @@ impl CanvasData { ); } - fn create_draw_target_for_shadow(&self, source_rect: &Rect) -> B::DrawTarget { + fn create_draw_target_for_shadow(&self, source_rect: &Rect) -> DrawTarget { self.drawtarget.create_similar_draw_target(&Size2D::new( source_rect.size.width as i32, source_rect.size.height as i32, @@ -673,7 +668,7 @@ impl CanvasData { transform: Transform2D, draw_shadow_source: F, ) where - F: FnOnce(&mut B::DrawTarget, Transform2D), + F: FnOnce(&mut DrawTarget, Transform2D), { let shadow_src_rect = transform.outer_transformed_rect(rect); let mut new_draw_target = self.create_draw_target_for_shadow(&shadow_src_rect); @@ -755,7 +750,7 @@ impl CanvasData { } } -impl Drop for CanvasData { +impl Drop for CanvasData { fn drop(&mut self) { self.compositor_api.delete_image(self.image_key); } @@ -771,8 +766,8 @@ const IDEOGRAPHIC_BASELINE_DEFAULT: f32 = 0.5; /// dest_rect: Area of the destination target where the pixels will be copied /// smoothing_enabled: It determines if smoothing is applied to the image result /// premultiply: Determines whenever the image data should be premultiplied or not -fn write_image( - draw_target: &mut B::DrawTarget, +fn write_image( + draw_target: &mut DrawTarget, snapshot: Snapshot, dest_rect: Rect, smoothing_enabled: bool, diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 2c933ecc82b..9d6f72d0a48 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -23,7 +23,6 @@ use pixels::Snapshot; use webrender_api::ImageKey; use crate::canvas_data::*; -use crate::raqote_backend::RaqoteBackend; pub struct CanvasPaintThread { canvases: HashMap, @@ -120,12 +119,8 @@ impl CanvasPaintThread { let canvas_id = self.next_canvas_id; self.next_canvas_id.0 += 1; - let canvas_data = CanvasData::new( - size, - self.compositor_api.clone(), - self.font_context.clone(), - RaqoteBackend, - ); + let canvas_data = + CanvasData::new(size, self.compositor_api.clone(), self.font_context.clone()); let image_key = canvas_data.image_key(); self.canvases.insert(canvas_id, Canvas::Raqote(canvas_data)); @@ -301,7 +296,7 @@ impl CanvasPaintThread { } enum Canvas { - Raqote(CanvasData), + Raqote(CanvasData), } impl Canvas { diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index 35e5f702cd1..7c539550658 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -19,7 +19,7 @@ use raqote::{DrawOptions, PathBuilder, StrokeStyle}; use style::color::AbsoluteColor; use webrender_api::{ImageDescriptor, ImageDescriptorFlags, ImageFormat}; -use crate::backend::{Backend, GenericDrawTarget}; +use crate::backend::GenericDrawTarget; use crate::canvas_data::{Filter, TextRun}; thread_local! { @@ -30,18 +30,6 @@ thread_local! { static SHARED_FONT_CACHE: RefCell> = RefCell::default(); } -#[derive(Clone, Default)] -pub(crate) struct RaqoteBackend; - -impl Backend for RaqoteBackend { - type DrawTarget = raqote::DrawTarget; - type SourceSurface = Vec; // TODO: See if we can avoid the alloc (probably?) - - fn create_drawtarget(&self, size: Size2D) -> Self::DrawTarget { - raqote::DrawTarget::new(size.width as i32, size.height as i32) - } -} - #[derive(Clone)] pub enum Pattern { // argb @@ -199,9 +187,15 @@ fn create_gradient_stops(gradient_stops: Vec) -> Vec for raqote::DrawTarget { +impl GenericDrawTarget for raqote::DrawTarget { + type SourceSurface = Vec; // TODO: See if we can avoid the alloc (probably?) + + fn new(size: Size2D) -> Self { + raqote::DrawTarget::new(size.width as i32, size.height as i32) + } + fn clear_rect(&mut self, rect: &Rect, transform: Transform2D) { - >::fill_rect( + ::fill_rect( self, rect, FillOrStrokeStyle::Color(AbsoluteColor::TRANSPARENT_BLACK), @@ -215,7 +209,7 @@ impl GenericDrawTarget for raqote::DrawTarget { #[allow(unsafe_code)] fn copy_surface( &mut self, - surface: ::SourceSurface, + surface: Self::SourceSurface, source: Rect, destination: Point2D, ) { @@ -226,16 +220,10 @@ impl GenericDrawTarget for raqote::DrawTarget { raqote::DrawTarget::copy_surface(self, &dt, source.to_box2d(), destination); } - fn create_similar_draw_target( - &self, - size: &Size2D, - ) -> ::DrawTarget { + fn create_similar_draw_target(&self, size: &Size2D) -> Self { raqote::DrawTarget::new(size.width, size.height) } - fn create_source_surface_from_data( - &self, - data: Snapshot, - ) -> Option<::SourceSurface> { + fn create_source_surface_from_data(&self, data: Snapshot) -> Option { Some( data.to_vec( Some(SnapshotAlphaMode::Transparent { @@ -249,7 +237,7 @@ impl GenericDrawTarget for raqote::DrawTarget { #[allow(unsafe_code)] fn draw_surface( &mut self, - surface: ::SourceSurface, + surface: Self::SourceSurface, dest: Rect, src: Rect, filter: Filter, @@ -297,7 +285,7 @@ impl GenericDrawTarget for raqote::DrawTarget { } fn draw_surface_with_shadow( &self, - _surface: ::SourceSurface, + _surface: Self::SourceSurface, _dest: &Point2D, _shadow_options: ShadowOptions, _composition_options: CompositionOptions, @@ -398,13 +386,7 @@ impl GenericDrawTarget for raqote::DrawTarget { rect.size.height, ); - >::fill( - self, - &pb, - style, - composition_options, - transform, - ); + ::fill(self, &pb, style, composition_options, transform); } fn get_size(&self) -> Size2D { Size2D::new(self.width(), self.height()) @@ -419,7 +401,7 @@ impl GenericDrawTarget for raqote::DrawTarget { fn push_clip_rect(&mut self, rect: &Rect) { self.push_clip_rect(rect.to_box2d()); } - fn surface(&self) -> ::SourceSurface { + fn surface(&self) -> Self::SourceSurface { self.get_data_u8().to_vec() } fn stroke(