diff options
Diffstat (limited to 'src/components/script')
-rw-r--r-- | src/components/script/dom/bindings/global.rs | 2 | ||||
-rw-r--r-- | src/components/script/dom/bindings/js.rs | 10 | ||||
-rw-r--r-- | src/components/script/dom/dedicatedworkerglobalscope.rs | 105 | ||||
-rw-r--r-- | src/components/script/dom/document.rs | 37 | ||||
-rw-r--r-- | src/components/script/dom/location.rs | 4 | ||||
-rw-r--r-- | src/components/script/dom/messageevent.rs | 10 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 9 | ||||
-rw-r--r-- | src/components/script/dom/webidls/DedicatedWorkerGlobalScope.webidl | 4 | ||||
-rw-r--r-- | src/components/script/dom/webidls/Node.webidl | 4 | ||||
-rw-r--r-- | src/components/script/dom/webidls/Worker.webidl | 5 | ||||
-rw-r--r-- | src/components/script/dom/worker.rs | 123 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 52 |
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), } } |