canvas: Apply large size limitations (#36445)

To prevent any potential crash/OOM issues with "canvas" element
from "rogue" applications let's apply large size limitations for context
canvas2d's draw target to Servo (similar approach in Firefox/Chromium -
they limits width and height to 32767/65535 pixels).

Fixes: #36155, #34117, #30164, #24710

--
- [x] ./mach build -d does not report any errors
- [x] ./mach test-tidy does not report any errors
- [x] There are tests for these changes

tests/wpt/tests/html/canvas/element/canvas-host/2d.canvas.host.size.large.html

tests/wpt/tests/html/canvas/offscreen/canvas-host/2d.canvas.host.size.large.html

tests/wpt/tests/html/canvas/offscreen/canvas-host/2d.canvas.host.size.large.worker.js

Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
Andrei Volykhin 2025-04-29 16:48:30 +03:00 committed by GitHub
parent bd6928f3dc
commit 6b2a755736
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 87 additions and 53 deletions

View file

@ -4,7 +4,7 @@
use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg, FromScriptMsg};
use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D};
use euclid::default::Size2D;
use profile_traits::ipc;
use script_bindings::inheritance::Castable;
use script_layout_interface::HTMLCanvasDataSource;
@ -74,23 +74,12 @@ impl CanvasRenderingContext2D {
reflect_dom_object(boxed, global, can_gc)
}
// https://html.spec.whatwg.org/multipage/#concept-canvas-set-bitmap-dimensions
pub(crate) fn set_bitmap_dimensions(&self, size: Size2D<u32>) {
self.reset_to_initial_state();
self.canvas_state
.get_ipc_renderer()
.send(CanvasMsg::Recreate(
Some(size.to_u64()),
self.canvas_state.get_canvas_id(),
))
.unwrap();
}
// https://html.spec.whatwg.org/multipage/#reset-the-rendering-context-to-its-default-state
fn reset_to_initial_state(&self) {
self.canvas_state.reset_to_initial_state();
}
/// <https://html.spec.whatwg.org/multipage/#concept-canvas-set-bitmap-dimensions>
pub(crate) fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) {
self.canvas_state.set_bitmap_dimensions(size);
}
@ -106,20 +95,17 @@ impl CanvasRenderingContext2D {
pub(crate) fn send_canvas_2d_msg(&self, msg: Canvas2dMsg) {
self.canvas_state.send_canvas_2d_msg(msg)
}
pub(crate) fn get_rect(&self, rect: Rect<u32>) -> Vec<u8> {
let rect = Rect::new(
Point2D::new(rect.origin.x as u64, rect.origin.y as u64),
Size2D::new(rect.size.width as u64, rect.size.height as u64),
);
self.canvas_state.get_rect(self.canvas.size(), rect)
}
}
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())
if canvas_state.is_paintable() {
HTMLCanvasDataSource::Image(canvas_state.image_key())
} else {
HTMLCanvasDataSource::Empty
}
}
}
@ -139,13 +125,11 @@ impl CanvasContext for CanvasRenderingContext2D {
}
fn resize(&self) {
self.set_bitmap_dimensions(self.size().cast())
self.set_canvas_bitmap_dimensions(self.size().cast())
}
fn get_image_data(&self) -> Option<Snapshot> {
let size = self.size();
if size.is_empty() {
if !self.canvas_state.is_paintable() {
return None;
}