aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/script')
-rw-r--r--src/components/script/dom/bindings/global.rs2
-rw-r--r--src/components/script/dom/bindings/js.rs10
-rw-r--r--src/components/script/dom/dedicatedworkerglobalscope.rs105
-rw-r--r--src/components/script/dom/document.rs37
-rw-r--r--src/components/script/dom/location.rs4
-rw-r--r--src/components/script/dom/messageevent.rs10
-rw-r--r--src/components/script/dom/node.rs9
-rw-r--r--src/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl4
-rw-r--r--src/components/script/dom/webidls/Node.webidl4
-rw-r--r--src/components/script/dom/webidls/Worker.webidl5
-rw-r--r--src/components/script/dom/worker.rs123
-rw-r--r--src/components/script/script_task.rs52
12 files changed, 277 insertions, 88 deletions
diff --git a/src/components/script/dom/bindings/global.rs b/src/components/script/dom/bindings/global.rs
index ed7807f9d72..35b94d0e472 100644
--- a/src/components/script/dom/bindings/global.rs
+++ b/src/components/script/dom/bindings/global.rs
@@ -72,6 +72,8 @@ impl<'a> GlobalRef<'a> {
}
}
+ /// `ScriptChan` used to send messages to the event loop of this global's
+ /// thread.
pub fn script_chan<'b>(&'b self) -> &'b ScriptChan {
match *self {
Window(ref window) => &window.script_chan,
diff --git a/src/components/script/dom/bindings/js.rs b/src/components/script/dom/bindings/js.rs
index 6a57b45449f..ab8b3e3c7f5 100644
--- a/src/components/script/dom/bindings/js.rs
+++ b/src/components/script/dom/bindings/js.rs
@@ -48,6 +48,7 @@
use dom::bindings::utils::{Reflector, Reflectable};
use dom::node::Node;
use dom::xmlhttprequest::{XMLHttpRequest, TrustedXHRAddress};
+use dom::worker::{Worker, TrustedWorkerAddress};
use js::jsapi::JSObject;
use layout_interface::TrustedNodeAddress;
use script_task::StackRoots;
@@ -143,6 +144,15 @@ impl JS<XMLHttpRequest> {
}
}
+impl JS<Worker> {
+ pub unsafe fn from_trusted_worker_address(inner: TrustedWorkerAddress) -> JS<Worker> {
+ let TrustedWorkerAddress(addr) = inner;
+ JS {
+ ptr: addr as *const Worker
+ }
+ }
+}
+
impl<T: Reflectable> JS<T> {
/// Create a new JS-owned value wrapped from a raw Rust pointer.
pub unsafe fn from_raw(raw: *const T) -> JS<T> {
diff --git a/src/components/script/dom/dedicatedworkerglobalscope.rs b/src/components/script/dom/dedicatedworkerglobalscope.rs
index 2aff963a8e0..15bf075df44 100644
--- a/src/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/src/components/script/dom/dedicatedworkerglobalscope.rs
@@ -3,26 +3,35 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
+use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::DedicatedWorkerGlobalScopeDerived;
use dom::bindings::codegen::InheritTypes::{EventTargetCast, WorkerGlobalScopeCast};
use dom::bindings::global::Worker;
use dom::bindings::js::{JSRef, Temporary, RootCollection};
use dom::bindings::trace::Untraceable;
use dom::bindings::utils::{Reflectable, Reflector};
-use dom::eventtarget::EventTarget;
+use dom::eventtarget::{EventTarget, EventTargetHelpers};
use dom::eventtarget::WorkerGlobalScopeTypeId;
use dom::messageevent::MessageEvent;
+use dom::worker::{Worker, TrustedWorkerAddress};
use dom::workerglobalscope::DedicatedGlobalScope;
use dom::workerglobalscope::WorkerGlobalScope;
+use dom::xmlhttprequest::XMLHttpRequest;
use script_task::{ScriptTask, ScriptChan};
+use script_task::{ScriptMsg, DOMMessage, XHRProgressMsg, WorkerRelease};
+use script_task::WorkerPostMessage;
use script_task::StackRootTLS;
use servo_net::resource_task::{ResourceTask, load_whole_resource};
-use servo_util::str::DOMString;
+use js::glue::JS_STRUCTURED_CLONE_VERSION;
+use js::jsapi::{JSContext, JS_ReadStructuredClone, JS_WriteStructuredClone};
+use js::jsval::{JSVal, UndefinedValue};
use js::rust::Cx;
use std::rc::Rc;
+use std::ptr;
use std::task::TaskBuilder;
use native::task::NativeTaskBuilder;
use url::Url;
@@ -30,41 +39,53 @@ use url::Url;
#[deriving(Encodable)]
pub struct DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope,
- receiver: Untraceable<Receiver<DOMString>>,
+ receiver: Untraceable<Receiver<ScriptMsg>>,
+ /// Sender to the parent thread.
+ parent_sender: ScriptChan,
+ worker: Untraceable<TrustedWorkerAddress>,
}
impl DedicatedWorkerGlobalScope {
pub fn new_inherited(worker_url: Url,
+ worker: TrustedWorkerAddress,
cx: Rc<Cx>,
- receiver: Receiver<DOMString>,
resource_task: ResourceTask,
- script_chan: ScriptChan)
+ parent_sender: ScriptChan,
+ own_sender: ScriptChan,
+ receiver: Receiver<ScriptMsg>)
-> DedicatedWorkerGlobalScope {
DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope::new_inherited(
DedicatedGlobalScope, worker_url, cx, resource_task,
- script_chan),
+ own_sender),
receiver: Untraceable::new(receiver),
+ parent_sender: parent_sender,
+ worker: Untraceable::new(worker),
}
}
pub fn new(worker_url: Url,
+ worker: TrustedWorkerAddress,
cx: Rc<Cx>,
- receiver: Receiver<DOMString>,
resource_task: ResourceTask,
- script_chan: ScriptChan)
+ parent_sender: ScriptChan,
+ own_sender: ScriptChan,
+ receiver: Receiver<ScriptMsg>)
-> Temporary<DedicatedWorkerGlobalScope> {
let scope = box DedicatedWorkerGlobalScope::new_inherited(
- worker_url, cx.clone(), receiver, resource_task, script_chan);
+ worker_url, worker, cx.clone(), resource_task, parent_sender,
+ own_sender, receiver);
DedicatedWorkerGlobalScopeBinding::Wrap(cx.ptr, scope)
}
}
impl DedicatedWorkerGlobalScope {
pub fn run_worker_scope(worker_url: Url,
- receiver: Receiver<DOMString>,
+ worker: TrustedWorkerAddress,
resource_task: ResourceTask,
- script_chan: ScriptChan) {
+ parent_sender: ScriptChan,
+ own_sender: ScriptChan,
+ receiver: Receiver<ScriptMsg>) {
TaskBuilder::new()
.native()
.named(format!("Web Worker at {}", worker_url.serialize()))
@@ -84,13 +105,14 @@ impl DedicatedWorkerGlobalScope {
let (_js_runtime, js_context) = ScriptTask::new_rt_and_cx();
let global = DedicatedWorkerGlobalScope::new(
- worker_url, js_context.clone(), receiver, resource_task,
- script_chan).root();
+ worker_url, worker, js_context.clone(), resource_task,
+ parent_sender, own_sender, receiver).root();
match js_context.evaluate_script(
global.reflector().get_jsobject(), source, url.serialize(), 1) {
Ok(_) => (),
Err(_) => println!("evaluate_script failed")
}
+ global.delayed_release_worker();
let scope: &JSRef<WorkerGlobalScope> =
WorkerGlobalScopeCast::from_ref(&*global);
@@ -98,9 +120,28 @@ impl DedicatedWorkerGlobalScope {
EventTargetCast::from_ref(&*global);
loop {
match global.receiver.recv_opt() {
- Ok(message) => {
- MessageEvent::dispatch(target, &Worker(*scope), message)
+ Ok(DOMMessage(data, nbytes)) => {
+ let mut message = UndefinedValue();
+ unsafe {
+ assert!(JS_ReadStructuredClone(
+ js_context.ptr, data as *const u64, nbytes,
+ JS_STRUCTURED_CLONE_VERSION, &mut message,
+ ptr::null(), ptr::mut_null()) != 0);
+ }
+
+ MessageEvent::dispatch_jsval(target, &Worker(*scope), message);
+ global.delayed_release_worker();
+ },
+ Ok(XHRProgressMsg(addr, progress)) => {
+ XMLHttpRequest::handle_xhr_progress(addr, progress)
+ },
+ Ok(WorkerPostMessage(addr, data, nbytes)) => {
+ Worker::handle_message(addr, data, nbytes);
+ },
+ Ok(WorkerRelease(addr)) => {
+ Worker::handle_release(addr)
},
+ Ok(_) => fail!("Unexpected message"),
Err(_) => break,
}
}
@@ -108,7 +149,39 @@ impl DedicatedWorkerGlobalScope {
}
}
-pub trait DedicatedWorkerGlobalScopeMethods {
+impl<'a> DedicatedWorkerGlobalScopeMethods for JSRef<'a, DedicatedWorkerGlobalScope> {
+ fn PostMessage(&self, cx: *mut JSContext, message: JSVal) {
+ let mut data = ptr::mut_null();
+ let mut nbytes = 0;
+ unsafe {
+ assert!(JS_WriteStructuredClone(cx, message, &mut data, &mut nbytes,
+ ptr::null(), ptr::mut_null()) != 0);
+ }
+
+ let ScriptChan(ref sender) = self.parent_sender;
+ sender.send(WorkerPostMessage(*self.worker, data, nbytes));
+ }
+
+ fn GetOnmessage(&self) -> Option<EventHandlerNonNull> {
+ let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
+ eventtarget.get_event_handler_common("message")
+ }
+
+ fn SetOnmessage(&self, listener: Option<EventHandlerNonNull>) {
+ let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
+ eventtarget.set_event_handler_common("message", listener)
+ }
+}
+
+trait PrivateDedicatedWorkerGlobalScopeHelpers {
+ fn delayed_release_worker(&self);
+}
+
+impl<'a> PrivateDedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalScope> {
+ fn delayed_release_worker(&self) {
+ let ScriptChan(ref sender) = self.parent_sender;
+ sender.send(WorkerRelease(*self.worker));
+ }
}
impl Reflectable for DedicatedWorkerGlobalScope {
diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs
index eb9eb3d3929..69d8abaf75f 100644
--- a/src/components/script/dom/document.rs
+++ b/src/components/script/dom/document.rs
@@ -78,6 +78,7 @@ pub struct Document {
pub is_html_document: bool,
url: Untraceable<Url>,
quirks_mode: Untraceable<Cell<QuirksMode>>,
+ links: Cell<Option<JS<HTMLCollection>>>,
}
impl DocumentDerived for EventTarget {
@@ -86,6 +87,13 @@ impl DocumentDerived for EventTarget {
}
}
+struct LinksFilter;
+impl CollectionFilter for LinksFilter {
+ fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool {
+ (elem.is_htmlanchorelement() || elem.is_htmlareaelement()) && elem.has_attribute("href")
+ }
+}
+
pub trait DocumentHelpers {
fn url<'a>(&'a self) -> &'a Url;
fn quirks_mode(&self) -> QuirksMode;
@@ -228,6 +236,7 @@ impl Document {
// http://dom.spec.whatwg.org/#concept-document-encoding
encoding_name: Traceable::new(RefCell::new("utf-8".to_string())),
is_html_document: is_html_document == HTMLDocument,
+ links: Cell::new(None),
}
}
@@ -657,8 +666,6 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
fn Images(&self) -> Temporary<HTMLCollection> {
let window = self.window.root();
-
- // FIXME: https://github.com/mozilla/servo/issues/1847
struct ImagesFilter;
impl CollectionFilter for ImagesFilter {
fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool {
@@ -671,8 +678,6 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
fn Embeds(&self) -> Temporary<HTMLCollection> {
let window = self.window.root();
-
- // FIXME: https://github.com/mozilla/servo/issues/1847
struct EmbedsFilter;
impl CollectionFilter for EmbedsFilter {
fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool {
@@ -684,29 +689,21 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
}
fn Plugins(&self) -> Temporary<HTMLCollection> {
- // FIXME: https://github.com/mozilla/servo/issues/1847
self.Embeds()
}
fn Links(&self) -> Temporary<HTMLCollection> {
- let window = self.window.root();
-
- // FIXME: https://github.com/mozilla/servo/issues/1847
- struct LinksFilter;
- impl CollectionFilter for LinksFilter {
- fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool {
- (elem.is_htmlanchorelement() || elem.is_htmlareaelement()) &&
- elem.get_attribute(Null, "href").is_some()
- }
+ if self.links.get().is_none() {
+ let window = self.window.root();
+ let root = NodeCast::from_ref(self);
+ let filter = box LinksFilter;
+ self.links.assign(Some(HTMLCollection::create(&*window, root, filter)));
}
- let filter = box LinksFilter;
- HTMLCollection::create(&*window, NodeCast::from_ref(self), filter)
+ Temporary::new(self.links.get().get_ref().clone())
}
fn Forms(&self) -> Temporary<HTMLCollection> {
let window = self.window.root();
-
- // FIXME: https://github.com/mozilla/servo/issues/1847
struct FormsFilter;
impl CollectionFilter for FormsFilter {
fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool {
@@ -719,8 +716,6 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
fn Scripts(&self) -> Temporary<HTMLCollection> {
let window = self.window.root();
-
- // FIXME: https://github.com/mozilla/servo/issues/1847
struct ScriptsFilter;
impl CollectionFilter for ScriptsFilter {
fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool {
@@ -733,8 +728,6 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
fn Anchors(&self) -> Temporary<HTMLCollection> {
let window = self.window.root();
-
- // FIXME: https://github.com/mozilla/servo/issues/1847
struct AnchorsFilter;
impl CollectionFilter for AnchorsFilter {
fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool {
diff --git a/src/components/script/dom/location.rs b/src/components/script/dom/location.rs
index 2804f77957e..e310c52d49e 100644
--- a/src/components/script/dom/location.rs
+++ b/src/components/script/dom/location.rs
@@ -43,6 +43,7 @@ impl<'a> LocationMethods for JSRef<'a, Location> {
fn Search(&self) -> DOMString {
match self.page.get_url().query {
None => "".to_string(),
+ Some(ref query) if query.as_slice() == "" => "".to_string(),
Some(ref query) => "?".to_string().append(query.as_slice())
}
}
@@ -50,7 +51,8 @@ impl<'a> LocationMethods for JSRef<'a, Location> {
fn Hash(&self) -> DOMString {
match self.page.get_url().fragment {
None => "".to_string(),
- Some(ref query) => "#".to_string().append(query.as_slice())
+ Some(ref hash) if hash.as_slice() == "" => "".to_string(),
+ Some(ref hash) => "#".to_string().append(hash.as_slice())
}
}
}
diff --git a/src/components/script/dom/messageevent.rs b/src/components/script/dom/messageevent.rs
index a72e38cd650..13c8cf52dfd 100644
--- a/src/components/script/dom/messageevent.rs
+++ b/src/components/script/dom/messageevent.rs
@@ -6,7 +6,6 @@ use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::MessageEventBinding;
use dom::bindings::codegen::Bindings::MessageEventBinding::MessageEventMethods;
use dom::bindings::codegen::InheritTypes::{EventCast, MessageEventDerived};
-use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary};
@@ -68,12 +67,11 @@ impl MessageEvent {
}
impl MessageEvent {
- pub fn dispatch(target: &JSRef<EventTarget>,
- scope: &GlobalRef,
- message: DOMString) {
+ pub fn dispatch_jsval(target: &JSRef<EventTarget>,
+ scope: &GlobalRef,
+ message: JSVal) {
let messageevent = MessageEvent::new(
- scope, "message".to_string(), false, false,
- message.to_jsval(scope.get_cx()),
+ scope, "message".to_string(), false, false, message,
"".to_string(), "".to_string()).root();
let event: &JSRef<Event> = EventCast::from_ref(&*messageevent);
target.dispatch_event_with_target(None, &*event).unwrap();
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
index 8ebd4a3f874..5850779692c 100644
--- a/src/components/script/dom/node.rs
+++ b/src/components/script/dom/node.rs
@@ -18,7 +18,7 @@ use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDeri
use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast};
use dom::bindings::codegen::InheritTypes::{HTMLLegendElementDerived, HTMLFieldSetElementDerived};
use dom::bindings::codegen::InheritTypes::HTMLOptGroupElementDerived;
-use dom::bindings::error::{ErrorResult, Fallible, NotFound, HierarchyRequest, Syntax};
+use dom::bindings::error::{Fallible, NotFound, HierarchyRequest, Syntax};
use dom::bindings::global::{GlobalRef, Window};
use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root, OptionalUnrootable};
use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable};
@@ -1557,14 +1557,14 @@ impl<'a> NodeMethods for JSRef<'a, Node> {
}
// http://dom.spec.whatwg.org/#dom-node-nodevalue
- fn SetNodeValue(&self, val: Option<DOMString>) -> ErrorResult {
+ fn SetNodeValue(&self, val: Option<DOMString>) {
match self.type_id {
CommentNodeTypeId |
TextNodeTypeId |
ProcessingInstructionNodeTypeId => {
self.SetTextContent(val)
}
- _ => Ok(())
+ _ => {}
}
}
@@ -1596,7 +1596,7 @@ impl<'a> NodeMethods for JSRef<'a, Node> {
}
// http://dom.spec.whatwg.org/#dom-node-textcontent
- fn SetTextContent(&self, value: Option<DOMString>) -> ErrorResult {
+ fn SetTextContent(&self, value: Option<DOMString>) {
let value = null_str_as_empty(&value);
match self.type_id {
DocumentFragmentNodeTypeId |
@@ -1627,7 +1627,6 @@ impl<'a> NodeMethods for JSRef<'a, Node> {
DoctypeNodeTypeId |
DocumentNodeTypeId => {}
}
- Ok(())
}
// http://dom.spec.whatwg.org/#dom-node-insertbefore
diff --git a/src/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl b/src/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl
index c0c69219e1e..dbf2891f72a 100644
--- a/src/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl
+++ b/src/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl
@@ -5,6 +5,6 @@
// http://www.whatwg.org/html/#dedicatedworkerglobalscope
[Global/*=Worker,DedicatedWorker*/]
/*sealed*/ interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
- //void postMessage(any message, optional sequence<Transferable> transfer);
- // attribute EventHandler onmessage;
+ void postMessage(any message/*, optional sequence<Transferable> transfer*/);
+ attribute EventHandler onmessage;
};
diff --git a/src/components/script/dom/webidls/Node.webidl b/src/components/script/dom/webidls/Node.webidl
index acec121ccd2..3297b2c3ab1 100644
--- a/src/components/script/dom/webidls/Node.webidl
+++ b/src/components/script/dom/webidls/Node.webidl
@@ -46,9 +46,9 @@ interface Node : EventTarget {
[Pure]
readonly attribute Node? nextSibling;
- [SetterThrows, Pure]
+ [Pure]
attribute DOMString? nodeValue;
- [SetterThrows, Pure]
+ [Pure]
attribute DOMString? textContent;
void normalize();
diff --git a/src/components/script/dom/webidls/Worker.webidl b/src/components/script/dom/webidls/Worker.webidl
index 7eacefab9f4..2228c203781 100644
--- a/src/components/script/dom/webidls/Worker.webidl
+++ b/src/components/script/dom/webidls/Worker.webidl
@@ -14,8 +14,7 @@ interface AbstractWorker {
interface Worker : EventTarget {
//void terminate();
- //void postMessage(any message/*, optional sequence<Transferable> transfer*/);
- void postMessage(DOMString message);
- // attribute EventHandler onmessage;
+ void postMessage(any message/*, optional sequence<Transferable> transfer*/);
+ attribute EventHandler onmessage;
};
Worker implements AbstractWorker;
diff --git a/src/components/script/dom/worker.rs b/src/components/script/dom/worker.rs
index 88a9b10307a..3119b4c96f2 100644
--- a/src/components/script/dom/worker.rs
+++ b/src/components/script/dom/worker.rs
@@ -4,33 +4,53 @@
use dom::bindings::codegen::Bindings::WorkerBinding;
use dom::bindings::codegen::Bindings::WorkerBinding::WorkerMethods;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
+use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::error::{Fallible, Syntax};
-use dom::bindings::global::GlobalRef;
-use dom::bindings::js::{JSRef, Temporary};
-use dom::bindings::trace::Untraceable;
+use dom::bindings::global::{GlobalRef, GlobalField};
+use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
-use dom::eventtarget::{EventTarget, WorkerTypeId};
+use dom::eventtarget::{EventTarget, EventTargetHelpers, WorkerTypeId};
+use dom::messageevent::MessageEvent;
+use script_task::{ScriptChan, DOMMessage};
use servo_util::str::DOMString;
+
+use js::glue::JS_STRUCTURED_CLONE_VERSION;
+use js::jsapi::{JSContext, JS_AddObjectRoot, JS_RemoveObjectRoot};
+use js::jsapi::{JS_ReadStructuredClone, JS_WriteStructuredClone};
+use js::jsval::{JSVal, UndefinedValue};
use url::UrlParser;
+use libc::{c_void, size_t};
+use std::cell::Cell;
+use std::ptr;
+
+pub struct TrustedWorkerAddress(pub *const c_void);
+
#[deriving(Encodable)]
pub struct Worker {
eventtarget: EventTarget,
- sender: Untraceable<Sender<DOMString>>,
+ refcount: Cell<uint>,
+ global: GlobalField,
+ /// Sender to the Receiver associated with the DedicatedWorkerGlobalScope
+ /// this Worker created.
+ sender: ScriptChan,
}
impl Worker {
- pub fn new_inherited(sender: Sender<DOMString>) -> Worker {
+ pub fn new_inherited(global: &GlobalRef, sender: ScriptChan) -> Worker {
Worker {
eventtarget: EventTarget::new_inherited(WorkerTypeId),
- sender: Untraceable::new(sender),
+ refcount: Cell::new(0),
+ global: GlobalField::from_rooted(global),
+ sender: sender,
}
}
- pub fn new(global: &GlobalRef, sender: Sender<DOMString>) -> Temporary<Worker> {
- reflect_dom_object(box Worker::new_inherited(sender),
+ pub fn new(global: &GlobalRef, sender: ScriptChan) -> Temporary<Worker> {
+ reflect_dom_object(box Worker::new_inherited(global, sender),
global,
WorkerBinding::Wrap)
}
@@ -44,17 +64,92 @@ impl Worker {
Err(_) => return Err(Syntax),
};
- let (sender, receiver) = channel();
let resource_task = global.resource_task();
+ let (receiver, sender) = ScriptChan::new();
+
+ let worker = Worker::new(global, sender.clone()).root();
+ let worker_ref = worker.addref();
+
DedicatedWorkerGlobalScope::run_worker_scope(
- worker_url, receiver, resource_task, global.script_chan().clone());
- Ok(Worker::new(global, sender))
+ worker_url, worker_ref, resource_task, global.script_chan().clone(),
+ sender, receiver);
+
+ Ok(Temporary::from_rooted(&*worker))
+ }
+
+ pub fn handle_message(address: TrustedWorkerAddress,
+ data: *mut u64, nbytes: size_t) {
+ let worker = unsafe { JS::from_trusted_worker_address(address).root() };
+
+ let global = worker.global.root();
+
+ let mut message = UndefinedValue();
+ unsafe {
+ assert!(JS_ReadStructuredClone(
+ global.root_ref().get_cx(), data as *const u64, nbytes,
+ JS_STRUCTURED_CLONE_VERSION, &mut message,
+ ptr::null(), ptr::mut_null()) != 0);
+ }
+
+ let target: &JSRef<EventTarget> = EventTargetCast::from_ref(&*worker);
+ MessageEvent::dispatch_jsval(target, &global.root_ref(), message);
+ }
+}
+
+impl Worker {
+ // Creates a trusted address to the object, and roots it. Always pair this with a release()
+ pub fn addref(&self) -> TrustedWorkerAddress {
+ let refcount = self.refcount.get();
+ if refcount == 0 {
+ let cx = self.global.root().root_ref().get_cx();
+ unsafe {
+ JS_AddObjectRoot(cx, self.reflector().rootable());
+ }
+ }
+ self.refcount.set(refcount + 1);
+ TrustedWorkerAddress(self as *const Worker as *const c_void)
+ }
+
+ pub fn release(&self) {
+ let refcount = self.refcount.get();
+ assert!(refcount > 0)
+ self.refcount.set(refcount - 1);
+ if refcount == 1 {
+ let cx = self.global.root().root_ref().get_cx();
+ unsafe {
+ JS_RemoveObjectRoot(cx, self.reflector().rootable());
+ }
+ }
+ }
+
+ pub fn handle_release(address: TrustedWorkerAddress) {
+ let worker = unsafe { JS::from_trusted_worker_address(address).root() };
+ worker.release();
}
}
impl<'a> WorkerMethods for JSRef<'a, Worker> {
- fn PostMessage(&self, message: DOMString) {
- self.sender.send(message);
+ fn PostMessage(&self, cx: *mut JSContext, message: JSVal) {
+ let mut data = ptr::mut_null();
+ let mut nbytes = 0;
+ unsafe {
+ assert!(JS_WriteStructuredClone(cx, message, &mut data, &mut nbytes,
+ ptr::null(), ptr::mut_null()) != 0);
+ }
+
+ self.addref();
+ let ScriptChan(ref sender) = self.sender;
+ sender.send(DOMMessage(data, nbytes));
+ }
+
+ fn GetOnmessage(&self) -> Option<EventHandlerNonNull> {
+ let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
+ eventtarget.get_event_handler_common("message")
+ }
+
+ fn SetOnmessage(&self, listener: Option<EventHandlerNonNull>) {
+ let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
+ eventtarget.set_event_handler_common("message", listener)
}
}
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs
index 2f7df8d6ddd..f7873ca3c24 100644
--- a/src/components/script/script_task.rs
+++ b/src/components/script/script_task.rs
@@ -20,6 +20,7 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers};
use dom::node;
use dom::node::{ElementNodeTypeId, Node, NodeHelpers};
use dom::window::{TimerId, Window, WindowHelpers};
+use dom::worker::{Worker, TrustedWorkerAddress};
use dom::xmlhttprequest::{TrustedXHRAddress, XMLHttpRequest, XHRProgress};
use html::hubbub_html_parser::HtmlParserResult;
use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredScript};
@@ -31,12 +32,6 @@ use layout_interface::ContentChangedDocumentDamage;
use layout_interface;
use page::{Page, IterablePage, Frame};
-use geom::point::Point2D;
-use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
-use js::jsapi::{JSContext, JSRuntime};
-use js::rust::{Cx, RtUtils};
-use js::rust::with_compartment;
-use js;
use script_traits::{CompositorEvent, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent};
use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, ScriptTaskFactory};
use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, SendEventMsg, ResizeInactiveMsg};
@@ -51,31 +46,51 @@ use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::geometry::to_frac_px;
use servo_util::task::spawn_named_with_send_on_failure;
+
+use geom::point::Point2D;
+use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
+use js::jsapi::{JSContext, JSRuntime};
+use js::rust::{Cx, RtUtils};
+use js::rust::with_compartment;
+use js;
+use url::Url;
+
+use libc::size_t;
+use serialize::{Encoder, Encodable};
use std::any::{Any, AnyRefExt};
use std::cell::RefCell;
use std::comm::{channel, Sender, Receiver, Select};
use std::mem::replace;
use std::rc::Rc;
-use url::Url;
-
-use serialize::{Encoder, Encodable};
local_data_key!(pub StackRoots: *const RootCollection)
-/// Messages used to control the script task.
+/// Messages used to control script event loops, such as ScriptTask and
+/// DedicatedWorkerGlobalScope.
pub enum ScriptMsg {
- /// Acts on a fragment URL load on the specified pipeline.
+ /// Acts on a fragment URL load on the specified pipeline (only dispatched
+ /// to ScriptTask).
TriggerFragmentMsg(PipelineId, Url),
- /// Begins a content-initiated load on the specified pipeline.
+ /// Begins a content-initiated load on the specified pipeline (only
+ /// dispatched to ScriptTask).
TriggerLoadMsg(PipelineId, Url),
- /// Instructs the script task to send a navigate message to the constellation.
+ /// Instructs the script task to send a navigate message to
+ /// the constellation (only dispatched to ScriptTask).
NavigateMsg(NavigationDirection),
- /// Fires a JavaScript timeout.
+ /// Fires a JavaScript timeout (only dispatched to ScriptTask).
FireTimerMsg(PipelineId, TimerId),
- /// Notifies the script that a window associated with a particular pipeline should be closed.
+ /// Notifies the script that a window associated with a particular pipeline
+ /// should be closed (only dispatched to ScriptTask).
ExitWindowMsg(PipelineId),
- /// Notifies the script of progress on a fetch
- XHRProgressMsg(TrustedXHRAddress, XHRProgress)
+ /// Notifies the script of progress on a fetch (dispatched to all tasks).
+ XHRProgressMsg(TrustedXHRAddress, XHRProgress),
+ /// Message sent through Worker.postMessage (only dispatched to
+ /// DedicatedWorkerGlobalScope).
+ DOMMessage(*mut u64, size_t),
+ /// Posts a message to the Worker object (dispatched to all tasks).
+ WorkerPostMessage(TrustedWorkerAddress, *mut u64, size_t),
+ /// Releases one reference to the Worker object (dispatched to all tasks).
+ WorkerRelease(TrustedWorkerAddress),
}
/// Encapsulates internal communication within the script task.
@@ -430,6 +445,9 @@ impl ScriptTask {
FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id),
FromConstellation(ResizeMsg(..)) => fail!("should have handled ResizeMsg already"),
FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_xhr_progress(addr, progress),
+ FromScript(DOMMessage(..)) => fail!("unexpected message"),
+ FromScript(WorkerPostMessage(addr, data, nbytes)) => Worker::handle_message(addr, data, nbytes),
+ FromScript(WorkerRelease(addr)) => Worker::handle_release(addr),
}
}