diff options
Diffstat (limited to 'components/script/script_task.rs')
-rw-r--r-- | components/script/script_task.rs | 136 |
1 files changed, 87 insertions, 49 deletions
diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 2d64f53b396..0f3f5c1b564 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -12,11 +12,11 @@ use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, Documen use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; -use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, NodeCast, EventCast}; +use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, HTMLIFrameElementCast, NodeCast, EventCast}; use dom::bindings::conversions::FromJSValConvertible; use dom::bindings::conversions::StringificationBehavior; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable}; +use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, RootedReference}; use dom::bindings::js::{RootCollection, RootCollectionPtr}; use dom::bindings::refcounted::{LiveDOMReferences, Trusted, TrustedReference}; use dom::bindings::structuredclone::StructuredCloneData; @@ -28,10 +28,12 @@ use dom::event::{Event, EventHelpers, EventBubbles, EventCancelable}; use dom::uievent::UIEvent; use dom::eventtarget::{EventTarget, EventTargetHelpers}; use dom::htmlelement::HTMLElementTypeId; +use dom::htmliframeelement::HTMLIFrameElement; use dom::keyboardevent::KeyboardEvent; use dom::mouseevent::MouseEvent; use dom::node::{self, Node, NodeHelpers, NodeDamage, NodeTypeId}; use dom::window::{Window, WindowHelpers, ScriptHelpers}; +use dom::worker::{Worker, TrustedWorkerAddress}; use parse::html::{HTMLInput, parse_html}; use layout_interface::{ScriptLayoutChan, LayoutChan, ReflowGoal, ReflowQueryType}; use layout_interface; @@ -41,7 +43,7 @@ use devtools; use devtools_traits::{DevtoolsControlChan, DevtoolsControlPort, NewGlobal, GetRootNode, DevtoolsPageInfo}; use devtools_traits::{DevtoolScriptControlMsg, EvaluateJS, GetDocumentElement}; -use devtools_traits::{GetChildren, GetLayout, ModifyAttribute}; +use devtools_traits::{GetChildren, GetLayout, ModifyAttribute, WantsLiveNotifications}; use script_traits::CompositorEvent; use script_traits::CompositorEvent::{ResizeEvent, ReflowEvent, ClickEvent}; use script_traits::CompositorEvent::{MouseDownEvent, MouseUpEvent}; @@ -52,7 +54,7 @@ use script_traits::ScriptTaskFactory; use servo_msg::compositor_msg::ReadyState::{FinishedLoading, Loading, PerformingLayout}; use servo_msg::compositor_msg::{LayerId, ScriptListener}; use servo_msg::constellation_msg::{ConstellationChan}; -use servo_msg::constellation_msg::{LoadData, NavigationDirection, PipelineId}; +use servo_msg::constellation_msg::{LoadData, NavigationDirection, PipelineId, SubpageId}; use servo_msg::constellation_msg::{Failure, Msg, WindowSizeData, Key, KeyState}; use servo_msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT}; use servo_msg::constellation_msg::{PipelineExitType}; @@ -63,6 +65,7 @@ use servo_net::resource_task::LoadData as NetLoadData; use servo_net::storage_task::StorageTask; use util::geometry::to_frac_px; use util::smallvec::SmallVec; +use util::str::DOMString; use util::task::spawn_named_with_send_on_failure; use util::task_state; @@ -123,6 +126,8 @@ pub enum ScriptMsg { /// Message sent through Worker.postMessage (only dispatched to /// DedicatedWorkerGlobalScope). DOMMessage(StructuredCloneData), + /// Sends a message to the Worker object (dispatched to all tasks) regarding error. + WorkerDispatchErrorEvent(TrustedWorkerAddress, DOMString, DOMString, u32, u32), /// Generic message that encapsulates event handling. RunnableMsg(Box<Runnable+Send>), /// A DOM object's last pinned reference was removed (dispatched to all tasks). @@ -379,7 +384,8 @@ impl ScriptTask { resource_task.clone(), storage_task, constellation_chan.clone(), - js_context.clone()); + js_context.clone(), + devtools_chan.clone()); let (devtools_sender, devtools_receiver) = channel(); ScriptTask { @@ -581,8 +587,8 @@ impl ScriptTask { match msg { ConstellationControlMsg::AttachLayout(_) => panic!("should have handled AttachLayout already"), - ConstellationControlMsg::Load(id, load_data) => - self.load(id, load_data), + ConstellationControlMsg::Load(id, parent, load_data) => + self.load(id, parent, load_data), ConstellationControlMsg::SendEvent(id, event) => self.handle_event(id, event), ConstellationControlMsg::ReflowComplete(id, reflow_id) => @@ -616,6 +622,8 @@ impl ScriptTask { self.handle_exit_window_msg(id), ScriptMsg::DOMMessage(..) => panic!("unexpected message"), + ScriptMsg::WorkerDispatchErrorEvent(addr, msg, file_name,line_num, col_num) => + Worker::handle_error_message(addr, msg, file_name, line_num, col_num), ScriptMsg::RunnableMsg(runnable) => runnable.handler(), ScriptMsg::RefcountCleanup(addr) => @@ -637,6 +645,8 @@ impl ScriptTask { devtools::handle_get_layout(&*self.page.borrow(), id, node_id, reply), ModifyAttribute(id, node_id, modifications) => devtools::handle_modify_attribute(&*self.page.borrow(), id, node_id, modifications), + WantsLiveNotifications(pipeline_id, to_send) => + devtools::handle_wants_live_notifications(&*self.page.borrow(), pipeline_id, to_send), } } @@ -660,7 +670,8 @@ impl ScriptTask { parent_page.resource_task.clone(), parent_page.storage_task.clone(), self.constellation_chan.clone(), - self.js_context.borrow().as_ref().unwrap().clone()) + self.js_context.borrow().as_ref().unwrap().clone(), + self.devtools_chan.clone()) }; parent_page.children.borrow_mut().push(Rc::new(new_page)); } @@ -742,9 +753,10 @@ impl ScriptTask { } // otherwise find just the matching page and exit all sub-pages - match page.remove(id) { + match page.find(id) { Some(ref mut page) => { shut_down_layout(&*page, (*self.js_runtime).ptr, exit_type); + page.remove(id); false } // TODO(tkuehn): pipeline closing is currently duplicated across @@ -757,12 +769,37 @@ impl ScriptTask { /// The entry point to document loading. Defines bindings, sets up the window and document /// objects, parses HTML and CSS, and kicks off initial layout. - fn load(&self, pipeline_id: PipelineId, load_data: LoadData) { + fn load(&self, pipeline_id: PipelineId, + parent: Option<(PipelineId, SubpageId)>, load_data: LoadData) { let url = load_data.url.clone(); debug!("ScriptTask: loading {:?} on page {:?}", url, pipeline_id); - let page = self.page.borrow_mut(); - let page = page.find(pipeline_id).expect("ScriptTask: received a load + let borrowed_page = self.page.borrow_mut(); + + let frame_element = parent.and_then(|(parent_id, subpage_id)| { + // In the case a parent id exists but the matching page + // cannot be found, this means the page exists in a different + // script task (due to origin) so it shouldn't be returned. + // TODO: window.parent will continue to return self in that + // case, which is wrong. We should be returning an object that + // denies access to most properties (per + // https://github.com/servo/servo/issues/3939#issuecomment-62287025). + borrowed_page.find(parent_id).and_then(|page| { + let match_iframe = |&:&node: &JSRef<HTMLIFrameElement>| { + node.subpage_id().map_or(false, |id| id == subpage_id) + }; + + let doc = page.frame().as_ref().unwrap().document.root(); + let doc: JSRef<Node> = NodeCast::from_ref(doc.r()); + + doc.traverse_preorder() + .filter_map(|node| HTMLIFrameElementCast::to_ref(node)) + .find(match_iframe) + .map(|node| Temporary::from_rooted(ElementCast::from_ref(node))) + }) + }).root(); + + let page = borrowed_page.find(pipeline_id).expect("ScriptTask: received a load message for a layout channel that is not associated with this script task. This is a bug."); @@ -839,9 +876,9 @@ impl ScriptTask { IsHTMLDocument::HTMLDocument, None, DocumentSource::FromParser).root(); if let Some(tm) = last_modified { - document.set_last_modified(dom_last_modified(&tm)); + document.r().set_last_modified(dom_last_modified(&tm)); } - window.r().init_browser_context(document.r()); + window.r().init_browser_context(document.r(), frame_element.r()); { @@ -943,7 +980,7 @@ impl ScriptTask { fn handle_event(&self, pipeline_id: PipelineId, event: CompositorEvent) { match event { ResizeEvent(new_size) => { - self.handle_resize_event(pipeline_id, new_size); + self.handle_resize_event(pipeline_id, new_size); } ReflowEvent(nodes) => { @@ -971,13 +1008,13 @@ impl ScriptTask { } ClickEvent(_button, point) => { - self.handle_click_event(pipeline_id, _button, point); + self.handle_click_event(pipeline_id, _button, point); } MouseDownEvent(..) => {} MouseUpEvent(..) => {} MouseMoveEvent(point) => { - self.handle_mouse_move_event(pipeline_id, point); + self.handle_mouse_move_event(pipeline_id, point); } KeyEvent(key, state, modifiers) => { @@ -1145,8 +1182,8 @@ impl ScriptTask { debug!("node address is {:?}", node_address.0); let temp_node = - node::from_untrusted_node_address( - self.js_runtime.ptr, node_address).root(); + node::from_untrusted_node_address( + self.js_runtime.ptr, node_address).root(); let maybe_elem: Option<JSRef<Element>> = ElementCast::to_ref(temp_node.r()); let maybe_node = match maybe_elem { @@ -1210,37 +1247,37 @@ impl ScriptTask { } if node_address.len() > 0 { - let top_most_node = - node::from_untrusted_node_address(self.js_runtime.ptr, node_address[0]).root(); - - if let Some(ref frame) = *page.frame() { - let window = frame.window.root(); - - let x = point.x.to_i32().unwrap_or(0); - let y = point.y.to_i32().unwrap_or(0); - - let mouse_event = MouseEvent::new(window.r(), - "mousemove".to_owned(), - true, - true, - Some(window.r()), - 0i32, - x, y, x, y, - false, false, false, false, - 0i16, - None).root(); - - let event: JSRef<Event> = EventCast::from_ref(mouse_event.r()); - let target: JSRef<EventTarget> = EventTargetCast::from_ref(top_most_node.r()); - event.fire(target); - } + let top_most_node = + node::from_untrusted_node_address(self.js_runtime.ptr, node_address[0]).root(); + + if let Some(ref frame) = *page.frame() { + let window = frame.window.root(); + + let x = point.x.to_i32().unwrap_or(0); + let y = point.y.to_i32().unwrap_or(0); + + let mouse_event = MouseEvent::new(window.r(), + "mousemove".to_owned(), + true, + true, + Some(window.r()), + 0i32, + x, y, x, y, + false, false, false, false, + 0i16, + None).root(); + + let event: JSRef<Event> = EventCast::from_ref(mouse_event.r()); + let target: JSRef<EventTarget> = EventTargetCast::from_ref(top_most_node.r()); + event.fire(target); + } } for node_address in node_address.iter() { let temp_node = - node::from_untrusted_node_address(self.js_runtime.ptr, *node_address); + node::from_untrusted_node_address(self.js_runtime.ptr, *node_address).root(); - let maybe_node = temp_node.root().ancestors().find(|node| node.is_element()); + let maybe_node = temp_node.r().ancestors().find(|node| node.is_element()); match maybe_node { Some(node) => { node.set_hover_state(true); @@ -1285,8 +1322,9 @@ fn shut_down_layout(page_tree: &Rc<Page>, rt: *mut JSRuntime, exit_type: Pipelin // processed this message. let (response_chan, response_port) = channel(); let LayoutChan(ref chan) = page.layout_chan; - chan.send(layout_interface::Msg::PrepareToExit(response_chan)).unwrap(); - response_port.recv().unwrap(); + if chan.send(layout_interface::Msg::PrepareToExit(response_chan)).is_ok() { + response_port.recv().unwrap(); + } } // Remove our references to the DOM objects in this page tree. @@ -1308,7 +1346,7 @@ fn shut_down_layout(page_tree: &Rc<Page>, rt: *mut JSRuntime, exit_type: Pipelin // Destroy the layout task. If there were node leaks, layout will now crash safely. for page in page_tree.iter() { let LayoutChan(ref chan) = page.layout_chan; - chan.send(layout_interface::Msg::ExitNow(exit_type)).unwrap(); + chan.send(layout_interface::Msg::ExitNow(exit_type)).ok(); } } @@ -1392,7 +1430,7 @@ impl DocumentProgressHandler { EventCancelable::NotCancelable).root(); let wintarget: JSRef<EventTarget> = EventTargetCast::from_ref(window.r()); let doctarget: JSRef<EventTarget> = EventTargetCast::from_ref(document.r()); - event.set_trusted(true); + event.r().set_trusted(true); let _ = wintarget.dispatch_event_with_target(doctarget, event.r()); } } |