mirror of
https://github.com/servo/servo
synced 2026-05-08 16:12:15 +02:00
This change makes it so that the `HTMLCanvasElement` is responsible for managing the `ImageKey` for associated `RenderingContext`s. Only canvases display their contents into WebRender directly, so this makes it so that keys are not generated for `OffscreenCanvas`. The main goal here is that `ImageKey`s are always associated with a particular `WebView`, which isn't possible in the various canvas backends yet. This is important because each `WebView` may soon have a different WebRender instance entirely with its own set of `ImageKey`s. This also allows for clearing `ImageKey`s when canvases are disconnected from the DOM in a future change. One tricky thing here is placeholder canvases, which are meant to be driven from workers. It seems that the implementation isn't correct for these at the moment as they need to be updated to the specification. Instead, what is happening is that any existing context / image is completely lost when converting to an `OffscreenCanvas`. Testing: This shouldn't change observable behavior, so is covered by existing tests. Fixes: This is part of #40261. --------- Signed-off-by: Martin Robinson <mrobinson@igalia.com> Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com> Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
192 lines
7.4 KiB
Rust
192 lines
7.4 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 crate::canvas_context::{CanvasContext, CanvasHelpers, HTMLCanvasElementOrOffscreenCanvas};
|
|
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;
|
|
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 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 mark_as_dirty(&self) {}
|
|
}
|
|
|
|
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(None));
|
|
}
|
|
|
|
// 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(())
|
|
}
|
|
}
|