canvas: Do not update ImageKey during canvas layout (#35719)

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
Samson 2025-03-12 16:36:52 +01:00 committed by GitHub
parent f31043602a
commit 6f6840d63c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 90 additions and 126 deletions

View file

@ -2,16 +2,15 @@
* 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::{
Canvas2dMsg, CanvasId, CanvasImageData, CanvasMsg, FromLayoutMsg, FromScriptMsg,
};
use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg, FromScriptMsg};
use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D};
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
use ipc_channel::ipc::IpcSharedMemory;
use profile_traits::ipc;
use script_layout_interface::HTMLCanvasDataSource;
use servo_url::ServoUrl;
use crate::canvas_context::CanvasContext;
use crate::canvas_context::{CanvasContext, LayoutCanvasRenderingContextHelpers};
use crate::canvas_state::CanvasState;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
CanvasDirection, CanvasFillRule, CanvasImageSource, CanvasLineCap, CanvasLineJoin,
@ -112,28 +111,16 @@ impl CanvasRenderingContext2D {
);
self.canvas_state.get_rect(self.canvas.size(), rect)
}
pub(crate) fn send_data(&self, sender: IpcSender<CanvasImageData>) {
let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendData(sender), self.get_canvas_id());
let _ = self.canvas_state.get_ipc_renderer().send(msg);
}
}
pub(crate) trait LayoutCanvasRenderingContext2DHelpers {
fn get_ipc_renderer(self) -> IpcSender<CanvasMsg>;
fn get_canvas_id(self) -> CanvasId;
}
impl LayoutCanvasRenderingContext2DHelpers for LayoutDom<'_, CanvasRenderingContext2D> {
fn get_ipc_renderer(self) -> IpcSender<CanvasMsg> {
(self.unsafe_get()).canvas_state.get_ipc_renderer().clone()
}
fn get_canvas_id(self) -> CanvasId {
// FIXME(nox): This relies on the fact that CanvasState::get_canvas_id
// does nothing fancy but it would be easier to trust a
// LayoutDom<_>-like type that would wrap the &CanvasState.
self.unsafe_get().canvas_state.get_canvas_id()
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(),
))
}
}

View file

@ -6,7 +6,6 @@ use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use canvas_traits::canvas::CanvasId;
use canvas_traits::webgl::{GLContextAttributes, WebGLVersion};
use dom_struct::dom_struct;
use euclid::default::Size2D;
@ -48,9 +47,7 @@ use crate::dom::bindings::reflector::{DomGlobal, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, ToLayout};
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::blob::Blob;
use crate::dom::canvasrenderingcontext2d::{
CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers,
};
use crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
use crate::dom::document::Document;
use crate::dom::element::{AttributeMutation, Element, LayoutElementHelpers};
#[cfg(not(feature = "webgpu"))]
@ -208,9 +205,7 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
fn data(self) -> HTMLCanvasData {
let source = unsafe {
match self.unsafe_get().context.borrow_for_layout().as_ref() {
Some(CanvasContext::Context2d(context)) => {
HTMLCanvasDataSource::Image(context.to_layout().get_ipc_renderer())
},
Some(CanvasContext::Context2d(context)) => context.to_layout().canvas_data_source(),
Some(CanvasContext::WebGL(context)) => context.to_layout().canvas_data_source(),
Some(CanvasContext::WebGL2(context)) => context.to_layout().canvas_data_source(),
#[cfg(feature = "webgpu")]
@ -229,20 +224,6 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
source,
width: width_attr.map_or(DEFAULT_WIDTH, |val| val.as_uint()),
height: height_attr.map_or(DEFAULT_HEIGHT, |val| val.as_uint()),
canvas_id: self.get_canvas_id_for_layout(),
}
}
#[allow(unsafe_code)]
fn get_canvas_id_for_layout(self) -> CanvasId {
let canvas = self.unsafe_get();
unsafe {
if let &Some(CanvasContext::Context2d(ref context)) = canvas.context.borrow_for_layout()
{
context.to_layout().get_canvas_id()
} else {
CanvasId(0)
}
}
}
}

View file

@ -4,13 +4,14 @@
use std::cell::Cell;
use canvas_traits::canvas::{CanvasId, CanvasImageData, CanvasMsg, FromLayoutMsg};
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg};
use dom_struct::dom_struct;
use euclid::{Scale, Size2D};
use ipc_channel::ipc::IpcSender;
use ipc_channel::ipc;
use script_bindings::reflector::Reflector;
use servo_url::ServoUrl;
use style_traits::CSSPixel;
use webrender_api::ImageKey;
use webrender_api::units::DevicePixel;
use super::bindings::reflector::DomGlobal as _;
@ -64,9 +65,13 @@ impl PaintRenderingContext2D {
self.canvas_state.get_canvas_id()
}
pub(crate) fn send_data(&self, sender: IpcSender<CanvasImageData>) {
let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendData(sender), self.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.image_key()
}
pub(crate) fn take_missing_image_urls(&self) -> Vec<ServoUrl> {

View file

@ -23,7 +23,6 @@ use js::rust::wrappers::{Call, Construct1};
use js::rust::{HandleValue, Runtime};
use net_traits::image_cache::ImageCache;
use pixels::PixelFormat;
use profile_traits::ipc;
use script_traits::{DrawAPaintImageResult, PaintWorkletError, Painter};
use servo_config::pref;
use servo_url::ServoUrl;
@ -40,7 +39,7 @@ use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
use crate::dom::bindings::conversions::{get_property, get_property_jsval};
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{DomGlobal, DomObject};
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::cssstylevalue::CSSStyleValue;
@ -354,19 +353,13 @@ impl PaintWorkletGlobalScope {
return self.invalid_image(size_in_dpx, missing_image_urls);
}
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone())
.expect("IPC channel creation.");
rendering_context.send_data(sender);
let image_key = match receiver.recv() {
Ok(data) => Some(data.image_key),
_ => None,
};
let image_key = rendering_context.image_key();
DrawAPaintImageResult {
width: size_in_dpx.width,
height: size_in_dpx.height,
format: PixelFormat::BGRA8,
image_key,
image_key: Some(image_key),
missing_image_urls,
}
}