/* 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 http://mozilla.org/MPL/2.0/. */ use app_units::Au; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::PaintWorkletGlobalScopeBinding; use dom::bindings::codegen::Bindings::PaintWorkletGlobalScopeBinding::PaintWorkletGlobalScopeMethods; use dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction; use dom::bindings::js::Root; use dom::bindings::str::DOMString; use dom::workletglobalscope::WorkletGlobalScope; use dom::workletglobalscope::WorkletGlobalScopeInit; use dom_struct::dom_struct; use euclid::Size2D; use ipc_channel::ipc::IpcSharedMemory; use js::rust::Runtime; use msg::constellation_msg::PipelineId; use net_traits::image::base::Image; use net_traits::image::base::PixelFormat; use script_traits::PaintWorkletError; use servo_atoms::Atom; use servo_url::ServoUrl; use std::rc::Rc; use std::sync::mpsc::Sender; #[dom_struct] /// https://drafts.css-houdini.org/css-paint-api/#paintworkletglobalscope pub struct PaintWorkletGlobalScope { /// The worklet global for this object worklet_global: WorkletGlobalScope, /// A buffer to draw into buffer: DOMRefCell>, } impl PaintWorkletGlobalScope { #[allow(unsafe_code)] pub fn new(runtime: &Runtime, pipeline_id: PipelineId, base_url: ServoUrl, init: &WorkletGlobalScopeInit) -> Root { debug!("Creating paint worklet global scope for pipeline {}.", pipeline_id); let global = box PaintWorkletGlobalScope { worklet_global: WorkletGlobalScope::new_inherited(pipeline_id, base_url, init), buffer: Default::default(), }; unsafe { PaintWorkletGlobalScopeBinding::Wrap(runtime.cx(), global) } } pub fn perform_a_worklet_task(&self, task: PaintWorkletTask) { match task { PaintWorkletTask::DrawAPaintImage(name, size, sender) => self.draw_a_paint_image(name, size, sender), } } fn draw_a_paint_image(&self, name: Atom, concrete_object_size: Size2D, sender: Sender>) { let width = concrete_object_size.width.to_px().abs() as u32; let height = concrete_object_size.height.to_px().abs() as u32; let area = (width as usize) * (height as usize); let old_buffer_size = self.buffer.borrow().len(); let new_buffer_size = area * 4; debug!("Drawing a paint image {}({},{}).", name, width, height); // TODO: call into script to create the image. // For now, we just build a dummy. if new_buffer_size > old_buffer_size { let pixel = [0xFF, 0x00, 0x00, 0xFF]; self.buffer.borrow_mut().extend(pixel.iter().cycle().take(new_buffer_size - old_buffer_size)); } else { self.buffer.borrow_mut().truncate(new_buffer_size); } let image = Image { width: width, height: height, format: PixelFormat::RGBA8, bytes: IpcSharedMemory::from_bytes(&*self.buffer.borrow()), id: None, }; let _ = sender.send(Ok(image)); } } impl PaintWorkletGlobalScopeMethods for PaintWorkletGlobalScope { /// https://drafts.css-houdini.org/css-paint-api/#dom-paintworkletglobalscope-registerpaint fn RegisterPaint(&self, name: DOMString, _paintCtor: Rc) { debug!("Registering paint image name {}.", name); // TODO } } /// Tasks which can be peformed by a paint worklet pub enum PaintWorkletTask { DrawAPaintImage(Atom, Size2D, Sender>) }