mirror of
https://github.com/servo/servo.git
synced 2025-09-30 00:29:14 +01:00
Any RenderingContext/OffscreenRenderingContext type has readonly "canvas" attribute and associated native-code DOM context objects have reference to target DOM canvas objects. https://html.spec.whatwg.org/multipage/canvas.html#renderingcontext https://html.spec.whatwg.org/multipage/canvas.html#offscreenrenderingcontext And currently the reference to DOM canvas object is the rooting pointer on the stack, which leads to the circular reference problem. The SpiderMonkey's (SM) garbage collector will not be able to free the DOM canvas and context objects (unreacheble from JS) because of the rooting pointer on stack (see STACK_ROOTS). And these objects will be stored until the associated script runtime/thread will be terminated. SM -> JS Roots -> DOM Canvas* (on heap) -> DOM Context (on heap) SM -> Rust Roots -> Dom Canvas* (on stack) <- as "canvas" member field Let's replace the rooting pointer to the traceble pointer (DomRoot -> Dom) in the "canvas" member field of DOM context object, which allows to broke circular referencing problem. Testing: No changes in existed tests Signed-off-by: Andrei Volykhin <volykhin.andrei@huawei.com> Co-authored-by: Andrei Volykhin <volykhin.andrei@huawei.com>
203 lines
7.7 KiB
Rust
203 lines
7.7 KiB
Rust
/* 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/. */
|
|
|
|
use std::cell::Cell;
|
|
|
|
use dom_struct::dom_struct;
|
|
use euclid::default::Size2D;
|
|
use pixels::Snapshot;
|
|
use webrender_api::ImageKey;
|
|
|
|
use crate::canvas_context::{
|
|
CanvasContext, CanvasHelpers, HTMLCanvasElementOrOffscreenCanvas,
|
|
LayoutCanvasRenderingContextHelpers,
|
|
};
|
|
use crate::dom::bindings::cell::DomRefCell;
|
|
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;
|
|
use crate::dom::bindings::codegen::Bindings::ImageBitmapRenderingContextBinding::ImageBitmapRenderingContextMethods;
|
|
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas as RootedHTMLCanvasElementOrOffscreenCanvas;
|
|
use crate::dom::bindings::error::{Error, Fallible};
|
|
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
|
|
use crate::dom::bindings::root::{DomRoot, LayoutDom};
|
|
use crate::dom::globalscope::GlobalScope;
|
|
use crate::dom::imagebitmap::ImageBitmap;
|
|
use crate::script_runtime::CanGc;
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#imagebitmaprenderingcontext>
|
|
#[dom_struct]
|
|
pub(crate) struct ImageBitmapRenderingContext {
|
|
reflector_: Reflector,
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-imagebitmaprenderingcontext-canvas>
|
|
canvas: HTMLCanvasElementOrOffscreenCanvas,
|
|
/// Represents both the [output bitmap] and the [bitmap mode] of the context.
|
|
/// <https://html.spec.whatwg.org/multipage/#concept-imagebitmaprenderingcontext-output-bitmap>
|
|
/// <https://html.spec.whatwg.org/multipage/#concept-imagebitmaprenderingcontext-bitmap-mode>
|
|
#[no_trace]
|
|
bitmap: DomRefCell<Option<Snapshot>>,
|
|
origin_clean: Cell<bool>,
|
|
}
|
|
|
|
impl ImageBitmapRenderingContext {
|
|
/// <https://html.spec.whatwg.org/multipage/#imagebitmaprenderingcontext-creation-algorithm>
|
|
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
|
fn new_inherited(canvas: HTMLCanvasElementOrOffscreenCanvas) -> ImageBitmapRenderingContext {
|
|
ImageBitmapRenderingContext {
|
|
reflector_: Reflector::new(),
|
|
canvas,
|
|
bitmap: DomRefCell::new(None),
|
|
origin_clean: Cell::new(true),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn new(
|
|
global: &GlobalScope,
|
|
canvas: &RootedHTMLCanvasElementOrOffscreenCanvas,
|
|
can_gc: CanGc,
|
|
) -> DomRoot<ImageBitmapRenderingContext> {
|
|
reflect_dom_object(
|
|
Box::new(ImageBitmapRenderingContext::new_inherited(
|
|
HTMLCanvasElementOrOffscreenCanvas::from(canvas),
|
|
)),
|
|
global,
|
|
can_gc,
|
|
)
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#set-an-imagebitmaprenderingcontext's-output-bitmap>
|
|
fn set_bitmap(&self, image_bitmap: Option<&ImageBitmap>) {
|
|
match image_bitmap {
|
|
Some(image_bitmap) => {
|
|
// Step 2.1. Set context's bitmap mode to valid.
|
|
// Step 2.2. Set context's output bitmap to refer to the same
|
|
// underlying bitmap data as bitmap, without making a copy.
|
|
*self.bitmap.borrow_mut() = image_bitmap.bitmap_data().clone();
|
|
|
|
// The origin-clean flag of bitmap is included in the bitmap
|
|
// data to be referenced by context's output bitmap.
|
|
self.origin_clean.set(image_bitmap.origin_is_clean());
|
|
},
|
|
None => {
|
|
// Step 1.1. Set context's bitmap mode to blank.
|
|
// Step 1.2. Let canvas be the canvas element to which context is bound.
|
|
// Step 1.3. Set context's output bitmap to be transparent black
|
|
// with a natural width equal to the numeric value of canvas's
|
|
// width attribute and a natural height equal to the numeric
|
|
// value of canvas's height attribute, those values being
|
|
// interpreted in CSS pixels.
|
|
*self.bitmap.borrow_mut() = None;
|
|
|
|
// Step 1.4. Set the output bitmap's origin-clean flag to true.
|
|
self.origin_clean.set(true);
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, ImageBitmapRenderingContext> {
|
|
fn canvas_data_source(self) -> Option<ImageKey> {
|
|
None
|
|
}
|
|
}
|
|
|
|
impl CanvasContext for ImageBitmapRenderingContext {
|
|
type ID = ();
|
|
|
|
fn context_id(&self) -> Self::ID {}
|
|
|
|
fn canvas(&self) -> Option<RootedHTMLCanvasElementOrOffscreenCanvas> {
|
|
Some(RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas))
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#the-canvas-element:concept-canvas-bitmaprenderer>
|
|
fn resize(&self) {
|
|
// The absence of the bitmap is the context's blank bitmap mode so the
|
|
// steps to set output bitmap could be omitted.
|
|
}
|
|
|
|
fn reset_bitmap(&self) {
|
|
// The newly created bitmap should be of the same dimensions as the
|
|
// previous bitmap if the context's bitmap mode is valid.
|
|
if self.bitmap.borrow().is_none() {
|
|
return;
|
|
}
|
|
|
|
let size = self.bitmap.borrow().as_ref().unwrap().size();
|
|
*self.bitmap.borrow_mut() = Some(Snapshot::cleared(size));
|
|
}
|
|
|
|
fn get_image_data(&self) -> Option<Snapshot> {
|
|
match self.bitmap.borrow().as_ref() {
|
|
Some(bitmap) => Some(bitmap.clone()),
|
|
None => {
|
|
let size = self.canvas.size();
|
|
if size.is_empty() ||
|
|
pixels::compute_rgba8_byte_length_if_within_limit(
|
|
size.width as usize,
|
|
size.height as usize,
|
|
)
|
|
.is_none()
|
|
{
|
|
None
|
|
} else {
|
|
Some(Snapshot::cleared(size))
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
fn origin_is_clean(&self) -> bool {
|
|
self.origin_clean.get()
|
|
}
|
|
|
|
fn size(&self) -> Size2D<u32> {
|
|
self.bitmap
|
|
.borrow()
|
|
.as_ref()
|
|
.map_or_else(|| self.canvas.size(), |bitmap| bitmap.size())
|
|
}
|
|
|
|
fn image_key(&self) -> Option<ImageKey> {
|
|
None
|
|
}
|
|
}
|
|
|
|
impl ImageBitmapRenderingContextMethods<crate::DomTypeHolder> for ImageBitmapRenderingContext {
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-imagebitmaprenderingcontext-canvas>
|
|
fn Canvas(&self) -> RootedHTMLCanvasElementOrOffscreenCanvas {
|
|
RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas)
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-imagebitmaprenderingcontext-transferfromimagebitmap>
|
|
fn TransferFromImageBitmap(&self, image_bitmap: Option<&ImageBitmap>) -> Fallible<()> {
|
|
let Some(image_bitmap) = image_bitmap else {
|
|
// Step 2. If bitmap is null, then run the steps to set an
|
|
// ImageBitmapRenderingContext's output bitmap, with
|
|
// bitmapContext as the context argument and no bitmap argument,
|
|
// then return.
|
|
self.set_bitmap(None);
|
|
|
|
return Ok(());
|
|
};
|
|
|
|
// Step 3. If the value of bitmap's [[Detached]] internal slot
|
|
// is set to true, then throw an "InvalidStateError"
|
|
// DOMException.
|
|
if image_bitmap.is_detached() {
|
|
return Err(Error::InvalidState);
|
|
}
|
|
|
|
// Step 4. Run the steps to set an ImageBitmapRenderingContext's
|
|
// output bitmap, with the context argument equal to
|
|
// bitmapContext, and the bitmap argument referring to bitmap's
|
|
// underlying bitmap data.
|
|
self.set_bitmap(Some(image_bitmap));
|
|
|
|
// Step 5. Set the value of bitmap's [[Detached]] internal slot
|
|
// to true.
|
|
// Step 6. Unset bitmap's bitmap data.
|
|
image_bitmap.Close();
|
|
|
|
Ok(())
|
|
}
|
|
}
|