script/dom/canvas/
imagebitmaprenderingcontext.rs1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use euclid::default::Size2D;
9use pixels::Snapshot;
10use webrender_api::ImageKey;
11
12use crate::canvas_context::{
13 CanvasContext, CanvasHelpers, HTMLCanvasElementOrOffscreenCanvas,
14 LayoutCanvasRenderingContextHelpers,
15};
16use crate::dom::bindings::cell::DomRefCell;
17use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;
18use crate::dom::bindings::codegen::Bindings::ImageBitmapRenderingContextBinding::ImageBitmapRenderingContextMethods;
19use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas as RootedHTMLCanvasElementOrOffscreenCanvas;
20use crate::dom::bindings::error::{Error, Fallible};
21use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
22use crate::dom::bindings::root::{DomRoot, LayoutDom};
23use crate::dom::globalscope::GlobalScope;
24use crate::dom::imagebitmap::ImageBitmap;
25use crate::script_runtime::CanGc;
26
27#[dom_struct]
29pub(crate) struct ImageBitmapRenderingContext {
30 reflector_: Reflector,
31 canvas: HTMLCanvasElementOrOffscreenCanvas,
33 #[no_trace]
37 bitmap: DomRefCell<Option<Snapshot>>,
38 origin_clean: Cell<bool>,
39}
40
41impl ImageBitmapRenderingContext {
42 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
44 fn new_inherited(canvas: HTMLCanvasElementOrOffscreenCanvas) -> ImageBitmapRenderingContext {
45 ImageBitmapRenderingContext {
46 reflector_: Reflector::new(),
47 canvas,
48 bitmap: DomRefCell::new(None),
49 origin_clean: Cell::new(true),
50 }
51 }
52
53 pub(crate) fn new(
54 global: &GlobalScope,
55 canvas: &RootedHTMLCanvasElementOrOffscreenCanvas,
56 can_gc: CanGc,
57 ) -> DomRoot<ImageBitmapRenderingContext> {
58 reflect_dom_object(
59 Box::new(ImageBitmapRenderingContext::new_inherited(
60 HTMLCanvasElementOrOffscreenCanvas::from(canvas),
61 )),
62 global,
63 can_gc,
64 )
65 }
66
67 fn set_bitmap(&self, image_bitmap: Option<&ImageBitmap>) {
69 match image_bitmap {
70 Some(image_bitmap) => {
71 *self.bitmap.borrow_mut() = image_bitmap.bitmap_data().clone();
75
76 self.origin_clean.set(image_bitmap.origin_is_clean());
79 },
80 None => {
81 *self.bitmap.borrow_mut() = None;
89
90 self.origin_clean.set(true);
92 },
93 }
94 }
95}
96
97impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, ImageBitmapRenderingContext> {
98 fn canvas_data_source(self) -> Option<ImageKey> {
99 None
100 }
101}
102
103impl CanvasContext for ImageBitmapRenderingContext {
104 type ID = ();
105
106 fn context_id(&self) -> Self::ID {}
107
108 fn canvas(&self) -> Option<RootedHTMLCanvasElementOrOffscreenCanvas> {
109 Some(RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas))
110 }
111
112 fn resize(&self) {
114 }
117
118 fn reset_bitmap(&self) {
119 if self.bitmap.borrow().is_none() {
122 return;
123 }
124
125 let size = self.bitmap.borrow().as_ref().unwrap().size();
126 *self.bitmap.borrow_mut() = Some(Snapshot::cleared(size));
127 }
128
129 fn get_image_data(&self) -> Option<Snapshot> {
130 match self.bitmap.borrow().as_ref() {
131 Some(bitmap) => Some(bitmap.clone()),
132 None => {
133 let size = self.canvas.size();
134 if size.is_empty() ||
135 pixels::compute_rgba8_byte_length_if_within_limit(
136 size.width as usize,
137 size.height as usize,
138 )
139 .is_none()
140 {
141 None
142 } else {
143 Some(Snapshot::cleared(size))
144 }
145 },
146 }
147 }
148
149 fn origin_is_clean(&self) -> bool {
150 self.origin_clean.get()
151 }
152
153 fn size(&self) -> Size2D<u32> {
154 self.bitmap
155 .borrow()
156 .as_ref()
157 .map_or_else(|| self.canvas.size(), |bitmap| bitmap.size())
158 }
159
160 fn image_key(&self) -> Option<ImageKey> {
161 None
162 }
163}
164
165impl ImageBitmapRenderingContextMethods<crate::DomTypeHolder> for ImageBitmapRenderingContext {
166 fn Canvas(&self) -> RootedHTMLCanvasElementOrOffscreenCanvas {
168 RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas)
169 }
170
171 fn TransferFromImageBitmap(&self, image_bitmap: Option<&ImageBitmap>) -> Fallible<()> {
173 let Some(image_bitmap) = image_bitmap else {
174 self.set_bitmap(None);
179
180 return Ok(());
181 };
182
183 if image_bitmap.is_detached() {
187 return Err(Error::InvalidState);
188 }
189
190 self.set_bitmap(Some(image_bitmap));
195
196 image_bitmap.Close();
200
201 Ok(())
202 }
203}