diff options
author | bors-servo <release+servo@mozilla.com> | 2013-07-31 14:42:29 -0700 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2013-07-31 14:42:29 -0700 |
commit | feee4ddcb23a072e60bfe76cbaa738215e065ad6 (patch) | |
tree | 629208c8bce64ff9d1837d726a62c5a4cf609d13 /src | |
parent | 7911ae56954cc0ff03f77ff901233a411a30f1e7 (diff) | |
parent | 8eac64b0aec9dcec3e79e292487e7759ebe1d189 (diff) | |
download | servo-feee4ddcb23a072e60bfe76cbaa738215e065ad6.tar.gz servo-feee4ddcb23a072e60bfe76cbaa738215e065ad6.zip |
auto merge of #647 : tkuehn/servo/master, r=metajack
This will be necessary for the constellation to properly assign sizes to iframes when a parent layout performs reflow.
Diffstat (limited to 'src')
-rw-r--r-- | src/components/main/constellation.rs | 182 | ||||
-rw-r--r-- | src/components/main/pipeline.rs | 23 | ||||
-rw-r--r-- | src/components/msg/constellation_msg.rs | 4 | ||||
-rw-r--r-- | src/components/script/dom/element.rs | 3 | ||||
-rw-r--r-- | src/components/script/html/hubbub_html_parser.rs | 20 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 18 |
6 files changed, 144 insertions, 106 deletions
diff --git a/src/components/main/constellation.rs b/src/components/main/constellation.rs index b5783533da9..6c3d16e7420 100644 --- a/src/components/main/constellation.rs +++ b/src/components/main/constellation.rs @@ -43,12 +43,25 @@ pub struct Constellation { } /// Stores the Id of the outermost frame's pipeline, along with a vector of children frames -#[deriving(Clone)] struct FrameTree { pipeline: @mut Pipeline, parent: Option<@mut Pipeline>, children: ~[@mut FrameTree], } +// Need to clone the FrameTrees, but _not_ the Pipelines +impl Clone for FrameTree { + fn clone(&self) -> FrameTree { + let mut children = ~[]; + for self.children.iter().advance |&frame_tree| { + children.push(@mut (*frame_tree).clone()); + } + FrameTree { + pipeline: self.pipeline, + parent: self.parent.clone(), + children: children, + } + } +} pub struct SendableFrameTree { pipeline: Pipeline, @@ -75,7 +88,7 @@ impl FrameTree { /// Returns the frame tree whose key is id fn find_mut(@mut self, id: PipelineId) -> Option<@mut FrameTree> { if self.pipeline.id == id { return Some(self); } - for self.children.mut_iter().advance |frame_tree| { + for self.children.iter().advance |frame_tree| { let found = frame_tree.find_mut(id); if found.is_some() { return found; } } @@ -188,32 +201,28 @@ impl NavigationContext { evicted } - /// Returns the frame tree whose key is pipeline_id. - pub fn find(&mut self, pipeline_id: PipelineId) -> Option<@mut FrameTree> { - for self.current.mut_iter().advance |frame_tree| { - let found = frame_tree.find_mut(pipeline_id); - if found.is_some() { return found; } - } - let mut forward = self.next.mut_rev_iter(); - let mut backward = self.previous.mut_rev_iter(); - loop { - match (forward.next(), backward.next()) { - (None, None) => { - return None; - } - (next_forward, next_backward) => { - let mut next_forward = next_forward; - let mut next_backward = next_backward; - for next_forward.mut_iter().advance |frame_tree| { - let found = frame_tree.find_mut(pipeline_id); - if found.is_some() { return found; } - } - for next_backward.mut_iter().advance |frame_tree| { - let found = frame_tree.find_mut(pipeline_id); - if found.is_some() { return found; } - } - } - } + /// Returns the frame trees whose keys are pipeline_id. + pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] { + let from_current = do self.current.iter().filter_map |frame_tree| { + frame_tree.find_mut(pipeline_id) + }; + let from_next = do self.next.iter().filter_map |frame_tree| { + frame_tree.find_mut(pipeline_id) + }; + let from_prev = do self.previous.iter().filter_map |frame_tree| { + frame_tree.find_mut(pipeline_id) + }; + from_prev.chain_(from_current).chain_(from_next).collect() + } + + pub fn contains(&mut self, pipeline_id: PipelineId) -> bool { + let from_current = self.current.iter(); + let from_next = self.next.iter(); + let from_prev = self.previous.iter(); + + let mut all_contained = from_prev.chain_(from_current).chain_(from_next); + do all_contained.any |frame_tree| { + frame_tree.contains(pipeline_id) } } } @@ -269,7 +278,7 @@ impl Constellation { /// Helper function for getting a unique pipeline Id fn get_next_pipeline_id(&mut self) -> PipelineId { let id = self.next_pipeline_id; - self.next_pipeline_id = PipelineId(*id + 1); + *self.next_pipeline_id += 1; id } @@ -297,16 +306,17 @@ impl Constellation { // This should only be called once per constellation, and only by the browser InitLoadUrlMsg(url) => { let pipeline = @mut Pipeline::create(self.get_next_pipeline_id(), - self.chan.clone(), - self.compositor_chan.clone(), - self.image_cache_task.clone(), - self.resource_task.clone(), - self.profiler_chan.clone(), - copy self.opts, - { - let size = self.compositor_chan.get_size(); - from_value(Size2D(size.width as uint, size.height as uint)) - }); + None, + self.chan.clone(), + self.compositor_chan.clone(), + self.image_cache_task.clone(), + self.resource_task.clone(), + self.profiler_chan.clone(), + copy self.opts, + { + let size = self.compositor_chan.get_size(); + from_value(Size2D(size.width as uint, size.height as uint)) + }); if url.path.ends_with(".js") { pipeline.script_chan.send(ExecuteMsg(pipeline.id, url)); } else { @@ -324,35 +334,30 @@ impl Constellation { self.pipelines.insert(pipeline.id, pipeline); } - LoadIframeUrlMsg(url, source_pipeline_id, size_future) => { + LoadIframeUrlMsg(url, source_pipeline_id, subpage_id, size_future) => { // A message from the script associated with pipeline_id that it has // parsed an iframe during html parsing. This iframe will result in a // new pipeline being spawned and a frame tree being added to pipeline_id's // frame tree's children. This message is never the result of a link clicked // or a new url entered. - // Start by finding the frame tree matching the pipeline id, - // and add the new pipeline to its sub frames. The frame tree - // could already be in the navigation context, or it could still - // be loading, in which case it is a new id in a constellation.pending_frames - // frame change, because pages aren't added to the navi context until they finish - // loading (excluding iframes). Which is checked first is seemingly arbitrary - let next_pipeline_id = self.get_next_pipeline_id(); - let frame_tree = { - let frame_tree = self.navigation_context.find(source_pipeline_id); - match frame_tree { - Some(frame_tree) => frame_tree, - None => { - let frame_change = do self.pending_frames.mut_iter().find_ |frame_change| { - frame_change.after.pipeline.id == source_pipeline_id - }; - let frame_change = frame_change.expect("Constellation: source pipeline id - of LoadIframeUrlMsg is not in navigation context nor a pending painter. - This should be impossible."); - frame_change.after - } - } + // Start by finding the frame trees matching the pipeline id, + // and add the new pipeline to their sub frames. + let frame_trees: ~[@mut FrameTree] = { + let matching_navi_frames = self.navigation_context.find_all(source_pipeline_id); + let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| { + frame_change.after.find_mut(source_pipeline_id) + }; + matching_navi_frames.iter().transform(|&x| x).chain_(matching_pending_frames).collect() }; + if frame_trees.is_empty() { + fail!("Constellation: source pipeline id of LoadIframeUrlMsg is not in + navigation context, nor is it in a pending frame. This should be + impossible."); + } + + let next_pipeline_id = self.get_next_pipeline_id(); + // Compare the pipeline's url to the new url. If the origin is the same, // then reuse the script task in creating the new pipeline let source_pipeline = *self.pipelines.find(&source_pipeline_id).expect("Constellation: @@ -368,6 +373,7 @@ impl Constellation { source_url.port == url.port) { // Reuse the script task if same-origin url's Pipeline::with_script(next_pipeline_id, + Some(subpage_id), self.chan.clone(), self.compositor_chan.clone(), self.image_cache_task.clone(), @@ -378,6 +384,7 @@ impl Constellation { } else { // Create a new script task if not same-origin url's Pipeline::create(next_pipeline_id, + Some(subpage_id), self.chan.clone(), self.compositor_chan.clone(), self.image_cache_task.clone(), @@ -392,11 +399,13 @@ impl Constellation { } else { pipeline.load(url, None); } - frame_tree.children.push(@mut FrameTree { - pipeline: pipeline, - parent: Some(source_pipeline), - children: ~[], - }); + for frame_trees.iter().advance |frame_tree| { + frame_tree.children.push(@mut FrameTree { + pipeline: pipeline, + parent: Some(source_pipeline), + children: ~[], + }); + } self.pipelines.insert(pipeline.id, pipeline); } @@ -406,6 +415,11 @@ impl Constellation { LoadUrlMsg(source_id, url, size_future) => { debug!("received message to load %s", url::to_str(&url)); // Make sure no pending page would be overridden. + let source_frame = self.current_frame().get_ref().find_mut(source_id).expect( + "Constellation: received a LoadUrlMsg from a pipeline_id associated + with a pipeline not in the active frame tree. This should be + impossible."); + for self.pending_frames.iter().advance |frame_change| { let old_id = frame_change.before.expect("Constellation: Received load msg from pipeline, but there is no currently active page. This should @@ -413,7 +427,7 @@ impl Constellation { let changing_frame = self.current_frame().get_ref().find_mut(old_id).expect("Constellation: Pending change has non-active source pipeline. This should be impossible."); - if changing_frame.contains(source_id) { + if changing_frame.contains(source_id) || source_frame.contains(old_id) { // id that sent load msg is being changed already; abort return true; } @@ -421,33 +435,25 @@ impl Constellation { // Being here means either there are no pending frames, or none of the pending // changes would be overriden by changing the subframe associated with source_id. + let parent = source_frame.parent.clone(); + let subpage_id = source_frame.pipeline.subpage_id.clone(); let next_pipeline_id = self.get_next_pipeline_id(); + let pipeline = @mut Pipeline::create(next_pipeline_id, - self.chan.clone(), - self.compositor_chan.clone(), - self.image_cache_task.clone(), - self.resource_task.clone(), - self.profiler_chan.clone(), - copy self.opts, - size_future); + subpage_id, + self.chan.clone(), + self.compositor_chan.clone(), + self.image_cache_task.clone(), + self.resource_task.clone(), + self.profiler_chan.clone(), + copy self.opts, + size_future); if url.path.ends_with(".js") { pipeline.script_chan.send(ExecuteMsg(pipeline.id, url)); } else { pipeline.load(url, Some(constellation_msg::Load)); - let parent = if self.current_frame().get_ref().pipeline.id == source_id { - // source_id is the root of the current frame tree; replace whole tree - None - } else { - // id is not the root of the current frame tree, but is in the frame tree; - // replace only the subtree - let source_frame = self.current_frame().get_ref().find_mut(source_id).expect( - "Constellation: received a LoadUrlMsg from a pipeline_id associated - with a pipeline not in the active frame tree. This should be - impossible."); - source_frame.parent - }; self.pending_frames.push(FrameChange{ before: Some(source_id), after: @mut FrameTree { @@ -532,7 +538,7 @@ impl Constellation { // Create the next frame tree that will be given to the compositor let next_frame_tree = match to_add.parent { None => to_add, // to_add is the root - Some(_parent) => self.current_frame().get(), + Some(_parent) => @mut (*self.current_frame().get()).clone(), }; // If there are frames to revoke permission from, do so now. @@ -613,7 +619,7 @@ impl Constellation { for evicted.iter().advance |frame_tree| { // exit any pipelines that don't exist outside the evicted frame trees for frame_tree.iter().advance |frame| { - if self.navigation_context.find(frame.pipeline.id).is_none() { + if !self.navigation_context.contains(frame.pipeline.id) { frame_tree.pipeline.exit(); self.pipelines.remove(&frame_tree.pipeline.id); } diff --git a/src/components/main/pipeline.rs b/src/components/main/pipeline.rs index ec17e01ef21..1ea7965b02a 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, NavigationType, PipelineId}; +use servo_msg::constellation_msg::{ConstellationChan, NavigationType, PipelineId, SubpageId}; use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan}; use script::script_task; use servo_net::image_cache_task::ImageCacheTask; @@ -25,6 +25,7 @@ use std::comm; #[deriving(Clone)] pub struct Pipeline { id: PipelineId, + subpage_id: Option<SubpageId>, script_chan: ScriptChan, layout_chan: LayoutChan, render_chan: RenderChan, @@ -36,13 +37,14 @@ pub struct Pipeline { impl Pipeline { /// Starts a render task, layout task, and script task. Returns the channels wrapped in a struct. pub fn with_script(id: PipelineId, - constellation_chan: ConstellationChan, - compositor_chan: CompositorChan, - image_cache_task: ImageCacheTask, - profiler_chan: ProfilerChan, - opts: Opts, - script_pipeline: &Pipeline, - size_future: Future<Size2D<uint>>) -> Pipeline { + subpage_id: Option<SubpageId>, + constellation_chan: ConstellationChan, + compositor_chan: CompositorChan, + image_cache_task: ImageCacheTask, + profiler_chan: ProfilerChan, + opts: Opts, + script_pipeline: &Pipeline, + size_future: Future<Size2D<uint>>) -> Pipeline { let (layout_port, layout_chan) = special_stream!(LayoutChan); let (render_port, render_chan) = special_stream!(RenderChan); @@ -72,6 +74,7 @@ impl Pipeline { script_pipeline.script_chan.send(AttachLayoutMsg(new_layout_info)); Pipeline::new(id, + subpage_id, script_pipeline.script_chan.clone(), layout_chan, render_chan) @@ -79,6 +82,7 @@ impl Pipeline { } pub fn create(id: PipelineId, + subpage_id: Option<SubpageId>, constellation_chan: ConstellationChan, compositor_chan: CompositorChan, image_cache_task: ImageCacheTask, @@ -117,18 +121,21 @@ impl Pipeline { copy opts, profiler_chan); Pipeline::new(id, + subpage_id, script_chan, layout_chan, render_chan) } pub fn new(id: PipelineId, + subpage_id: Option<SubpageId>, script_chan: ScriptChan, layout_chan: LayoutChan, render_chan: RenderChan) -> Pipeline { Pipeline { id: id, + subpage_id: subpage_id, script_chan: script_chan, layout_chan: layout_chan, render_chan: render_chan, diff --git a/src/components/msg/constellation_msg.rs b/src/components/msg/constellation_msg.rs index 6f71f8a0454..419aadf1ae3 100644 --- a/src/components/msg/constellation_msg.rs +++ b/src/components/msg/constellation_msg.rs @@ -30,7 +30,7 @@ pub enum Msg { ExitMsg(Chan<()>), InitLoadUrlMsg(Url), LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>), - LoadIframeUrlMsg(Url, PipelineId, Future<Size2D<uint>>), + LoadIframeUrlMsg(Url, PipelineId, SubpageId, Future<Size2D<uint>>), NavigateMsg(NavigationDirection), RendererReadyMsg(PipelineId), ResizedWindowBroadcast(Size2D<uint>), @@ -51,3 +51,5 @@ pub enum NavigationDirection { #[deriving(Clone, Eq, IterBytes)] pub struct PipelineId(uint); +#[deriving(Clone, Eq, IterBytes)] +pub struct SubpageId(uint); diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index 7f42230b61b..ac60914db1c 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -18,6 +18,8 @@ use std::str::eq_slice; use extra::net::url::Url; use geom::size::Size2D; +use servo_msg::constellation_msg::SubpageId; + pub struct Element { parent: Node<ScriptView>, tag_name: ~str, // TODO: This should be an atom, not a ~str. @@ -112,6 +114,7 @@ pub struct HTMLHeadingElement { pub struct HTMLIframeElement { parent: Element, frame: Option<Url>, + subpage_id: Option<SubpageId>, size_future_chan: Option<ChanOne<Size2D<uint>>>, } diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index d3b94d2fe3f..8bb6afd22b2 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -42,6 +42,7 @@ use std::str::eq_slice; use std::result; use std::task; use hubbub::hubbub; +use servo_msg::constellation_msg::SubpageId; use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task; use servo_net::resource_task::{Done, Load, Payload, ResourceTask}; @@ -83,7 +84,7 @@ enum JSMessage { pub struct HtmlParserResult { root: AbstractNode<ScriptView>, style_port: Port<Stylesheet>, - iframe_port: Port<(Url, Future<Size2D<uint>>)>, + iframe_port: Port<(Url, SubpageId, Future<Size2D<uint>>)>, js_port: Port<JSResult>, } @@ -222,7 +223,7 @@ fn build_element_from_tag(cx: *JSContext, tag: &str) -> AbstractNode<ScriptView> handle_element!(cx, tag, "ul", HTMLUListElementTypeId, HTMLUListElement, []); handle_element!(cx, tag, "img", HTMLImageElementTypeId, HTMLImageElement, [(image: None)]); - handle_element!(cx, tag, "iframe", HTMLIframeElementTypeId, HTMLIframeElement, [(frame: None), (size_future_chan: None)]); + handle_element!(cx, tag, "iframe", HTMLIframeElementTypeId, HTMLIframeElement, [(frame: None), (size_future_chan: None), (subpage_id: None)]); handle_element!(cx, tag, "h1", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading1)]); handle_element!(cx, tag, "h2", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading2)]); @@ -240,7 +241,8 @@ fn build_element_from_tag(cx: *JSContext, tag: &str) -> AbstractNode<ScriptView> pub fn parse_html(cx: *JSContext, url: Url, resource_task: ResourceTask, - image_cache_task: ImageCacheTask) -> HtmlParserResult { + image_cache_task: ImageCacheTask, + next_subpage_id: SubpageId) -> HtmlParserResult { debug!("Hubbub: parsing %?", url); // Spawn a CSS parser to receive links to CSS style sheets. let resource_task2 = resource_task.clone(); @@ -281,6 +283,8 @@ pub fn parse_html(cx: *JSContext, let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone()); let (iframe_port, iframe_chan) = comm::stream(); + let next_subpage_id = Cell::new(next_subpage_id); + parser.set_tree_handler(~hubbub::TreeHandler { create_comment: |data: ~str| { debug!("create comment"); @@ -337,10 +341,18 @@ pub fn parse_html(cx: *JSContext, for src_opt.iter().advance |src| { let iframe_url = make_url(src.clone(), Some(url2.clone())); iframe_element.frame = Some(iframe_url.clone()); + + // Size future let (port, chan) = comm::oneshot(); iframe_element.size_future_chan = Some(chan); let size_future = from_port(port); - iframe_chan.send((iframe_url, size_future)); + + // Subpage Id + let subpage_id = next_subpage_id.take(); + iframe_element.subpage_id = Some(subpage_id); + next_subpage_id.put_back(SubpageId(*subpage_id + 1)); + + iframe_chan.send((iframe_url, subpage_id, size_future)); } } } diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index d5ba18b4402..f769e4b282a 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -21,7 +21,7 @@ use layout_interface::{ReflowDocumentDamage, ReflowForDisplay, ReflowGoal}; use layout_interface::ReflowMsg; use layout_interface; use servo_msg::constellation_msg::{ConstellationChan, LoadUrlMsg, NavigationDirection}; -use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowBroadcast}; +use servo_msg::constellation_msg::{PipelineId, SubpageId, RendererReadyMsg, ResizedWindowBroadcast}; use servo_msg::constellation_msg::{LoadIframeUrlMsg}; use servo_msg::constellation_msg; @@ -128,6 +128,8 @@ pub struct Page { /// and simply caches pages forever (!). The bool indicates if reflow is required /// when reloading. url: Option<(Url, bool)>, + + next_subpage_id: SubpageId, } pub struct PageTree { @@ -151,6 +153,7 @@ impl PageTree { window_size: size_future, js_info: None, url: None, + next_subpage_id: SubpageId(0), }, inner: ~[], } @@ -599,7 +602,8 @@ impl ScriptTask { let html_parsing_result = hubbub_html_parser::parse_html(page.js_info.get_ref().js_compartment.cx.ptr, url.clone(), self.resource_task.clone(), - self.image_cache_task.clone()); + self.image_cache_task.clone(), + page.next_subpage_id.clone()); let HtmlParserResult {root, js_port, style_port, iframe_port} = html_parsing_result; @@ -624,12 +628,14 @@ impl ScriptTask { // FIXME: These should be streamed to layout as they're parsed. We don't need to stop here // in the script task. - let get_iframes = |iframe_port: &Port<(Url, Future<Size2D<uint>>)>| loop { + let get_iframes = |iframe_port: &Port<(Url, SubpageId, Future<Size2D<uint>>)>| loop { match iframe_port.try_recv() { None => break, - Some((iframe_url, size_future)) => { + Some((iframe_url, subpage_id, size_future)) => { + page.next_subpage_id = SubpageId(*subpage_id + 1); self.constellation_chan.send(LoadIframeUrlMsg(iframe_url, pipeline_id, + subpage_id, size_future)); } } @@ -652,9 +658,11 @@ impl ScriptTask { Left(Some(sheet)) => { page.layout_chan.send(AddStylesheetMsg(sheet)); } - Right(Some((iframe_url, size_future))) => { + Right(Some((iframe_url, subpage_id, size_future))) => { + page.next_subpage_id = SubpageId(*subpage_id + 1); self.constellation_chan.send(LoadIframeUrlMsg(iframe_url, pipeline_id, + subpage_id, size_future)); } Right(None) => { |