diff --git a/Makefile.in b/Makefile.in index 3b89b0a8ac8..906c084bc07 100644 --- a/Makefile.in +++ b/Makefile.in @@ -32,7 +32,7 @@ MKFILE_DEPS := config.stamp $(call rwildcard,$(S)mk/,*) # Enable debug!() etc even without configure --enable-debug # The evaluation of these prints & their arguments is controlled # at runtime by the environment variable RUST_LOG. -CFG_RUSTC_FLAGS += --cfg debug +CFG_RUSTC_FLAGS += --cfg debug -Z debug-info ifdef CFG_DISABLE_OPTIMIZE $(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE)) diff --git a/src/components/main/compositing/compositor_layer.rs b/src/components/main/compositing/compositor_layer.rs index e1a5324ef3e..f11dd54156b 100644 --- a/src/components/main/compositing/compositor_layer.rs +++ b/src/components/main/compositing/compositor_layer.rs @@ -486,7 +486,12 @@ impl CompositorLayer { } else { // ID does not match ours, so recurse on descendents (including hidden children). self.children.mut_iter().map(|x| &mut x.child) - .any(|x| x.add_buffers(pipeline_id, cell.take(), epoch)) + .any(|x| { + let buffers = cell.take(); + let result = x.add_buffers(pipeline_id, buffers.clone(), epoch); + cell.put_back(buffers); + result + }) } } diff --git a/src/components/main/constellation.rs b/src/components/main/constellation.rs index 271b72526bb..70b4ee5cf79 100644 --- a/src/components/main/constellation.rs +++ b/src/components/main/constellation.rs @@ -13,8 +13,8 @@ use geom::size::Size2D; use geom::rect::Rect; use gfx::opts::Opts; use pipeline::Pipeline; -use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FrameRectMsg, IFrameSandboxState}; -use servo_msg::constellation_msg::{InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg}; +use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, FrameRectMsg}; +use servo_msg::constellation_msg::{IFrameSandboxState, InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg}; use servo_msg::constellation_msg::{Msg, NavigateMsg, NavigationType, IFrameUnsandboxed}; use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId}; use servo_msg::constellation_msg; @@ -23,6 +23,7 @@ use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; use servo_net::resource_task::ResourceTask; use servo_net::resource_task; use servo_util::time::ProfilerChan; +use servo_util::url::make_url; use std::hashmap::{HashMap, HashSet}; use std::util::replace; use extra::url::Url; @@ -312,6 +313,15 @@ impl Constellation { &self.navigation_context.current } + /// Returns both the navigation context and pending frame trees whose keys are pipeline_id. + pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] { + let matching_navi_frames = self.navigation_context.find_all(pipeline_id); + let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| { + frame_change.after.find_mut(pipeline_id) + }; + matching_navi_frames.move_iter().chain(matching_pending_frames).collect() + } + /// Handles loading pages, navigation, and granting access to the compositor fn handle_request(&mut self, request: Msg) -> bool { match request { @@ -319,6 +329,9 @@ impl Constellation { self.handle_exit(sender); return false; } + FailureMsg(pipeline_id, subpage_id) => { + self.handle_failure_msg(pipeline_id, subpage_id); + } // This should only be called once per constellation, and only by the browser InitLoadUrlMsg(url) => { self.handle_init_load(url); @@ -363,6 +376,32 @@ impl Constellation { sender.send(()); } + fn handle_failure_msg(&mut self, pipeline_id: PipelineId, subpage_id: Option) { + let new_id = self.get_next_pipeline_id(); + let pipeline = @mut Pipeline::create(new_id, + subpage_id, + self.chan.clone(), + self.compositor_chan.clone(), + self.image_cache_task.clone(), + self.resource_task.clone(), + self.profiler_chan.clone(), + self.opts.clone(), + { + let size = self.compositor_chan.get_size(); + from_value(Size2D(size.width as uint, size.height as uint)) + }); + let failure = ~"about:failure"; + let url = make_url(failure, None); + pipeline.load(url); + + let frames = self.find_all(pipeline_id); + for frame_tree in frames.iter() { + frame_tree.pipeline = pipeline; + }; + + self.pipelines.insert(pipeline_id, pipeline); + } + fn handle_init_load(&mut self, url: Url) { let pipeline = @mut Pipeline::create(self.get_next_pipeline_id(), None, @@ -420,14 +459,8 @@ impl Constellation { } } // Traverse the navigation context and pending frames and tell each associated pipeline to resize. - let frame_trees: ~[@mut FrameTree] = { - let matching_navi_frames = self.navigation_context.find_all(pipeline_id); - let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| { - frame_change.after.find_mut(pipeline_id) - }; - matching_navi_frames.move_iter().chain(matching_pending_frames).collect() - }; - for frame_tree in frame_trees.iter() { + let frames = self.find_all(pipeline_id); + for frame_tree in frames.iter() { for child_frame_tree in frame_tree.children.mut_iter() { let pipeline = &child_frame_tree.frame_tree.pipeline; if pipeline.subpage_id.expect("Constellation: child frame does not have a diff --git a/src/components/main/pipeline.rs b/src/components/main/pipeline.rs index 0204748c20b..37e8b1eb41e 100644 --- a/src/components/main/pipeline.rs +++ b/src/components/main/pipeline.rs @@ -11,7 +11,7 @@ use gfx::opts::Opts; use layout::layout_task::LayoutTask; use script::layout_interface::LayoutChan; use script::script_task::{ExecuteMsg, LoadMsg}; -use servo_msg::constellation_msg::{ConstellationChan, PipelineId, SubpageId}; +use servo_msg::constellation_msg::{ConstellationChan, FailureMsg, PipelineId, SubpageId}; use script::dom::node::AbstractNode; use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan}; use script::script_task; @@ -20,9 +20,11 @@ use servo_net::resource_task::ResourceTask; use servo_util::time::ProfilerChan; use geom::size::Size2D; use extra::future::Future; +use std::cell::Cell; use std::comm; +use std::task; -/// A uniquely-identifiable pipeline of stript task, layout task, and render task. +/// A uniquely-identifiable pipeline of script task, layout task, and render task. #[deriving(Clone)] pub struct Pipeline { id: PipelineId, @@ -94,37 +96,81 @@ impl Pipeline { let (script_port, script_chan) = special_stream!(ScriptChan); let (layout_port, layout_chan) = special_stream!(LayoutChan); let (render_port, render_chan) = special_stream!(RenderChan); + let pipeline = Pipeline::new(id, + subpage_id, + script_chan.clone(), + layout_chan.clone(), + render_chan.clone()); + let (port, chan) = stream::(); + + let script_port = Cell::new(script_port); + let resource_task = Cell::new(resource_task); + let size = Cell::new(size); + let render_port = Cell::new(render_port); + let layout_port = Cell::new(layout_port); + let constellation_chan_handler = Cell::new(constellation_chan.clone()); + let constellation_chan = Cell::new(constellation_chan); + let image_cache_task = Cell::new(image_cache_task); + let profiler_chan = Cell::new(profiler_chan); - ScriptTask::create(id, - compositor_chan.clone(), - layout_chan.clone(), - script_port, - script_chan.clone(), - constellation_chan.clone(), - resource_task, - image_cache_task.clone(), - size); + do Pipeline::spawn(chan) { + let script_port = script_port.take(); + let resource_task = resource_task.take(); + let size = size.take(); + let render_port = render_port.take(); + let layout_port = layout_port.take(); + let constellation_chan = constellation_chan.take(); + let image_cache_task = image_cache_task.take(); + let profiler_chan = profiler_chan.take(); + ScriptTask::create(id, + compositor_chan.clone(), + layout_chan.clone(), + script_port, + script_chan.clone(), + constellation_chan.clone(), + resource_task, + image_cache_task.clone(), + size); - RenderTask::create(id, - render_port, - compositor_chan.clone(), - opts.clone(), - profiler_chan.clone()); + RenderTask::create(id, + render_port, + compositor_chan.clone(), + opts.clone(), + profiler_chan.clone()); - LayoutTask::create(id, - layout_port, - constellation_chan, - script_chan.clone(), - render_chan.clone(), - image_cache_task, - opts.clone(), - profiler_chan); - Pipeline::new(id, - subpage_id, - script_chan, - layout_chan, - render_chan) + LayoutTask::create(id, + layout_port, + constellation_chan, + script_chan.clone(), + render_chan.clone(), + image_cache_task, + opts.clone(), + profiler_chan); + }; + + do spawn { + match port.recv() { + task::Success => (), + task::Failure => { + let constellation_chan = constellation_chan_handler.take(); + constellation_chan.send(FailureMsg(id, subpage_id)); + } + } + }; + + pipeline + } + + /// This function wraps the task creation within a supervised task + /// so that failure will only tear down those tasks instead of ours. + pub fn spawn(chan: Chan, f: ~fn()) { + let mut task = task::task(); + task.opts.notify_chan = Some(chan); + task.supervised(); + do task.spawn { + f(); + }; } pub fn new(id: PipelineId, diff --git a/src/components/msg/constellation_msg.rs b/src/components/msg/constellation_msg.rs index c5b4dbb48d0..7724d53c429 100644 --- a/src/components/msg/constellation_msg.rs +++ b/src/components/msg/constellation_msg.rs @@ -35,6 +35,7 @@ pub enum IFrameSandboxState { pub enum Msg { ExitMsg(Chan<()>), + FailureMsg(PipelineId, Option), InitLoadUrlMsg(Url), FrameRectMsg(PipelineId, SubpageId, Rect), LoadUrlMsg(PipelineId, Url, Future>), diff --git a/src/components/util/url.rs b/src/components/util/url.rs index bdfef004335..8ad5f343a7e 100644 --- a/src/components/util/url.rs +++ b/src/components/util/url.rs @@ -16,42 +16,55 @@ Create a URL object from a string. Does various helpful browsery things like is based off the current url */ +// TODO: about:failure-> pub fn make_url(str_url: ~str, current_url: Option) -> Url { let schm = url::get_scheme(str_url); - let str_url = if schm.is_err() { - if current_url.is_none() { - // Assume we've been given a file path. If it's absolute just return - // it, otherwise make it absolute with the cwd. - if str_url.starts_with("/") { - ~"file://" + str_url - } else { - ~"file://" + os::getcwd().push(str_url).to_str() - } - } else { - let current_url = current_url.unwrap(); - debug!("make_url: current_url: %?", current_url); - if str_url.starts_with("//") { - current_url.scheme + ":" + str_url - } else if current_url.path.is_empty() || - str_url.starts_with("/") { - current_url.scheme + "://" + - current_url.host + "/" + - str_url.trim_left_chars(&'/') - } else { - let mut path = ~[]; - for p in current_url.path.split_iter('/') { - path.push(p.to_str()); + let str_url = match schm { + Err(_) => { + if current_url.is_none() { + // Assume we've been given a file path. If it's absolute just return + // it, otherwise make it absolute with the cwd. + if str_url.starts_with("/") { + ~"file://" + str_url + } else { + ~"file://" + os::getcwd().push(str_url).to_str() } - let path = path.init(); - let mut path = path.iter().map(|x| (*x).clone()).collect::<~[~str]>(); - path.push(str_url); - let path = path.connect("/"); - - current_url.scheme + "://" + current_url.host + path + } else { + let current_url = current_url.unwrap(); + debug!("make_url: current_url: %?", current_url); + if str_url.starts_with("//") { + current_url.scheme + ":" + str_url + } else if current_url.path.is_empty() || + str_url.starts_with("/") { + current_url.scheme + "://" + + current_url.host + "/" + + str_url.trim_left_chars(&'/') + } else { + let mut path = ~[]; + for p in current_url.path.split_iter('/') { + path.push(p.to_str()); + } + let path = path.init(); + let mut path = path.iter().map(|x| (*x).clone()).collect::<~[~str]>(); + path.push(str_url); + let path = path.connect("/"); + + current_url.scheme + "://" + current_url.host + path + } + } + }, + Ok((scheme, page)) => { + match scheme { + ~"about" => { + match page { + ~"failure" => ~"file://" + os::getcwd().push("../src/test/html/failure.html").to_str(), + // TODO: handle the rest of the about: pages + _ => str_url + } + }, + _ => str_url } } - } else { - str_url }; // FIXME: Need to handle errors diff --git a/src/test/html/andreas.jpeg b/src/test/html/andreas.jpeg new file mode 100644 index 00000000000..7aa813783bf Binary files /dev/null and b/src/test/html/andreas.jpeg differ diff --git a/src/test/html/failure.html b/src/test/html/failure.html new file mode 100644 index 00000000000..9f68ac9f0ff --- /dev/null +++ b/src/test/html/failure.html @@ -0,0 +1,8 @@ + + + about:failure + + + + + diff --git a/src/test/html/summit-crash.html b/src/test/html/summit-crash.html new file mode 100644 index 00000000000..7086941d0d5 --- /dev/null +++ b/src/test/html/summit-crash.html @@ -0,0 +1,12 @@ + + + Summit demo crash page + + + +
pre
+ + diff --git a/src/test/html/summit-link.html b/src/test/html/summit-link.html new file mode 100644 index 00000000000..77d1e704960 --- /dev/null +++ b/src/test/html/summit-link.html @@ -0,0 +1,9 @@ + + + Summit page linking to the crash page + + + + Load a crashing page + + diff --git a/src/test/html/summit.html b/src/test/html/summit.html new file mode 100644 index 00000000000..a74b40e593f --- /dev/null +++ b/src/test/html/summit.html @@ -0,0 +1,12 @@ + + + Summit demo page + + + + + + +