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    fn mark_as_dirty(&self) {}
165}
166
167impl ImageBitmapRenderingContextMethods<crate::DomTypeHolder> for ImageBitmapRenderingContext {
168    fn Canvas(&self) -> RootedHTMLCanvasElementOrOffscreenCanvas {
170        RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas)
171    }
172
173    fn TransferFromImageBitmap(&self, image_bitmap: Option<&ImageBitmap>) -> Fallible<()> {
175        let Some(image_bitmap) = image_bitmap else {
176            self.set_bitmap(None);
181
182            return Ok(());
183        };
184
185        if image_bitmap.is_detached() {
189            return Err(Error::InvalidState(None));
190        }
191
192        self.set_bitmap(Some(image_bitmap));
197
198        image_bitmap.Close();
202
203        Ok(())
204    }
205}