diff options
author | Josh Matthews <josh@joshmatthews.net> | 2014-03-31 18:41:28 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2014-05-03 14:18:30 -0400 |
commit | d7b96db33ca8f2b8a162df38e0f00e95f5ea6fa1 (patch) | |
tree | efd1e7f7ec1dd30467c2a67306e1a639837abead /src/components/script/script_task.rs | |
parent | ffdc3f5b32a345b88eed774848924e862d47c093 (diff) | |
download | servo-d7b96db33ca8f2b8a162df38e0f00e95f5ea6fa1.tar.gz servo-d7b96db33ca8f2b8a162df38e0f00e95f5ea6fa1.zip |
Implement safe rooting strategy via Unrooted, Root, JSRef, and JS.
Diffstat (limited to 'src/components/script/script_task.rs')
-rw-r--r-- | src/components/script/script_task.rs | 159 |
1 files changed, 83 insertions, 76 deletions
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index f442ddae7c1..f29a18b850a 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -7,7 +7,8 @@ use dom::bindings::codegen::RegisterBindings; use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast, ElementCast, EventCast}; -use dom::bindings::js::{JS, JSRef, RootCollection, RootedReference}; +use dom::bindings::js::{JS, JSRef, RootCollection, Unrooted, OptionalAssignable}; +use dom::bindings::js::OptionalRootable; use dom::bindings::trace::{Traceable, Untraceable}; use dom::bindings::utils::{Reflectable, GlobalStaticData, wrap_for_same_compartment}; use dom::document::{Document, HTMLDocument}; @@ -16,6 +17,7 @@ use dom::event::{Event_, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, M use dom::event::Event; use dom::uievent::UIEvent; use dom::eventtarget::EventTarget; +use dom::node; use dom::node::{Node, NodeHelpers}; use dom::window::{TimerId, Window}; use html::hubbub_html_parser::HtmlParserResult; @@ -272,14 +274,15 @@ impl Page { /// Adds the given damage. pub fn damage(&self, level: DocumentDamageLevel) { + let roots = RootCollection::new(); let root = match *self.frame() { None => return, Some(ref frame) => frame.document.get().GetDocumentElement() }; - match root { + match root.root(&roots) { None => {}, Some(root) => { - let root: JS<Node> = NodeCast::from(&root); + let root: &JSRef<Node> = NodeCast::from_ref(&*root); let mut damage = *self.damage.deref().borrow_mut(); match damage { None => {} @@ -351,6 +354,8 @@ impl Page { goal: ReflowGoal, script_chan: ScriptChan, compositor: &ScriptListener) { + let roots = RootCollection::new(); + let root = match *self.frame() { None => return, Some(ref frame) => { @@ -358,7 +363,7 @@ impl Page { } }; - match root { + match root.root(&roots) { None => {}, Some(root) => { debug!("script: performing reflow for goal {:?}", goal); @@ -377,7 +382,7 @@ impl Page { let mut last_reflow_id = self.last_reflow_id.deref().borrow_mut(); *last_reflow_id += 1; - let root: JS<Node> = NodeCast::from(&root); + let root: &JSRef<Node> = NodeCast::from_ref(&*root); let mut damage = self.damage.deref().borrow_mut(); let window_size = self.window_size.deref().borrow(); @@ -401,19 +406,21 @@ impl Page { } } - fn find_fragment_node(&self, fragid: ~str) -> Option<JS<Element>> { - let document = self.frame().get_ref().document.clone(); + fn find_fragment_node(&self, fragid: ~str) -> Option<Unrooted<Element>> { + let roots = RootCollection::new(); + let document = self.frame().get_ref().document.root(&roots); match document.get().GetElementById(fragid.to_owned()) { Some(node) => Some(node), None => { - let doc_node: JS<Node> = NodeCast::from(&document); - let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element()); + let doc_node: &JSRef<Node> = NodeCast::from_ref(&*document); + let mut anchors = doc_node.traverse_preorder(&roots) + .filter(|node| node.is_anchor_element()); anchors.find(|node| { - let elem: JS<Element> = ElementCast::to(node).unwrap(); - elem.get_attribute(Null, "name").map_or(false, |attr| { + let elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); + elem.get_attribute(Null, "name").root(&roots).map_or(false, |attr| { attr.get().value_ref() == fragid }) - }).map(|node| ElementCast::to(&node).unwrap()) + }).map(|node| Unrooted::new_rooted(ElementCast::to_ref(&node).unwrap())) } } } @@ -435,13 +442,15 @@ impl Page { } pub fn hit_test(&self, point: &Point2D<f32>) -> Option<UntrustedNodeAddress> { + let roots = RootCollection::new(); let frame = self.frame(); let document = frame.get_ref().document.clone(); - let root = document.get().GetDocumentElement(); + let root = document.get().GetDocumentElement().root(&roots); if root.is_none() { return None; } - let root: JS<Node> = NodeCast::from(&root.unwrap()); + let root = root.unwrap(); + let root: &JSRef<Node> = NodeCast::from_ref(&*root); let (chan, port) = channel(); let address = match self.query_layout(HitTestQuery(root.to_trusted_node_address(), *point, chan), port) { Ok(HitTestResponse(node_address)) => { @@ -456,13 +465,15 @@ impl Page { } pub fn get_nodes_under_mouse(&self, point: &Point2D<f32>) -> Option<Vec<UntrustedNodeAddress>> { + let roots = RootCollection::new(); let frame = self.frame(); let document = frame.get_ref().document.clone(); - let root = document.get().GetDocumentElement(); + let root = document.get().GetDocumentElement().root(&roots); if root.is_none() { return None; } - let root: JS<Node> = NodeCast::from(&root.unwrap()); + let root = root.unwrap(); + let root: &JSRef<Node> = NodeCast::from_ref(&*root); let (chan, port) = channel(); let address = match self.query_layout(MouseOverQuery(root.to_trusted_node_address(), *point, chan), port) { Ok(MouseOverResponse(node_address)) => { @@ -868,16 +879,14 @@ impl ScriptTask { page_tree.page.clone(), self.chan.clone(), self.compositor.dup(), - self.image_cache_task.clone()); - let window_root = window.root(&roots); + self.image_cache_task.clone()).root(&roots); page.initialize_js_info(cx.clone(), window.reflector().get_jsobject()); - let mut document = Document::new(&window_root.root_ref(), Some(url.clone()), HTMLDocument, None); - let doc_root = document.root(&roots); - window.get_mut().init_browser_context(&document); + let mut document = Document::new(&*window, Some(url.clone()), HTMLDocument, None).root(&roots); + window.get_mut().init_browser_context(&*document); { let mut js_info = page.mut_js_info(); - RegisterBindings::Register(&window_root.root_ref(), js_info.get_mut_ref()); + RegisterBindings::Register(&*window, js_info.get_mut_ref()); } self.compositor.set_ready_state(Loading); @@ -885,7 +894,7 @@ impl ScriptTask { // // Note: We can parse the next document in parallel with any previous documents. let html_parsing_result = hubbub_html_parser::parse_html(page, - &mut doc_root.root_ref(), + &mut *document, url.clone(), self.resource_task.clone()); @@ -897,8 +906,8 @@ impl ScriptTask { // Create the root frame. let mut frame = page.mut_frame(); *frame = Some(Frame { - document: document.clone(), - window: window.clone(), + document: document.deref().unrooted(), + window: window.deref().unrooted(), }); } @@ -973,26 +982,24 @@ impl ScriptTask { // We have no concept of a document loader right now, so just dispatch the // "load" event as soon as we've finished executing all scripts parsed during // the initial load. - let mut event = Event::new(&window_root.root_ref()); + let mut event = Event::new(&*window).root(&roots); event.get_mut().InitEvent(~"load", false, false); - let event = event.root(&roots); - let doctarget = EventTargetCast::from(&document); - let doctarget = doctarget.root(&roots); - let mut wintarget: JS<EventTarget> = EventTargetCast::from(&window); - let wintarget_root = wintarget.root(&roots); - let _ = wintarget.get_mut().dispatch_event_with_target(&wintarget_root.root_ref(), - Some(doctarget.root_ref()), - &mut event.root_ref()); + let doctarget: &JSRef<EventTarget> = EventTargetCast::from_ref(&*document); + let wintarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(&mut *window); + let wintarget_alias = wintarget.clone(); + let _ = wintarget.get_mut().dispatch_event_with_target(&wintarget_alias, + Some((*doctarget).clone()), + &mut *event); let mut fragment_node = page.fragment_node.deref().borrow_mut(); - *fragment_node = fragment.map_or(None, |fragid| page.find_fragment_node(fragid)); + (*fragment_node).assign(fragment.map_or(None, |fragid| page.find_fragment_node(fragid))); let ConstellationChan(ref chan) = self.constellation_chan; chan.send(LoadCompleteMsg(page.id, url)); } - fn scroll_fragment_point(&self, pipeline_id: PipelineId, node: JS<Element>) { - let node: JS<Node> = NodeCast::from(&node); + fn scroll_fragment_point(&self, pipeline_id: PipelineId, node: &JSRef<Element>) { + let node: &JSRef<Node> = NodeCast::from_ref(node); let rect = node.get_bounding_content_box(); let point = Point2D(to_frac_px(rect.origin.x).to_f32().unwrap(), to_frac_px(rect.origin.y).to_f32().unwrap()); @@ -1015,6 +1022,7 @@ impl ScriptTask { match event { ResizeEvent(new_width, new_height) => { + let roots = RootCollection::new(); debug!("script got resize event: {:u}, {:u}", new_width, new_height); let window = { @@ -1032,31 +1040,28 @@ impl ScriptTask { } let mut fragment_node = page.fragment_node.deref().borrow_mut(); - match fragment_node.take() { - Some(node) => self.scroll_fragment_point(pipeline_id, node), + match fragment_node.take().map(|node| node.root(&roots)) { + Some(node) => self.scroll_fragment_point(pipeline_id, &*node), None => {} } - frame.as_ref().map(|frame| frame.window.clone()) + frame.as_ref().map(|frame| Unrooted::new(frame.window.clone())) }; - match window { - Some(ref window) => { + match window.root(&roots) { + Some(mut window) => { // http://dev.w3.org/csswg/cssom-view/#resizing-viewports // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-resize - let roots = RootCollection::new(); - let window_root = window.root(&roots); - - let mut uievent = UIEvent::new(&window_root.root_ref()); - uievent.get_mut().InitUIEvent(~"resize", false, false, Some(window_root).root_ref(), 0i32); - let event: JS<Event> = EventCast::from(&uievent); - let event = event.root(&roots); - - let mut wintarget: JS<EventTarget> = EventTargetCast::from(window); - let targetroot = wintarget.root(&roots); - let _ = wintarget.get_mut().dispatch_event_with_target(&targetroot.root_ref(), + let mut uievent = UIEvent::new(&*window).root(&roots); + uievent.get_mut().InitUIEvent(~"resize", false, false, + Some((*window).clone()), 0i32); + let event: &mut JSRef<Event> = EventCast::from_mut_ref(&mut *uievent); + + let wintarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(&mut *window); + let wintarget_alias = wintarget.clone(); + let _ = wintarget.get_mut().dispatch_event_with_target(&wintarget_alias, None, - &mut event.root_ref()); + &mut *event); } None => () } @@ -1076,32 +1081,31 @@ impl ScriptTask { } ClickEvent(_button, point) => { + let roots = RootCollection::new(); debug!("ClickEvent: clicked at {:?}", point); let mut page_tree = self.page_tree.borrow_mut(); let page = get_page(&mut *page_tree, pipeline_id); match page.hit_test(&point) { Some(node_address) => { debug!("node address is {:?}", node_address); - let mut node: JS<Node> = - NodeHelpers::from_untrusted_node_address(self.js_runtime.deref().ptr, - node_address); - debug!("clicked on {:s}", node.debug_str()); + let mut node = + node::from_untrusted_node_address(self.js_runtime.deref().ptr, + node_address).root(&roots); + debug!("clicked on {:s}", node.deref().debug_str()); // Traverse node generations until a node that is an element is // found. - while !node.is_element() { - match node.parent_node() { - Some(parent) => node = parent, + while !node.deref().is_element() { + match node.deref().parent_node() { + Some(parent) => node = parent.root(&roots), None => break, } } - if node.is_element() { - let element: JS<Element> = ElementCast::to(&node).unwrap(); + if node.deref().is_element() { + let element: &JSRef<Element> = ElementCast::to_ref(&*node).unwrap(); if "a" == element.get().local_name { - let roots = RootCollection::new(); - let element = element.root(&roots); - self.load_url_from_element(page, &element.root_ref()) + self.load_url_from_element(page, element) } } } @@ -1112,6 +1116,7 @@ impl ScriptTask { MouseDownEvent(..) => {} MouseUpEvent(..) => {} MouseMoveEvent(point) => { + let roots = RootCollection::new(); let mut page_tree = self.page_tree.borrow_mut(); let page = get_page(&mut *page_tree, pipeline_id); match page.get_nodes_under_mouse(&point) { @@ -1124,6 +1129,7 @@ impl ScriptTask { match *mouse_over_targets { Some(ref mut mouse_over_targets) => { for node in mouse_over_targets.mut_iter() { + let mut node = node.root(&roots); node.set_hover_state(false); } } @@ -1131,14 +1137,14 @@ impl ScriptTask { } for node_address in node_address.iter() { - let mut node: JS<Node> = - NodeHelpers::from_untrusted_node_address( - self.js_runtime.deref().ptr, *node_address); + let mut node = + node::from_untrusted_node_address( + self.js_runtime.deref().ptr, *node_address).root(&roots); // Traverse node generations until a node that is an element is // found. while !node.is_element() { match node.parent_node() { - Some(parent) => node = parent, + Some(parent) => node = parent.root(&roots), None => break, } } @@ -1149,12 +1155,12 @@ impl ScriptTask { match *mouse_over_targets { Some(ref mouse_over_targets) => { if !target_compare { - target_compare = !mouse_over_targets.contains(&node); + target_compare = !mouse_over_targets.contains(&node.unrooted()); } } None => {} } - target_list.push(node); + target_list.push(node.unrooted()); } } match *mouse_over_targets { @@ -1182,9 +1188,10 @@ impl ScriptTask { } fn load_url_from_element(&self, page: &Page, element: &JSRef<Element>) { + let roots = RootCollection::new(); // if the node's element is "a," load url from href attr - let attr = element.unrooted().get_attribute(Null, "href"); - for href in attr.iter() { + let attr = element.get_attribute(Null, "href"); + for href in attr.root(&roots).iter() { debug!("ScriptTask: clicked on link to {:s}", href.get().Value()); let click_frag = href.get().value_ref().starts_with("#"); let base_url = Some(page.get_url()); @@ -1192,8 +1199,8 @@ impl ScriptTask { let url = parse_url(href.get().value_ref(), base_url); if click_frag { - match page.find_fragment_node(url.fragment.unwrap()) { - Some(node) => self.scroll_fragment_point(page.id, node), + match page.find_fragment_node(url.fragment.unwrap()).root(&roots) { + Some(node) => self.scroll_fragment_point(page.id, &*node), None => {} } } else { |