diff options
Diffstat (limited to 'components/script/dom/offscreencanvas.rs')
-rw-r--r-- | components/script/dom/offscreencanvas.rs | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs new file mode 100644 index 00000000000..b381c245cfa --- /dev/null +++ b/components/script/dom/offscreencanvas.rs @@ -0,0 +1,203 @@ +/* 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 crate::dom::bindings::cell::{ref_filter_map, DomRefCell, Ref}; +use crate::dom::bindings::codegen::Bindings::OffscreenCanvasBinding::{ + OffscreenCanvasMethods, OffscreenRenderingContext, +}; +use crate::dom::bindings::error::Fallible; +use crate::dom::bindings::reflector::reflect_dom_object; +use crate::dom::bindings::reflector::DomObject; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::str::DOMString; +use crate::dom::eventtarget::EventTarget; +use crate::dom::globalscope::GlobalScope; +use crate::dom::htmlcanvaselement::HTMLCanvasElement; +use crate::dom::offscreencanvasrenderingcontext2d::OffscreenCanvasRenderingContext2D; +use crate::script_runtime::JSContext; +use canvas_traits::canvas::{CanvasMsg, FromScriptMsg}; +use dom_struct::dom_struct; +use euclid::default::Size2D; +use ipc_channel::ipc::IpcSharedMemory; +use js::rust::HandleValue; +use profile_traits::ipc; +use std::cell::Cell; + +#[unrooted_must_root_lint::must_root] +#[derive(Clone, JSTraceable, MallocSizeOf)] +pub enum OffscreenCanvasContext { + OffscreenContext2d(Dom<OffscreenCanvasRenderingContext2D>), + //WebGL(Dom<WebGLRenderingContext>), + //WebGL2(Dom<WebGL2RenderingContext>), +} + +#[dom_struct] +pub struct OffscreenCanvas { + eventtarget: EventTarget, + width: Cell<u64>, + height: Cell<u64>, + context: DomRefCell<Option<OffscreenCanvasContext>>, + placeholder: Option<Dom<HTMLCanvasElement>>, +} + +impl OffscreenCanvas { + pub fn new_inherited( + width: u64, + height: u64, + placeholder: Option<&HTMLCanvasElement>, + ) -> OffscreenCanvas { + OffscreenCanvas { + eventtarget: EventTarget::new_inherited(), + width: Cell::new(width), + height: Cell::new(height), + context: DomRefCell::new(None), + placeholder: placeholder.map(Dom::from_ref), + } + } + + pub fn new( + global: &GlobalScope, + width: u64, + height: u64, + placeholder: Option<&HTMLCanvasElement>, + ) -> DomRoot<OffscreenCanvas> { + reflect_dom_object( + Box::new(OffscreenCanvas::new_inherited(width, height, placeholder)), + global, + ) + } + + #[allow(non_snake_case)] + pub fn Constructor( + global: &GlobalScope, + width: u64, + height: u64, + ) -> Fallible<DomRoot<OffscreenCanvas>> { + let offscreencanvas = OffscreenCanvas::new(global, width, height, None); + Ok(offscreencanvas) + } + + pub fn get_size(&self) -> Size2D<u64> { + Size2D::new(self.Width(), self.Height()) + } + + pub fn origin_is_clean(&self) -> bool { + match *self.context.borrow() { + Some(OffscreenCanvasContext::OffscreenContext2d(ref context)) => { + context.origin_is_clean() + }, + _ => true, + } + } + + pub fn context(&self) -> Option<Ref<OffscreenCanvasContext>> { + ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref()) + } + + pub fn fetch_all_data(&self) -> Option<(Option<IpcSharedMemory>, Size2D<u32>)> { + let size = self.get_size(); + + if size.width == 0 || size.height == 0 { + return None; + } + + let data = match self.context.borrow().as_ref() { + Some(&OffscreenCanvasContext::OffscreenContext2d(ref context)) => { + let (sender, receiver) = + ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); + let msg = CanvasMsg::FromScript( + FromScriptMsg::SendPixels(sender), + context.get_canvas_id(), + ); + context.get_ipc_renderer().send(msg).unwrap(); + + Some(receiver.recv().unwrap()) + }, + None => None, + }; + + Some((data, size.to_u32())) + } + + #[allow(unsafe_code)] + fn get_or_init_2d_context(&self) -> Option<DomRoot<OffscreenCanvasRenderingContext2D>> { + if let Some(ctx) = self.context() { + return match *ctx { + OffscreenCanvasContext::OffscreenContext2d(ref ctx) => Some(DomRoot::from_ref(ctx)), + }; + } + let context = OffscreenCanvasRenderingContext2D::new( + &self.global(), + self, + self.placeholder.as_ref().map(|c| &**c), + ); + *self.context.borrow_mut() = Some(OffscreenCanvasContext::OffscreenContext2d( + Dom::from_ref(&*context), + )); + Some(context) + } + + pub fn is_valid(&self) -> bool { + self.Width() != 0 && self.Height() != 0 + } +} + +impl OffscreenCanvasMethods for OffscreenCanvas { + // https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-getcontext + fn GetContext( + &self, + _cx: JSContext, + id: DOMString, + _options: HandleValue, + ) -> Option<OffscreenRenderingContext> { + match &*id { + "2d" => self + .get_or_init_2d_context() + .map(OffscreenRenderingContext::OffscreenCanvasRenderingContext2D), + /*"webgl" | "experimental-webgl" => self + .get_or_init_webgl_context(cx, options) + .map(OffscreenRenderingContext::WebGLRenderingContext), + "webgl2" | "experimental-webgl2" => self + .get_or_init_webgl2_context(cx, options) + .map(OffscreenRenderingContext::WebGL2RenderingContext),*/ + _ => None, + } + } + + // https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-width + fn Width(&self) -> u64 { + return self.width.get(); + } + + // https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-width + fn SetWidth(&self, value: u64) { + self.width.set(value); + + if let Some(canvas_context) = self.context() { + match &*canvas_context { + OffscreenCanvasContext::OffscreenContext2d(rendering_context) => { + rendering_context.set_canvas_bitmap_dimensions(self.get_size()); + }, + } + } + } + + // https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-height + fn Height(&self) -> u64 { + return self.height.get(); + } + + // https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-height + fn SetHeight(&self, value: u64) { + self.height.set(value); + + if let Some(canvas_context) = self.context() { + match &*canvas_context { + OffscreenCanvasContext::OffscreenContext2d(rendering_context) => { + rendering_context.set_canvas_bitmap_dimensions(self.get_size()); + }, + } + } + } +} |