mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
canvas: Update the image as part of update the rendering (#35996)
* Create `update_rendering` in `CanvasState` instead of manually updating in layout Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Mark as dirty and do flushes Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixup rebase Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Update components/script/dom/htmlcanvaselement.rs Co-authored-by: Martin Robinson <mrobinson@igalia.com> Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
ed995e61a6
commit
62737b3830
11 changed files with 72 additions and 51 deletions
|
@ -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<u64>) {
|
||||
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::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||
canvas.mark_as_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||
canvas.owner_document().add_dirty_2d_canvas(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<HashMap<String, Dom<ShadowRoot>>>,
|
||||
/// List of all context 2d IDs that need flushing.
|
||||
dirty_2d_contexts: DomRefCell<HashMapTracedValues<CanvasId, Dom<CanvasRenderingContext2D>>>,
|
||||
/// List of all WebGL context IDs that need flushing.
|
||||
dirty_webgl_contexts:
|
||||
DomRefCell<HashMapTracedValues<WebGLContextId, Dom<WebGLRenderingContext>>>,
|
||||
|
@ -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())),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue