aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/paintworkletglobalscope.rs97
-rw-r--r--components/script/dom/webidls/PaintWorkletGlobalScope.webidl9
-rw-r--r--components/script/dom/webidls/Window.webidl4
-rw-r--r--components/script/dom/window.rs17
-rw-r--r--components/script/dom/worklet.rs52
-rw-r--r--components/script/dom/workletglobalscope.rs14
7 files changed, 191 insertions, 3 deletions
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 8ab41391bb2..3ea53f2b4ca 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -391,6 +391,7 @@ pub mod node;
pub mod nodeiterator;
pub mod nodelist;
pub mod pagetransitionevent;
+pub mod paintworkletglobalscope;
pub mod performance;
pub mod performancetiming;
pub mod permissions;
diff --git a/components/script/dom/paintworkletglobalscope.rs b/components/script/dom/paintworkletglobalscope.rs
new file mode 100644
index 00000000000..6a4babe896d
--- /dev/null
+++ b/components/script/dom/paintworkletglobalscope.rs
@@ -0,0 +1,97 @@
+/* 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<Vec<u8>>,
+}
+
+impl PaintWorkletGlobalScope {
+ #[allow(unsafe_code)]
+ pub fn new(runtime: &Runtime,
+ pipeline_id: PipelineId,
+ base_url: ServoUrl,
+ init: &WorkletGlobalScopeInit)
+ -> Root<PaintWorkletGlobalScope> {
+ 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<Au>,
+ sender: Sender<Result<Image, PaintWorkletError>>) {
+ 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<VoidFunction>) {
+ debug!("Registering paint image name {}.", name);
+ // TODO
+ }
+}
+
+/// Tasks which can be peformed by a paint worklet
+pub enum PaintWorkletTask {
+ DrawAPaintImage(Atom, Size2D<Au>, Sender<Result<Image, PaintWorkletError>>)
+}
diff --git a/components/script/dom/webidls/PaintWorkletGlobalScope.webidl b/components/script/dom/webidls/PaintWorkletGlobalScope.webidl
new file mode 100644
index 00000000000..1611ad23694
--- /dev/null
+++ b/components/script/dom/webidls/PaintWorkletGlobalScope.webidl
@@ -0,0 +1,9 @@
+/* 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/. */
+
+// https://drafts.css-houdini.org/css-paint-api/#paintworkletglobalscope
+[Global=(Worklet,PaintWorklet), Exposed=PaintWorklet]
+interface PaintWorkletGlobalScope : WorkletGlobalScope {
+ void registerPaint(DOMString name, VoidFunction paintCtor);
+};
diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl
index c4c25399743..50808c83016 100644
--- a/components/script/dom/webidls/Window.webidl
+++ b/components/script/dom/webidls/Window.webidl
@@ -204,3 +204,7 @@ partial interface Window {
//readonly attribute EventSender eventSender;
};
+// https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet
+partial interface Window {
+ [SameObject] readonly attribute Worklet paintWorklet;
+};
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index fc793c206c4..e627721bd05 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -51,6 +51,7 @@ use dom::storage::Storage;
use dom::testrunner::TestRunner;
use dom::windowproxy::WindowProxy;
use dom::worklet::Worklet;
+use dom::workletglobalscope::WorkletGlobalScopeType;
use dom_struct::dom_struct;
use euclid::{Point2D, Rect, Size2D};
use fetch;
@@ -279,6 +280,8 @@ pub struct Window {
/// Worklets
test_worklet: MutNullableJS<Worklet>,
+ /// https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet
+ paint_worklet: MutNullableJS<Worklet>,
}
impl Window {
@@ -373,6 +376,14 @@ impl Window {
self.webvr_thread.clone()
}
+ fn new_paint_worklet(&self) -> Root<Worklet> {
+ debug!("Creating new paint worklet.");
+ let worklet = Worklet::new(self, WorkletGlobalScopeType::Paint);
+ let executor = Arc::new(worklet.executor());
+ let _ = self.layout_chan.send(Msg::SetPaintWorkletExecutor(executor));
+ worklet
+ }
+
pub fn permission_state_invocation_results(&self) -> &DOMRefCell<HashMap<String, PermissionState>> {
&self.permission_state_invocation_results
}
@@ -1011,6 +1022,11 @@ impl WindowMethods for Window {
fetch::Fetch(&self.upcast(), input, init)
}
+ // https://drafts.css-houdini.org/css-paint-api-1/#paint-worklet
+ fn PaintWorklet(&self) -> Root<Worklet> {
+ self.paint_worklet.or_init(|| self.new_paint_worklet())
+ }
+
fn TestRunner(&self) -> Root<TestRunner> {
self.test_runner.or_init(|| TestRunner::new(self.upcast()))
}
@@ -1856,6 +1872,7 @@ impl Window {
pending_layout_images: DOMRefCell::new(HashMap::new()),
unminified_js_dir: DOMRefCell::new(None),
test_worklet: Default::default(),
+ paint_worklet: Default::default(),
};
unsafe {
diff --git a/components/script/dom/worklet.rs b/components/script/dom/worklet.rs
index fa5b3950b51..da74215f752 100644
--- a/components/script/dom/worklet.rs
+++ b/components/script/dom/worklet.rs
@@ -10,6 +10,7 @@
//! thread pool implementation, which only performs GC or code loading on
//! a backup thread, not on the primary worklet thread.
+use app_units::Au;
use dom::bindings::codegen::Bindings::RequestBinding::RequestCredentials;
use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use dom::bindings::codegen::Bindings::WorkletBinding::WorkletMethods;
@@ -27,6 +28,7 @@ use dom::bindings::str::USVString;
use dom::bindings::trace::JSTraceable;
use dom::bindings::trace::RootedTraceableBox;
use dom::globalscope::GlobalScope;
+use dom::paintworkletglobalscope::PaintWorkletTask;
use dom::promise::Promise;
use dom::testworkletglobalscope::TestWorkletTask;
use dom::window::Window;
@@ -35,6 +37,7 @@ use dom::workletglobalscope::WorkletGlobalScopeInit;
use dom::workletglobalscope::WorkletGlobalScopeType;
use dom::workletglobalscope::WorkletTask;
use dom_struct::dom_struct;
+use euclid::Size2D;
use js::jsapi::JSGCParamKey;
use js::jsapi::JSTracer;
use js::jsapi::JS_GC;
@@ -42,6 +45,7 @@ use js::jsapi::JS_GetGCParameter;
use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use net_traits::IpcSend;
+use net_traits::image::base::Image;
use net_traits::load_whole_resource;
use net_traits::request::Destination;
use net_traits::request::RequestInit;
@@ -54,6 +58,9 @@ use script_runtime::new_rt_and_cx;
use script_thread::MainThreadScriptMsg;
use script_thread::Runnable;
use script_thread::ScriptThread;
+use script_traits::PaintWorkletError;
+use script_traits::PaintWorkletExecutor;
+use servo_atoms::Atom;
use servo_rand;
use servo_url::ImmutableOrigin;
use servo_url::ServoUrl;
@@ -62,12 +69,14 @@ use std::collections::HashMap;
use std::collections::hash_map;
use std::rc::Rc;
use std::sync::Arc;
+use std::sync::Mutex;
use std::sync::atomic::AtomicIsize;
use std::sync::atomic::Ordering;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::thread;
+use std::time::Duration;
use style::thread_state;
use swapper::Swapper;
use swapper::swapper;
@@ -76,6 +85,7 @@ use uuid::Uuid;
// Magic numbers
const WORKLET_THREAD_POOL_SIZE: u32 = 3;
const MIN_GC_THRESHOLD: u32 = 1_000_000;
+const PAINT_TIMEOUT_MILLISECONDS: u64 = 10;
#[dom_struct]
/// https://drafts.css-houdini.org/worklets/#worklet
@@ -109,6 +119,13 @@ impl Worklet {
pub fn worklet_global_scope_type(&self) -> WorkletGlobalScopeType {
self.global_type
}
+
+ pub fn executor(&self) -> WorkletExecutor {
+ WorkletExecutor {
+ worklet_id: self.worklet_id,
+ primary_sender: Mutex::new(ScriptThread::worklet_thread_pool().primary_sender.clone()),
+ }
+ }
}
impl WorkletMethods for Worklet {
@@ -561,7 +578,8 @@ impl WorkletThread {
// TODO: Caching.
// TODO: Avoid re-parsing the origin as a URL.
let resource_fetcher = self.global_init.resource_threads.sender();
- let origin_url = ServoUrl::parse(&*origin.unicode_serialization()).expect("Failed to parse origin as URL.");
+ let origin_url = ServoUrl::parse(&*origin.unicode_serialization())
+ .unwrap_or_else(|_| ServoUrl::parse("about:blank").unwrap());
let request = RequestInit {
url: script_url,
type_: RequestType::Script,
@@ -635,3 +653,35 @@ impl WorkletThread {
self.script_sender.send(msg).expect("Worklet thread outlived script thread.");
}
}
+
+/// An executor of worklet tasks
+pub struct WorkletExecutor {
+ worklet_id: WorkletId,
+ // Rather annoyingly, we have to use a mutex here because
+ // layout threads share their context rather than cloning it.
+ primary_sender: Mutex<Sender<WorkletData>>,
+}
+
+impl WorkletExecutor {
+ /// Schedule a worklet task to be peformed by the worklet thread pool.
+ fn schedule_a_worklet_task(&self, task: WorkletTask) {
+ let _ = self.primary_sender.lock()
+ .expect("Locking the worklet channel.")
+ .send(WorkletData::Task(self.worklet_id, task));
+ }
+}
+
+impl PaintWorkletExecutor for WorkletExecutor {
+ /// https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image
+ fn draw_a_paint_image(&self,
+ name: Atom,
+ concrete_object_size: Size2D<Au>)
+ -> Result<Image, PaintWorkletError>
+ {
+ let (sender, receiver) = mpsc::channel();
+ let task = WorkletTask::Paint(PaintWorkletTask::DrawAPaintImage(name, concrete_object_size, sender));
+ let timeout = Duration::from_millis(PAINT_TIMEOUT_MILLISECONDS);
+ self.schedule_a_worklet_task(task);
+ receiver.recv_timeout(timeout)?
+ }
+}
diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs
index a2e2463ca27..78804d66ae0 100644
--- a/components/script/dom/workletglobalscope.rs
+++ b/components/script/dom/workletglobalscope.rs
@@ -6,6 +6,8 @@ use devtools_traits::ScriptToDevtoolsControlMsg;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::globalscope::GlobalScope;
+use dom::paintworkletglobalscope::PaintWorkletGlobalScope;
+use dom::paintworkletglobalscope::PaintWorkletTask;
use dom::testworkletglobalscope::TestWorkletGlobalScope;
use dom::testworkletglobalscope::TestWorkletTask;
use dom_struct::dom_struct;
@@ -92,6 +94,10 @@ impl WorkletGlobalScope {
Some(global) => global.perform_a_worklet_task(task),
None => warn!("This is not a test worklet."),
},
+ WorkletTask::Paint(task) => match self.downcast::<PaintWorkletGlobalScope>() {
+ Some(global) => global.perform_a_worklet_task(task),
+ None => warn!("This is not a paint worklet."),
+ },
}
}
}
@@ -116,8 +122,10 @@ pub struct WorkletGlobalScopeInit {
/// https://drafts.css-houdini.org/worklets/#worklet-global-scope-type
#[derive(Clone, Copy, Debug, HeapSizeOf, JSTraceable)]
pub enum WorkletGlobalScopeType {
- /// https://drafts.css-houdini.org/worklets/#examples
+ /// A servo-specific testing worklet
Test,
+ /// A paint worklet
+ Paint,
}
impl WorkletGlobalScopeType {
@@ -132,6 +140,8 @@ impl WorkletGlobalScopeType {
match *self {
WorkletGlobalScopeType::Test =>
Root::upcast(TestWorkletGlobalScope::new(runtime, pipeline_id, base_url, init)),
+ WorkletGlobalScopeType::Paint =>
+ Root::upcast(PaintWorkletGlobalScope::new(runtime, pipeline_id, base_url, init)),
}
}
}
@@ -139,5 +149,5 @@ impl WorkletGlobalScopeType {
/// A task which can be performed in the context of a worklet global.
pub enum WorkletTask {
Test(TestWorkletTask),
+ Paint(PaintWorkletTask),
}
-