diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index e57e8308b4a..608c97ad496 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -79,12 +79,6 @@ impl<'a> CanvasPaintThread<'a> { canvas_paint_thread.canvas(canvas_id).send_pixels(chan); }, }, - Ok(CanvasMsg::FromLayout(message, canvas_id)) => match message { - FromLayoutMsg::UpdateImage(sender) => { - canvas_paint_thread.canvas(canvas_id).update_image_rendering(); - sender.send(()).unwrap(); - }, - }, Err(e) => { warn!("Error on CanvasPaintThread receive ({})", e); }, @@ -256,6 +250,10 @@ impl<'a> CanvasPaintThread<'a> { Canvas2dMsg::SetTextBaseline(text_baseline) => { self.canvas(canvas_id).set_text_baseline(text_baseline) }, + Canvas2dMsg::UpdateImage(sender) => { + self.canvas(canvas_id).update_image_rendering(); + sender.send(()).unwrap(); + }, } } diff --git a/components/layout_2020/dom.rs b/components/layout_2020/dom.rs index 78c48ddf0ae..b0323a4e56b 100644 --- a/components/layout_2020/dom.rs +++ b/components/layout_2020/dom.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::marker::PhantomData; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use base::id::{BrowsingContextId, PipelineId}; @@ -155,9 +155,7 @@ where let canvas_data = node.canvas_data()?; let source = match canvas_data.source { HTMLCanvasDataSource::WebGL(texture_id) => CanvasSource::WebGL(texture_id), - HTMLCanvasDataSource::Image((image_key, canvas_id, ipc_sender)) => { - CanvasSource::Image((image_key, canvas_id, Arc::new(Mutex::new(ipc_sender)))) - }, + HTMLCanvasDataSource::Image(image_key) => CanvasSource::Image(image_key), HTMLCanvasDataSource::WebGPU(image_key) => CanvasSource::WebGPU(image_key), HTMLCanvasDataSource::Empty => CanvasSource::Empty, }; diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index e55d12f22a1..f387b47731e 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -4,14 +4,12 @@ use std::cell::LazyCell; use std::fmt; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use app_units::Au; use base::id::{BrowsingContextId, PipelineId}; -use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg}; use data_url::DataUrl; use euclid::Size2D; -use ipc_channel::ipc::{self, IpcSender}; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use pixels::Image; use script_layout_interface::IFrameSize; @@ -98,7 +96,7 @@ impl NaturalSizes { pub(crate) enum CanvasSource { WebGL(ImageKey), - Image((ImageKey, CanvasId, Arc>>)), + Image(ImageKey), WebGPU(ImageKey), /// transparent black Empty, @@ -381,18 +379,7 @@ impl ReplacedContents { let image_key = match canvas_info.source { CanvasSource::WebGL(image_key) => image_key, CanvasSource::WebGPU(image_key) => image_key, - CanvasSource::Image((image_key, canvas_id, ref ipc_renderer)) => { - let ipc_renderer = ipc_renderer.lock().unwrap(); - let (sender, receiver) = ipc::channel().unwrap(); - ipc_renderer - .send(CanvasMsg::FromLayout( - FromLayoutMsg::UpdateImage(sender), - canvas_id, - )) - .unwrap(); - receiver.recv().unwrap(); - image_key - }, + CanvasSource::Image(image_key) => image_key, CanvasSource::Empty => return vec![], }; vec![Fragment::Image(ArcRefCell::new(ImageFragment { diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs index e2434b45006..c9e94307dd6 100644 --- a/components/script/canvas_state.rs +++ b/components/script/canvas_state.rs @@ -54,7 +54,7 @@ use crate::dom::element::{Element, cors_setting_for_element}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlcanvaselement::{CanvasContext, HTMLCanvasElement}; use crate::dom::imagedata::ImageData; -use crate::dom::node::{Node, NodeDamage, NodeTraits}; +use crate::dom::node::{Node, NodeTraits}; use crate::dom::offscreencanvas::{OffscreenCanvas, OffscreenCanvasContext}; use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope; use crate::dom::textmetrics::TextMetrics; @@ -221,6 +221,18 @@ impl CanvasState { .unwrap() } + /// Updates WR image and blocks on completion + pub(crate) fn update_rendering(&self) { + let (sender, receiver) = ipc::channel().unwrap(); + self.ipc_renderer + .send(CanvasMsg::Canvas2d( + Canvas2dMsg::UpdateImage(sender), + self.canvas_id, + )) + .unwrap(); + receiver.recv().unwrap(); + } + // https://html.spec.whatwg.org/multipage/#concept-canvas-set-bitmap-dimensions pub(crate) fn set_bitmap_dimensions(&self, size: Size2D) { self.reset_to_initial_state(); @@ -608,7 +620,7 @@ impl CanvasState { pub(crate) fn mark_as_dirty(&self, canvas: Option<&HTMLCanvasElement>) { if let Some(canvas) = canvas { - canvas.upcast::().dirty(NodeDamage::OtherNodeDamage); + canvas.mark_as_dirty(); } } diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index b134ccdf4c5..b55246500ad 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -7,6 +7,7 @@ use dom_struct::dom_struct; use euclid::default::{Point2D, Rect, Size2D}; use ipc_channel::ipc::IpcSharedMemory; use profile_traits::ipc; +use script_bindings::inheritance::Castable; use script_layout_interface::HTMLCanvasDataSource; use servo_url::ServoUrl; @@ -30,6 +31,7 @@ use crate::dom::dommatrix::DOMMatrix; use crate::dom::globalscope::GlobalScope; use crate::dom::htmlcanvaselement::HTMLCanvasElement; use crate::dom::imagedata::ImageData; +use crate::dom::node::{Node, NodeDamage, NodeTraits}; use crate::dom::textmetrics::TextMetrics; use crate::script_runtime::CanGc; @@ -116,11 +118,7 @@ impl CanvasRenderingContext2D { impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, CanvasRenderingContext2D> { fn canvas_data_source(self) -> HTMLCanvasDataSource { let canvas_state = &self.unsafe_get().canvas_state; - HTMLCanvasDataSource::Image(( - canvas_state.image_key(), - canvas_state.get_canvas_id(), - canvas_state.get_ipc_renderer().clone(), - )) + HTMLCanvasDataSource::Image(canvas_state.image_key()) } } @@ -135,6 +133,10 @@ impl CanvasContext for CanvasRenderingContext2D { self.canvas.clone() } + fn update_rendering(&self) { + self.canvas_state.update_rendering(); + } + fn resize(&self) { self.set_bitmap_dimensions(self.size().cast()) } @@ -156,7 +158,10 @@ impl CanvasContext for CanvasRenderingContext2D { } fn mark_as_dirty(&self) { - self.canvas_state.mark_as_dirty(self.canvas.canvas()) + if let Some(canvas) = self.canvas.canvas() { + canvas.upcast::().dirty(NodeDamage::OtherNodeDamage); + canvas.owner_document().add_dirty_2d_canvas(self); + } } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index e3651dd4a57..339220d3d64 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -17,6 +17,7 @@ use std::time::{Duration, Instant}; use base::cross_process_instant::CrossProcessInstant; use base::id::WebViewId; +use canvas_traits::canvas::CanvasId; use canvas_traits::webgl::{self, WebGLContextId, WebGLMsg}; use chrono::Local; use constellation_traits::{AnimationTickType, CompositorHitTestResult}; @@ -74,6 +75,7 @@ use webgpu::swapchain::WebGPUContextId; use webrender_api::units::DeviceIntRect; use super::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods; +use super::canvasrenderingcontext2d::CanvasRenderingContext2D; use super::clipboardevent::ClipboardEventType; use super::performancepainttiming::PerformancePaintTiming; use crate::DomTypes; @@ -466,6 +468,8 @@ pub(crate) struct Document { /// where `id` needs to match any of the registered ShadowRoots /// hosting the media controls UI. media_controls: DomRefCell>>, + /// List of all context 2d IDs that need flushing. + dirty_2d_contexts: DomRefCell>>, /// List of all WebGL context IDs that need flushing. dirty_webgl_contexts: DomRefCell>>, @@ -3298,6 +3302,21 @@ impl Document { receiver.recv().unwrap(); } + pub(crate) fn add_dirty_2d_canvas(&self, context: &CanvasRenderingContext2D) { + self.dirty_2d_contexts + .borrow_mut() + .entry(context.context_id()) + .or_insert_with(|| Dom::from_ref(context)); + } + + pub(crate) fn flush_dirty_2d_canvases(&self) { + self.dirty_2d_contexts + .borrow_mut() + .drain() + .filter(|(_, context)| context.onscreen()) + .for_each(|(_, context)| context.update_rendering()); + } + #[cfg(feature = "webgpu")] pub(crate) fn webgpu_contexts(&self) -> WebGPUContextsMap { self.webgpu_contexts.clone() @@ -3847,6 +3866,7 @@ impl Document { shadow_roots: DomRefCell::new(HashSet::new()), shadow_roots_styles_changed: Cell::new(false), media_controls: DomRefCell::new(HashMap::new()), + dirty_2d_contexts: DomRefCell::new(HashMapTracedValues::new()), dirty_webgl_contexts: DomRefCell::new(HashMapTracedValues::new()), #[cfg(feature = "webgpu")] webgpu_contexts: Rc::new(RefCell::new(HashMapTracedValues::new())), diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 42a526ce348..37d7aa91f90 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -180,6 +180,21 @@ impl HTMLCanvasElement { } } + pub(crate) fn mark_as_dirty(&self) { + if let Some(ref context) = *self.context.borrow() { + match *context { + CanvasContext::Context2d(ref context) => context.mark_as_dirty(), + CanvasContext::WebGL(ref context) => context.mark_as_dirty(), + CanvasContext::WebGL2(ref context) => context.mark_as_dirty(), + #[cfg(feature = "webgpu")] + CanvasContext::WebGPU(ref context) => context.mark_as_dirty(), + CanvasContext::Placeholder(ref _context) => { + // TODO: Should this be marked as dirty? + }, + } + } + } + pub(crate) fn set_natural_width(&self, value: u32, can_gc: CanGc) { let value = if value > UNSIGNED_LONG_MAX { DEFAULT_WIDTH diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs index 396d53ee330..4e0672a42a2 100644 --- a/components/script/dom/paintrenderingcontext2d.rs +++ b/components/script/dom/paintrenderingcontext2d.rs @@ -4,10 +4,8 @@ use std::cell::Cell; -use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg}; use dom_struct::dom_struct; use euclid::{Scale, Size2D}; -use ipc_channel::ipc; use script_bindings::reflector::Reflector; use servo_url::ServoUrl; use style_traits::CSSPixel; @@ -61,16 +59,9 @@ impl PaintRenderingContext2D { ) } - pub(crate) fn get_canvas_id(&self) -> CanvasId { - self.canvas_state.get_canvas_id() - } - /// Send update to canvas paint thread and returns [`ImageKey`] pub(crate) fn image_key(&self) -> ImageKey { - let (sender, receiver) = ipc::channel().unwrap(); - let msg = CanvasMsg::FromLayout(FromLayoutMsg::UpdateImage(sender), self.get_canvas_id()); - let _ = self.canvas_state.get_ipc_renderer().send(msg); - receiver.recv().unwrap(); + self.canvas_state.update_rendering(); self.canvas_state.image_key() } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 2680494290d..ecf7b39cd60 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1941,6 +1941,7 @@ impl Window { let for_display = reflow_goal.needs_display(); if for_display { document.flush_dirty_webgl_canvases(); + document.flush_dirty_2d_canvases(); } let pending_restyles = document.drain_pending_restyles(); diff --git a/components/shared/canvas/canvas.rs b/components/shared/canvas/canvas.rs index 1c04e3c9cc6..1db7675cf42 100644 --- a/components/shared/canvas/canvas.rs +++ b/components/shared/canvas/canvas.rs @@ -25,7 +25,6 @@ pub struct CanvasId(pub u64); #[derive(Debug, Deserialize, Serialize)] pub enum CanvasMsg { Canvas2d(Canvas2dMsg, CanvasId), - FromLayout(FromLayoutMsg, CanvasId), FromScript(FromScriptMsg, CanvasId), Recreate(Option>, CanvasId), Close(CanvasId), @@ -74,10 +73,6 @@ pub enum Canvas2dMsg { SetFont(FontStyleStruct), SetTextAlign(TextAlign), SetTextBaseline(TextBaseline), -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub enum FromLayoutMsg { UpdateImage(IpcSender<()>), } diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index f1c99561463..b400d531a9a 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -19,7 +19,6 @@ use app_units::Au; use atomic_refcell::AtomicRefCell; use base::Epoch; use base::id::{BrowsingContextId, PipelineId, WebViewId}; -use canvas_traits::canvas::{CanvasId, CanvasMsg}; use constellation_traits::{ScrollState, UntrustedNodeAddress, WindowSizeData}; use euclid::Size2D; use euclid::default::{Point2D, Rect}; @@ -116,7 +115,7 @@ pub enum LayoutElementType { pub enum HTMLCanvasDataSource { WebGL(ImageKey), - Image((ImageKey, CanvasId, IpcSender)), + Image(ImageKey), WebGPU(ImageKey), /// transparent black Empty,