diff options
Diffstat (limited to 'src/components/script/script_task.rs')
-rw-r--r-- | src/components/script/script_task.rs | 129 |
1 files changed, 46 insertions, 83 deletions
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 1938ef92ff3..4b70c13f0cc 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -14,15 +14,15 @@ use dom::event::Event; use dom::eventtarget::AbstractEventTarget; use dom::htmldocument::HTMLDocument; use dom::namespace::Null; -use dom::node::{AbstractNode, LayoutDataRef}; -use dom::window::{TimerData, Window}; +use dom::node::AbstractNode; +use dom::window::{TimerData, TimerHandle, Window}; use html::hubbub_html_parser::HtmlParserResult; use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredIFrame, HtmlDiscoveredScript}; use html::hubbub_html_parser; use layout_interface::{AddStylesheetMsg, DocumentDamage}; use layout_interface::{ContentBoxQuery, ContentBoxResponse}; use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery}; -use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg, ReapLayoutDataMsg}; +use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg}; use layout_interface::{Reflow, ReflowDocumentDamage, ReflowForDisplay, ReflowGoal, ReflowMsg}; use layout_interface::ContentChangedDocumentDamage; use layout_interface; @@ -46,12 +46,9 @@ use servo_net::image_cache_task::ImageCacheTask; use servo_net::resource_task::ResourceTask; use servo_util::geometry::to_frac_px; use servo_util::url::make_url; -use std::cell::Cell; use std::comm::{Port, SharedChan}; -use std::comm; use std::ptr; use std::str::eq_slice; -use std::task::{spawn_sched, SingleThreaded}; use std::util::replace; /// Messages used to control the script task. @@ -90,8 +87,9 @@ pub struct ScriptChan(SharedChan<ScriptMsg>); impl ScriptChan { /// Creates a new script chan. - pub fn new(chan: Chan<ScriptMsg>) -> ScriptChan { - ScriptChan(SharedChan::new(chan)) + pub fn new() -> (Port<ScriptMsg>, ScriptChan) { + let (port, chan) = SharedChan::new(); + (port, ScriptChan(chan)) } } @@ -140,8 +138,8 @@ pub struct PageTree { inner: ~[PageTree], } -pub struct PageTreeIterator<'self> { - priv stack: ~[&'self mut PageTree], +pub struct PageTreeIterator<'a> { + priv stack: ~[&'a mut PageTree], } impl PageTree { @@ -203,7 +201,7 @@ impl PageTree { } } -impl<'self> Iterator<@mut Page> for PageTreeIterator<'self> { +impl<'a> Iterator<@mut Page> for PageTreeIterator<'a> { fn next(&mut self) -> Option<@mut Page> { if !self.stack.is_empty() { let next = self.stack.pop(); @@ -254,12 +252,14 @@ impl Page { let join_port = replace(&mut self.layout_join_port, None); match join_port { Some(ref join_port) => { - if !join_port.peek() { - info!("script: waiting on layout"); + match join_port.try_recv() { + None => { + info!("script: waiting on layout"); + join_port.recv(); + } + Some(_) => {} } - join_port.recv(); - debug!("script: layout joined") } None => fail!(~"reader forked but no join port?"), @@ -307,7 +307,7 @@ impl Page { compositor.set_ready_state(PerformingLayout); // Layout will let us know when it's done. - let (join_port, join_chan) = comm::stream(); + let (join_port, join_chan) = Chan::new(); self.layout_join_port = Some(join_port); self.last_reflow_id += 1; @@ -359,11 +359,6 @@ impl Page { js_context: js_context, }); } - - /// Sends the given layout data back to the layout task to be destroyed. - pub unsafe fn reap_dead_layout_data(&self, layout_data: LayoutDataRef) { - self.layout_chan.send(ReapLayoutDataMsg(layout_data)) - } } /// Information for one frame in the browsing context. @@ -412,7 +407,6 @@ pub struct ScriptTask { } /// Returns the relevant page from the associated JS Context. -#[fixed_stack_segment] pub fn page_from_context(js_context: *JSContext) -> *mut Page { unsafe { JS_GetContextPrivate(js_context) as *mut Page @@ -468,24 +462,7 @@ impl ScriptTask { resource_task: ResourceTask, image_cache_task: ImageCacheTask, window_size: Size2D<uint>) { - let parms = Cell::new((compositor, - layout_chan, - port, - chan, - constellation_chan, - resource_task, - image_cache_task)); - // Since SpiderMonkey is blocking it needs to run in its own thread. - // If we don't do this then we'll just end up with a bunch of SpiderMonkeys - // starving all the other tasks. - do spawn_sched(SingleThreaded) { - let (compositor, - layout_chan, - port, - chan, - constellation_chan, - resource_task, - image_cache_task) = parms.take(); + spawn(proc() { let script_task = ScriptTask::new(id, @compositor as @ScriptListener, layout_chan, @@ -496,7 +473,7 @@ impl ScriptTask { image_cache_task, window_size); script_task.start(); - } + }); } /// Handle incoming control messages. @@ -520,12 +497,13 @@ impl ScriptTask { // Store new resizes, and gather all other events. let mut sequential = ~[]; + + // Receive at least one message so we don't spinloop. + let mut event = self.port.recv(); + loop { - // Receive at least one message so we don't spinloop. - let event = self.port.recv(); match event { ResizeMsg(id, size) => { - debug!("script got resize message"); let page = self.page_tree.find(id).expect("resize sent to nonexistent pipeline").page; page.resize_event = Some(size); } @@ -534,9 +512,9 @@ impl ScriptTask { } } - // Break if there are no more messages. - if !self.port.peek() { - break; + match self.port.try_recv() { + None => break, + Some(ev) => event = ev, } } @@ -556,7 +534,7 @@ impl ScriptTask { self.handle_exit_window_msg(id); return false }, - ResizeMsg(*) => fail!("should have handled ResizeMsg already"), + ResizeMsg(..) => fail!("should have handled ResizeMsg already"), } } @@ -579,14 +557,14 @@ impl ScriptTask { } /// Handles a timer that fired. - #[fixed_stack_segment] fn handle_fire_timer_msg(&mut self, id: PipelineId, timer_data: ~TimerData) { let page = self.page_tree.find(id).expect("ScriptTask: received fire timer msg for a pipeline ID not associated with this script task. This is a bug.").page; let window = page.frame.expect("ScriptTask: Expect a timeout to have a document").window; - if !window.active_timers.contains(&timer_data.handle) { + if !window.active_timers.contains(&TimerHandle { handle: timer_data.handle, cancel_chan: None }) { return; } + window.active_timers.remove(&TimerHandle { handle: timer_data.handle, cancel_chan: None }); unsafe { let this_value = if timer_data.args.len() > 0 { RUST_JSVAL_TO_OBJECT(timer_data.args[0]) @@ -711,7 +689,6 @@ impl ScriptTask { // // Note: We can parse the next document in parallel with any previous documents. let document = HTMLDocument::new(window); - let html_parsing_result = hubbub_html_parser::parse_html(cx.ptr, document, url.clone(), @@ -736,7 +713,7 @@ impl ScriptTask { let mut js_scripts = None; loop { - match discovery_port.try_recv() { + match discovery_port.recv_opt() { Some(HtmlDiscoveredScript(scripts)) => { assert!(js_scripts.is_none()); js_scripts = Some(scripts); @@ -805,20 +782,20 @@ impl ScriptTask { None => { let doc_node = AbstractNode::from_document(document); let mut anchors = doc_node.traverse_preorder().filter(|node| node.is_anchor_element()); - do anchors.find |node| { - do node.with_imm_element |elem| { + anchors.find(|node| { + node.with_imm_element(|elem| { match elem.get_attr(Null, "name") { Some(name) => eq_slice(name, fragid), None => false } - } - } + }) + }) } } } fn scroll_fragment_point(&self, pipeline_id: PipelineId, page: &mut Page, node: AbstractNode) { - let (port, chan) = comm::stream(); + let (port, chan) = Chan::new(); match page.query_layout(ContentBoxQuery(node, chan), port) { ContentBoxResponse(rect) => { let point = Point2D(to_frac_px(rect.origin.x).to_f32().unwrap(), @@ -870,7 +847,7 @@ impl ScriptTask { if root.is_none() { return; } - let (port, chan) = comm::stream(); + let (port, chan) = Chan::new(); match page.query_layout(HitTestQuery(root.unwrap(), point, chan), port) { Ok(node) => match node { HitTestResponse(node) => { @@ -886,11 +863,11 @@ impl ScriptTask { } } if node.is_element() { - do node.with_imm_element |element| { + node.with_imm_element(|element| { if "a" == element.tag_name { self.load_url_from_element(page, element) } - } + }) } } }, @@ -899,8 +876,8 @@ impl ScriptTask { } } } - MouseDownEvent(*) => {} - MouseUpEvent(*) => {} + MouseDownEvent(..) => {} + MouseUpEvent(..) => {} } } @@ -910,9 +887,9 @@ impl ScriptTask { for href in attr.iter() { debug!("ScriptTask: clicked on link to {:s}", *href); let click_frag = href.starts_with("#"); - let current_url = do page.url.as_ref().map |&(ref url, _)| { + let current_url = page.url.as_ref().map(|&(ref url, _)| { url.clone() - }; + }); debug!("ScriptTask: current url is {:?}", current_url); let url = make_url(href.to_owned(), current_url); @@ -933,29 +910,15 @@ fn shut_down_layout(page: @mut Page) { page.join_layout(); // Tell the layout task to begin shutting down. - let (response_port, response_chan) = comm::stream(); + let (response_port, response_chan) = Chan::new(); page.layout_chan.send(layout_interface::PrepareToExitMsg(response_chan)); response_port.recv(); - // Destroy all nodes. - // - // If there was a leak, the layout task will soon crash safely when it detects that local data - // is missing from its heap. - // - // FIXME(pcwalton): *But*, for now, because we use `@mut` boxes to hold onto Nodes, if this - // didn't destroy all the nodes there will be an *exploitable* security vulnerability as the - // nodes try to access the destroyed JS context. We need to change this so that the only actor - // who can judge a JS object dead (and thus run its drop glue) is the JS engine itself; thus it - // will be impossible (absent a serious flaw in the JS engine) for the JS context to be dead - // before nodes are. - unsafe { - let document_node = AbstractNode::from_document(page.frame.as_ref().unwrap().document); - for node in document_node.traverse_preorder() { - node.mut_node().reap_layout_data() - } - } + // Destroy all nodes. Setting frame and js_info to None will trigger our + // compartment to shutdown, run GC, etc. + page.frame = None; + page.js_info = None; // Destroy the layout task. If there were node leaks, layout will now crash safely. page.layout_chan.send(layout_interface::ExitNowMsg); } - |