script: Move canvas stuff into dom/canvas folder (#39071)

Move all canvas stuff to canvas folder and 2d canvas to canvas/2d
folder. Webgl and webgpu context remain in respective folders as
outlined in
https://github.com/servo/servo/issues/38901#issuecomment-3243020235

Testing: Just refactor.
Part of https://github.com/servo/servo/issues/38901

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
Sam 2025-09-02 09:43:10 +02:00 committed by GitHub
parent f4dd2960b8
commit 069ddbfd12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 138 additions and 124 deletions

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ use canvas_traits::canvas::{
};
use dom_struct::dom_struct;
use crate::canvas_state::parse_color;
use super::canvas_state::parse_color;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasGradientMethods;
use crate::dom::bindings::error::{Error, ErrorResult};

View file

@ -12,8 +12,8 @@ use script_bindings::inheritance::Castable;
use servo_url::ServoUrl;
use webrender_api::ImageKey;
use super::canvas_state::CanvasState;
use crate::canvas_context::{CanvasContext, CanvasHelpers, LayoutCanvasRenderingContextHelpers};
use crate::canvas_state::CanvasState;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
CanvasDirection, CanvasFillRule, CanvasImageSource, CanvasLineCap, CanvasLineJoin,
CanvasRenderingContext2DMethods, CanvasTextAlign, CanvasTextBaseline,

View file

@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
mod canvas_state;
pub(crate) mod canvasgradient;
pub(crate) mod canvaspattern;
#[allow(dead_code)]
pub(crate) mod canvasrenderingcontext2d;
pub(crate) mod offscreencanvasrenderingcontext2d;
pub(crate) mod paintrenderingcontext2d;
pub(crate) mod path2d;
pub(crate) mod textmetrics;

View file

@ -12,8 +12,7 @@ use style_traits::CSSPixel;
use webrender_api::ImageKey;
use webrender_api::units::DevicePixel;
use super::bindings::reflector::DomGlobal as _;
use crate::canvas_state::CanvasState;
use super::canvas_state::CanvasState;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
CanvasFillRule, CanvasImageSource, CanvasLineCap, CanvasLineJoin,
};
@ -23,7 +22,7 @@ use crate::dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPat
use crate::dom::bindings::error::{ErrorResult, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::reflector::{DomGlobal as _, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::canvasgradient::CanvasGradient;

View file

@ -0,0 +1,377 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//! Common interfaces for Canvas Contexts
use base::Epoch;
use euclid::default::Size2D;
use layout_api::HTMLCanvasData;
use pixels::Snapshot;
use script_bindings::root::{Dom, DomRoot};
use webrender_api::ImageKey;
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::node::{Node, NodeDamage};
#[cfg(feature = "webgpu")]
use crate::dom::types::GPUCanvasContext;
use crate::dom::types::{
CanvasRenderingContext2D, ImageBitmapRenderingContext, OffscreenCanvas,
OffscreenCanvasRenderingContext2D, WebGL2RenderingContext, WebGLRenderingContext,
};
pub(crate) trait LayoutCanvasRenderingContextHelpers {
/// `None` is rendered as transparent black (cleared canvas)
fn canvas_data_source(self) -> Option<ImageKey>;
}
pub(crate) trait LayoutHTMLCanvasElementHelpers {
fn data(self) -> HTMLCanvasData;
}
pub(crate) trait CanvasContext {
type ID;
fn context_id(&self) -> Self::ID;
fn canvas(&self) -> Option<HTMLCanvasElementOrOffscreenCanvas>;
fn resize(&self);
// Resets the backing bitmap (to transparent or opaque black) without the
// context state reset.
// Used by OffscreenCanvas.transferToImageBitmap.
fn reset_bitmap(&self);
/// Returns none if area of canvas is zero.
///
/// In case of other errors it returns cleared snapshot
fn get_image_data(&self) -> Option<Snapshot>;
fn origin_is_clean(&self) -> bool {
true
}
fn size(&self) -> Size2D<u32> {
self.canvas()
.map(|canvas| canvas.size())
.unwrap_or_default()
}
fn mark_as_dirty(&self) {
if let Some(HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas)) = &self.canvas()
{
canvas.upcast::<Node>().dirty(NodeDamage::Other);
}
}
/// The WebRender [`ImageKey`] of this [`CanvasContext`] if any.
fn image_key(&self) -> Option<ImageKey>;
/// Request that the [`CanvasContext`] update the rendering of its contents,
/// returning `true` if new image was produced.
fn update_rendering(&self, _canvas_epoch: Epoch) -> bool {
false
}
fn onscreen(&self) -> bool {
let Some(canvas) = self.canvas() else {
return false;
};
match canvas {
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(ref canvas) => {
canvas.upcast::<Node>().is_connected()
},
// FIXME(34628): Offscreen canvases should be considered offscreen if a placeholder is set.
// <https://www.w3.org/TR/webgpu/#abstract-opdef-updating-the-rendering-of-a-webgpu-canvas>
HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(_) => false,
}
}
}
pub(crate) trait CanvasHelpers {
fn size(&self) -> Size2D<u32>;
fn canvas(&self) -> Option<DomRoot<HTMLCanvasElement>>;
}
impl CanvasHelpers for HTMLCanvasElementOrOffscreenCanvas {
fn size(&self) -> Size2D<u32> {
match self {
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => {
canvas.get_size().cast()
},
HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas) => canvas.get_size(),
}
}
fn canvas(&self) -> Option<DomRoot<HTMLCanvasElement>> {
match self {
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => Some(canvas.clone()),
HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas) => canvas.placeholder(),
}
}
}
/// Non rooted variant of [`crate::dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::RenderingContext`]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
#[derive(Clone, JSTraceable, MallocSizeOf)]
pub(crate) enum RenderingContext {
Placeholder(Dom<OffscreenCanvas>),
Context2d(Dom<CanvasRenderingContext2D>),
BitmapRenderer(Dom<ImageBitmapRenderingContext>),
WebGL(Dom<WebGLRenderingContext>),
WebGL2(Dom<WebGL2RenderingContext>),
#[cfg(feature = "webgpu")]
WebGPU(Dom<GPUCanvasContext>),
}
impl CanvasContext for RenderingContext {
type ID = ();
fn context_id(&self) -> Self::ID {}
fn canvas(&self) -> Option<HTMLCanvasElementOrOffscreenCanvas> {
match self {
RenderingContext::Placeholder(offscreen_canvas) => offscreen_canvas.context()?.canvas(),
RenderingContext::Context2d(context) => context.canvas(),
RenderingContext::BitmapRenderer(context) => context.canvas(),
RenderingContext::WebGL(context) => context.canvas(),
RenderingContext::WebGL2(context) => context.canvas(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.canvas(),
}
}
fn resize(&self) {
match self {
RenderingContext::Placeholder(offscreen_canvas) => {
if let Some(context) = offscreen_canvas.context() {
context.resize()
}
},
RenderingContext::Context2d(context) => context.resize(),
RenderingContext::BitmapRenderer(context) => context.resize(),
RenderingContext::WebGL(context) => context.resize(),
RenderingContext::WebGL2(context) => context.resize(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.resize(),
}
}
fn reset_bitmap(&self) {
match self {
RenderingContext::Placeholder(offscreen_canvas) => {
if let Some(context) = offscreen_canvas.context() {
context.reset_bitmap()
}
},
RenderingContext::Context2d(context) => context.reset_bitmap(),
RenderingContext::BitmapRenderer(context) => context.reset_bitmap(),
RenderingContext::WebGL(context) => context.reset_bitmap(),
RenderingContext::WebGL2(context) => context.reset_bitmap(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.reset_bitmap(),
}
}
fn get_image_data(&self) -> Option<Snapshot> {
match self {
RenderingContext::Placeholder(offscreen_canvas) => {
offscreen_canvas.context()?.get_image_data()
},
RenderingContext::Context2d(context) => context.get_image_data(),
RenderingContext::BitmapRenderer(context) => context.get_image_data(),
RenderingContext::WebGL(context) => context.get_image_data(),
RenderingContext::WebGL2(context) => context.get_image_data(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.get_image_data(),
}
}
fn origin_is_clean(&self) -> bool {
match self {
RenderingContext::Placeholder(offscreen_canvas) => offscreen_canvas
.context()
.is_none_or(|context| context.origin_is_clean()),
RenderingContext::Context2d(context) => context.origin_is_clean(),
RenderingContext::BitmapRenderer(context) => context.origin_is_clean(),
RenderingContext::WebGL(context) => context.origin_is_clean(),
RenderingContext::WebGL2(context) => context.origin_is_clean(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.origin_is_clean(),
}
}
fn size(&self) -> Size2D<u32> {
match self {
RenderingContext::Placeholder(offscreen_canvas) => offscreen_canvas
.context()
.map(|context| context.size())
.unwrap_or_default(),
RenderingContext::Context2d(context) => context.size(),
RenderingContext::BitmapRenderer(context) => context.size(),
RenderingContext::WebGL(context) => context.size(),
RenderingContext::WebGL2(context) => context.size(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.size(),
}
}
fn mark_as_dirty(&self) {
match self {
RenderingContext::Placeholder(offscreen_canvas) => {
if let Some(context) = offscreen_canvas.context() {
context.mark_as_dirty()
}
},
RenderingContext::Context2d(context) => context.mark_as_dirty(),
RenderingContext::BitmapRenderer(context) => context.mark_as_dirty(),
RenderingContext::WebGL(context) => context.mark_as_dirty(),
RenderingContext::WebGL2(context) => context.mark_as_dirty(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.mark_as_dirty(),
}
}
fn image_key(&self) -> Option<ImageKey> {
match self {
RenderingContext::Placeholder(offscreen_canvas) => offscreen_canvas
.context()
.and_then(|context| context.image_key()),
RenderingContext::Context2d(context) => context.image_key(),
RenderingContext::BitmapRenderer(context) => context.image_key(),
RenderingContext::WebGL(context) => context.image_key(),
RenderingContext::WebGL2(context) => context.image_key(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.image_key(),
}
}
fn update_rendering(&self, canvas_epoch: Epoch) -> bool {
match self {
RenderingContext::Placeholder(offscreen_canvas) => offscreen_canvas
.context()
.is_some_and(|context| context.update_rendering(canvas_epoch)),
RenderingContext::Context2d(context) => context.update_rendering(canvas_epoch),
RenderingContext::BitmapRenderer(context) => context.update_rendering(canvas_epoch),
RenderingContext::WebGL(context) => context.update_rendering(canvas_epoch),
RenderingContext::WebGL2(context) => context.update_rendering(canvas_epoch),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.update_rendering(canvas_epoch),
}
}
fn onscreen(&self) -> bool {
match self {
RenderingContext::Placeholder(offscreen_canvas) => offscreen_canvas
.context()
.is_some_and(|context| context.onscreen()),
RenderingContext::Context2d(context) => context.onscreen(),
RenderingContext::BitmapRenderer(context) => context.onscreen(),
RenderingContext::WebGL(context) => context.onscreen(),
RenderingContext::WebGL2(context) => context.onscreen(),
#[cfg(feature = "webgpu")]
RenderingContext::WebGPU(context) => context.onscreen(),
}
}
}
/// Non rooted variant of [`crate::dom::bindings::codegen::Bindings::OffscreenCanvasBinding::OffscreenRenderingContext`]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
#[derive(Clone, JSTraceable, MallocSizeOf)]
pub(crate) enum OffscreenRenderingContext {
Context2d(Dom<OffscreenCanvasRenderingContext2D>),
BitmapRenderer(Dom<ImageBitmapRenderingContext>),
// WebGL(Dom<WebGLRenderingContext>),
// WebGL2(Dom<WebGL2RenderingContext>),
// #[cfg(feature = "webgpu")]
// WebGPU(Dom<GPUCanvasContext>),
Detached,
}
impl CanvasContext for OffscreenRenderingContext {
type ID = ();
fn context_id(&self) -> Self::ID {}
fn canvas(&self) -> Option<HTMLCanvasElementOrOffscreenCanvas> {
match self {
OffscreenRenderingContext::Context2d(context) => context.canvas(),
OffscreenRenderingContext::BitmapRenderer(context) => context.canvas(),
OffscreenRenderingContext::Detached => None,
}
}
fn resize(&self) {
match self {
OffscreenRenderingContext::Context2d(context) => context.resize(),
OffscreenRenderingContext::BitmapRenderer(context) => context.resize(),
OffscreenRenderingContext::Detached => {},
}
}
fn reset_bitmap(&self) {
match self {
OffscreenRenderingContext::Context2d(context) => context.reset_bitmap(),
OffscreenRenderingContext::BitmapRenderer(context) => context.reset_bitmap(),
OffscreenRenderingContext::Detached => {},
}
}
fn get_image_data(&self) -> Option<Snapshot> {
match self {
OffscreenRenderingContext::Context2d(context) => context.get_image_data(),
OffscreenRenderingContext::BitmapRenderer(context) => context.get_image_data(),
OffscreenRenderingContext::Detached => None,
}
}
fn origin_is_clean(&self) -> bool {
match self {
OffscreenRenderingContext::Context2d(context) => context.origin_is_clean(),
OffscreenRenderingContext::BitmapRenderer(context) => context.origin_is_clean(),
OffscreenRenderingContext::Detached => true,
}
}
fn size(&self) -> Size2D<u32> {
match self {
OffscreenRenderingContext::Context2d(context) => context.size(),
OffscreenRenderingContext::BitmapRenderer(context) => context.size(),
OffscreenRenderingContext::Detached => Size2D::default(),
}
}
fn mark_as_dirty(&self) {
match self {
OffscreenRenderingContext::Context2d(context) => context.mark_as_dirty(),
OffscreenRenderingContext::BitmapRenderer(context) => context.mark_as_dirty(),
OffscreenRenderingContext::Detached => {},
}
}
fn image_key(&self) -> Option<ImageKey> {
None
}
fn update_rendering(&self, canvas_epoch: Epoch) -> bool {
match self {
OffscreenRenderingContext::Context2d(context) => context.update_rendering(canvas_epoch),
OffscreenRenderingContext::BitmapRenderer(context) => {
context.update_rendering(canvas_epoch)
},
OffscreenRenderingContext::Detached => false,
}
}
fn onscreen(&self) -> bool {
match self {
OffscreenRenderingContext::Context2d(context) => context.onscreen(),
OffscreenRenderingContext::BitmapRenderer(context) => context.onscreen(),
OffscreenRenderingContext::Detached => false,
}
}
}

View file

@ -14,8 +14,9 @@ use js::rust::HandleObject;
use js::typedarray::{ClampedU8, Uint8ClampedArray};
use pixels::{Snapshot, SnapshotAlphaMode, SnapshotPixelFormat};
use super::bindings::buffer_source::{HeapBufferSource, create_heap_buffer_source_with_length};
use crate::dom::bindings::buffer_source::create_buffer_source;
use crate::dom::bindings::buffer_source::{
HeapBufferSource, create_buffer_source, create_heap_buffer_source_with_length,
};
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
ImageDataMethods, ImageDataPixelFormat, ImageDataSettings, PredefinedColorSpace,
};

View file

@ -0,0 +1,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
#[path = "2d/mod.rs"]
mod canvas2d;
pub(crate) use canvas2d::*;
pub(crate) mod canvas_context;
pub(crate) mod imagebitmap;
pub(crate) mod imagebitmaprenderingcontext;
pub(crate) mod imagedata;
pub(crate) mod offscreencanvas;

View file

@ -230,10 +230,8 @@ pub(crate) mod bluetooth;
pub(crate) use self::bluetooth::*;
pub(crate) mod broadcastchannel;
pub(crate) mod bytelengthqueuingstrategy;
pub(crate) mod canvasgradient;
pub(crate) mod canvaspattern;
#[allow(dead_code)]
pub(crate) mod canvasrenderingcontext2d;
mod canvas;
pub(crate) use self::canvas::*;
pub(crate) mod cdatasection;
pub(crate) mod characterdata;
pub(crate) mod client;
@ -343,9 +341,6 @@ pub(crate) mod idbopendbrequest;
pub(crate) mod idbrequest;
pub(crate) mod idbtransaction;
pub(crate) mod idbversionchangeevent;
pub(crate) mod imagebitmap;
pub(crate) mod imagebitmaprenderingcontext;
pub(crate) mod imagedata;
pub(crate) mod inputevent;
pub(crate) mod intersectionobserver;
pub(crate) mod intersectionobserverentry;
@ -381,13 +376,9 @@ pub(crate) mod nodeiterator;
#[allow(dead_code)]
pub(crate) mod nodelist;
pub(crate) mod notification;
pub(crate) mod offscreencanvas;
pub(crate) mod offscreencanvasrenderingcontext2d;
pub(crate) mod pagetransitionevent;
pub(crate) mod paintrenderingcontext2d;
pub(crate) mod paintsize;
pub(crate) mod paintworkletglobalscope;
pub(crate) mod path2d;
pub(crate) mod performance;
#[allow(dead_code)]
pub(crate) mod performanceentry;
@ -490,7 +481,6 @@ pub(crate) mod textdecodercommon;
pub(crate) mod textdecoderstream;
pub(crate) mod textencoder;
pub(crate) mod textencoderstream;
pub(crate) mod textmetrics;
pub(crate) mod texttrack;
pub(crate) mod texttrackcue;
pub(crate) mod texttrackcuelist;