IFrame elements now manage FrameIds rather than the constellation.

This commit is contained in:
Alan Jeffrey 2016-09-28 19:45:39 -05:00
parent 86f31d0dc7
commit f53408df80
7 changed files with 169 additions and 177 deletions

View file

@ -139,14 +139,11 @@ pub struct Constellation<Message, LTF, STF> {
font_cache_thread: FontCacheThread, font_cache_thread: FontCacheThread,
/// ID of the root frame. /// ID of the root frame.
root_frame_id: Option<FrameId>, root_frame_id: FrameId,
/// The next free ID to assign to a pipeline ID namespace. /// The next free ID to assign to a pipeline ID namespace.
next_pipeline_namespace_id: PipelineNamespaceId, next_pipeline_namespace_id: PipelineNamespaceId,
/// The next free ID to assign to a frame.
next_frame_id: FrameId,
/// Pipeline ID that has currently focused element for key events. /// Pipeline ID that has currently focused element for key events.
focus_pipeline_id: Option<PipelineId>, focus_pipeline_id: Option<PipelineId>,
@ -268,6 +265,7 @@ impl Frame {
/// Represents a pending change in the frame tree, that will be applied /// Represents a pending change in the frame tree, that will be applied
/// once the new pipeline has loaded and completed initial layout / paint. /// once the new pipeline has loaded and completed initial layout / paint.
struct FrameChange { struct FrameChange {
frame_id: FrameId,
old_pipeline_id: Option<PipelineId>, old_pipeline_id: Option<PipelineId>,
new_pipeline_id: PipelineId, new_pipeline_id: PipelineId,
document_ready: bool, document_ready: bool,
@ -476,6 +474,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let swmanager_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(swmanager_receiver); let swmanager_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(swmanager_receiver);
PipelineNamespace::install(PipelineNamespaceId(0));
let mut constellation: Constellation<Message, LTF, STF> = Constellation { let mut constellation: Constellation<Message, LTF, STF> = Constellation {
script_sender: ipc_script_sender, script_sender: ipc_script_sender,
layout_sender: ipc_layout_sender, layout_sender: ipc_layout_sender,
@ -495,9 +495,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
pipelines: HashMap::new(), pipelines: HashMap::new(),
frames: HashMap::new(), frames: HashMap::new(),
pending_frames: vec!(), pending_frames: vec!(),
next_pipeline_namespace_id: PipelineNamespaceId(0), // We initialize the namespace at 1, since we reserved namespace 0 for the constellation
root_frame_id: None, next_pipeline_namespace_id: PipelineNamespaceId(1),
next_frame_id: FrameId(0), root_frame_id: FrameId::new(),
focus_pipeline_id: None, focus_pipeline_id: None,
time_profiler_chan: state.time_profiler_chan, time_profiler_chan: state.time_profiler_chan,
mem_profiler_chan: state.mem_profiler_chan, mem_profiler_chan: state.mem_profiler_chan,
@ -525,8 +525,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
(rng, prob) (rng, prob)
}), }),
}; };
let namespace_id = constellation.next_pipeline_namespace_id();
PipelineNamespace::install(namespace_id);
constellation.run(); constellation.run();
}); });
(compositor_sender, swmanager_sender) (compositor_sender, swmanager_sender)
@ -614,9 +613,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Get an iterator for the current frame tree. Specify self.root_frame_id to // Get an iterator for the current frame tree. Specify self.root_frame_id to
// iterate the entire tree, or a specific frame id to iterate only that sub-tree. // iterate the entire tree, or a specific frame id to iterate only that sub-tree.
fn current_frame_tree_iter(&self, frame_id_root: Option<FrameId>) -> FrameTreeIterator { fn current_frame_tree_iter(&self, frame_id_root: FrameId) -> FrameTreeIterator {
FrameTreeIterator { FrameTreeIterator {
stack: frame_id_root.into_iter().collect(), stack: vec!(frame_id_root),
pipelines: &self.pipelines, pipelines: &self.pipelines,
frames: &self.frames, frames: &self.frames,
} }
@ -656,20 +655,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
// Create a new frame and update the internal bookkeeping. // Create a new frame and update the internal bookkeeping.
fn new_frame(&mut self, pipeline_id: PipelineId) -> FrameId { fn new_frame(&mut self, frame_id: FrameId, pipeline_id: PipelineId) {
let id = self.next_frame_id; let frame = Frame::new(frame_id, pipeline_id);
let FrameId(ref mut i) = self.next_frame_id;
*i += 1;
let frame = Frame::new(id, pipeline_id);
assert!(self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame).is_none()); assert!(self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame).is_none());
assert!(!self.frames.contains_key(&id)); assert!(!self.frames.contains_key(&frame_id));
self.pipelines.get_mut(&pipeline_id).map(|pipeline| pipeline.frame = Some(id)); self.pipelines.get_mut(&pipeline_id).map(|pipeline| pipeline.frame = Some(frame_id));
self.frames.insert(id, frame); self.frames.insert(frame_id, frame);
id
} }
/// Handles loading pages, navigation, and granting access to the compositor /// Handles loading pages, navigation, and granting access to the compositor
@ -1032,10 +1025,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
if self.shutting_down { return; } if self.shutting_down { return; }
self.shutting_down = true; self.shutting_down = true;
// TODO: exit before the root frame is set? // TODO: exit before the root frame is initialized?
if let Some(root_id) = self.root_frame_id { let root_frame_id = self.root_frame_id;
self.close_frame(root_id, ExitPipelineMode::Normal); self.close_frame(root_frame_id, ExitPipelineMode::Normal);
}
} }
fn handle_shutdown(&mut self) { fn handle_shutdown(&mut self) {
@ -1121,6 +1113,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let pipeline_url = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.url.clone()); let pipeline_url = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.url.clone());
let parent_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info); let parent_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info);
let window_size = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.size); let window_size = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.size);
let frame_id = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame);
self.close_pipeline(pipeline_id, ExitPipelineMode::Force); self.close_pipeline(pipeline_id, ExitPipelineMode::Force);
self.pipelines.remove(&pipeline_id); self.pipelines.remove(&pipeline_id);
@ -1142,16 +1135,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
warn!("creating replacement pipeline for about:failure"); warn!("creating replacement pipeline for about:failure");
let new_pipeline_id = PipelineId::new(); if let Some(frame_id) = frame_id {
let load_data = LoadData::new(failure_url, None, None); let new_pipeline_id = PipelineId::new();
self.new_pipeline(new_pipeline_id, parent_info, Some(pipeline_id), window_size, None, load_data, false); let load_data = LoadData::new(failure_url, None, None);
self.new_pipeline(new_pipeline_id, parent_info, Some(pipeline_id), window_size, None, load_data, false);
self.pending_frames.push(FrameChange { self.pending_frames.push(FrameChange {
old_pipeline_id: Some(pipeline_id), frame_id: frame_id,
new_pipeline_id: new_pipeline_id, old_pipeline_id: Some(pipeline_id),
document_ready: false, new_pipeline_id: new_pipeline_id,
replace: false, document_ready: false,
}); replace: false,
});
}
} }
} }
@ -1172,11 +1168,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_init_load(&mut self, url: Url) { fn handle_init_load(&mut self, url: Url) {
let window_size = self.window_size.visible_viewport; let window_size = self.window_size.visible_viewport;
let root_pipeline_id = PipelineId::new(); let root_pipeline_id = PipelineId::new();
debug_assert!(PipelineId::fake_root_pipeline_id() == root_pipeline_id);
self.new_pipeline(root_pipeline_id, None, None, Some(window_size), None, self.new_pipeline(root_pipeline_id, None, None, Some(window_size), None,
LoadData::new(url.clone(), None, None), false); LoadData::new(url.clone(), None, None), false);
self.handle_load_start_msg(root_pipeline_id); self.handle_load_start_msg(root_pipeline_id);
self.pending_frames.push(FrameChange { self.pending_frames.push(FrameChange {
frame_id: self.root_frame_id,
old_pipeline_id: None, old_pipeline_id: None,
new_pipeline_id: root_pipeline_id, new_pipeline_id: root_pipeline_id,
document_ready: false, document_ready: false,
@ -1304,6 +1300,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
is_private); is_private);
self.pending_frames.push(FrameChange { self.pending_frames.push(FrameChange {
frame_id: load_info.frame_id,
old_pipeline_id: load_info.old_pipeline_id, old_pipeline_id: load_info.old_pipeline_id,
new_pipeline_id: load_info.new_pipeline_id, new_pipeline_id: load_info.new_pipeline_id,
document_ready: false, document_ready: false,
@ -1351,8 +1348,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let display_alert_dialog = if PREFS.is_mozbrowser_enabled() { let display_alert_dialog = if PREFS.is_mozbrowser_enabled() {
let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info); let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info);
if parent_pipeline_info.is_some() { if parent_pipeline_info.is_some() {
let root_pipeline_id = self.root_frame_id let root_pipeline_id = self.frames.get(&self.root_frame_id)
.and_then(|root_frame_id| self.frames.get(&root_frame_id))
.map(|root_frame| root_frame.current.pipeline_id); .map(|root_frame| root_frame.current.pipeline_id);
let ancestor_info = self.get_mozbrowser_ancestor_info(pipeline_id); let ancestor_info = self.get_mozbrowser_ancestor_info(pipeline_id);
@ -1441,6 +1437,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let new_pipeline_id = PipelineId::new(); let new_pipeline_id = PipelineId::new();
self.new_pipeline(new_pipeline_id, None, None, window_size, None, load_data, false); self.new_pipeline(new_pipeline_id, None, None, window_size, None, load_data, false);
self.pending_frames.push(FrameChange { self.pending_frames.push(FrameChange {
frame_id: self.root_frame_id,
old_pipeline_id: Some(source_id), old_pipeline_id: Some(source_id),
new_pipeline_id: new_pipeline_id, new_pipeline_id: new_pipeline_id,
document_ready: false, document_ready: false,
@ -1458,11 +1455,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
fn handle_load_start_msg(&mut self, pipeline_id: PipelineId) { fn handle_load_start_msg(&mut self, pipeline_id: PipelineId) {
if let Some(frame_id) = self.get_top_level_frame_for_pipeline(Some(pipeline_id)) { let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
let forward = !self.joint_session_future(frame_id).is_empty(); let forward = !self.joint_session_future(frame_id).is_empty();
let back = !self.joint_session_past(frame_id).is_empty(); let back = !self.joint_session_past(frame_id).is_empty();
self.compositor_proxy.send(ToCompositorMsg::LoadStart(back, forward)); self.compositor_proxy.send(ToCompositorMsg::LoadStart(back, forward));
}
} }
fn handle_load_complete_msg(&mut self, pipeline_id: PipelineId) { fn handle_load_complete_msg(&mut self, pipeline_id: PipelineId) {
@ -1477,22 +1473,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
if webdriver_reset { if webdriver_reset {
self.webdriver.load_channel = None; self.webdriver.load_channel = None;
} }
if let Some(frame_id) = self.get_top_level_frame_for_pipeline(Some(pipeline_id)) { let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
let forward = !self.joint_session_future(frame_id).is_empty(); let forward = !self.joint_session_future(frame_id).is_empty();
let back = !self.joint_session_past(frame_id).is_empty(); let back = !self.joint_session_past(frame_id).is_empty();
let root = self.root_frame_id.is_none() || self.root_frame_id == Some(frame_id); let root = self.root_frame_id == frame_id;
self.compositor_proxy.send(ToCompositorMsg::LoadComplete(back, forward, root)); self.compositor_proxy.send(ToCompositorMsg::LoadComplete(back, forward, root));
}
self.handle_subframe_loaded(pipeline_id); self.handle_subframe_loaded(pipeline_id);
} }
fn handle_traverse_history_msg(&mut self, fn handle_traverse_history_msg(&mut self,
pipeline_id: Option<PipelineId>, pipeline_id: Option<PipelineId>,
direction: TraversalDirection) { direction: TraversalDirection) {
let frame_id = match self.get_top_level_frame_for_pipeline(pipeline_id) { let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
Some(frame_id) => frame_id,
None => return warn!("Traverse message received after root's closure."),
};
let mut traversal_info = HashMap::new(); let mut traversal_info = HashMap::new();
@ -1526,14 +1518,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
fn handle_joint_session_history_length(&self, pipeline_id: PipelineId, sender: IpcSender<u32>) { fn handle_joint_session_history_length(&self, pipeline_id: PipelineId, sender: IpcSender<u32>) {
let frame_id = match self.get_top_level_frame_for_pipeline(Some(pipeline_id)) { let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
Some(frame_id) => frame_id,
None => {
warn!("Jsh length message received after root's closure.");
let _ = sender.send(0);
return;
},
};
// Initialize length at 1 to count for the current active entry // Initialize length at 1 to count for the current active entry
let mut length = 1; let mut length = 1;
@ -1548,8 +1533,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Send to the explicitly focused pipeline (if it exists), or the root // Send to the explicitly focused pipeline (if it exists), or the root
// frame's current pipeline. If neither exist, fall back to sending to // frame's current pipeline. If neither exist, fall back to sending to
// the compositor below. // the compositor below.
let root_pipeline_id = self.root_frame_id let root_pipeline_id = self.frames.get(&self.root_frame_id)
.and_then(|root_frame_id| self.frames.get(&root_frame_id))
.map(|root_frame| root_frame.current.pipeline_id); .map(|root_frame| root_frame.current.pipeline_id);
let pipeline_id = self.focus_pipeline_id.or(root_pipeline_id); let pipeline_id = self.focus_pipeline_id.or(root_pipeline_id);
@ -1574,8 +1558,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_reload_msg(&mut self) { fn handle_reload_msg(&mut self) {
// Send Reload constellation msg to root script channel. // Send Reload constellation msg to root script channel.
let root_pipeline_id = self.root_frame_id let root_pipeline_id = self.frames.get(&self.root_frame_id)
.and_then(|root_frame_id| self.frames.get(&root_frame_id))
.map(|root_frame| root_frame.current.pipeline_id); .map(|root_frame| root_frame.current.pipeline_id);
if let Some(pipeline_id) = root_pipeline_id { if let Some(pipeline_id) = root_pipeline_id {
@ -1618,8 +1601,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_get_pipeline(&mut self, frame_id: Option<FrameId>, fn handle_get_pipeline(&mut self, frame_id: Option<FrameId>,
resp_chan: IpcSender<Option<(PipelineId, bool)>>) { resp_chan: IpcSender<Option<(PipelineId, bool)>>) {
let current_pipeline_id = frame_id.or(self.root_frame_id) let frame_id = frame_id.unwrap_or(self.root_frame_id);
.and_then(|frame_id| self.frames.get(&frame_id)) let current_pipeline_id = self.frames.get(&frame_id)
.map(|frame| frame.current.pipeline_id); .map(|frame| frame.current.pipeline_id);
let current_pipeline_id_loaded = current_pipeline_id let current_pipeline_id_loaded = current_pipeline_id
.map(|id| (id, true)); .map(|id| (id, true));
@ -1793,8 +1776,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
}, },
WebDriverCommandMsg::TakeScreenshot(pipeline_id, reply) => { WebDriverCommandMsg::TakeScreenshot(pipeline_id, reply) => {
let current_pipeline_id = self.root_frame_id let current_pipeline_id = self.frames.get(&self.root_frame_id)
.and_then(|root_frame_id| self.frames.get(&root_frame_id))
.map(|root_frame| root_frame.current.pipeline_id); .map(|root_frame| root_frame.current.pipeline_id);
if Some(pipeline_id) == current_pipeline_id { if Some(pipeline_id) == current_pipeline_id {
self.compositor_proxy.send(ToCompositorMsg::CreatePng(reply)); self.compositor_proxy.send(ToCompositorMsg::CreatePng(reply));
@ -1898,12 +1880,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
} }
fn get_top_level_frame_for_pipeline(&self, pipeline_id: Option<PipelineId>) -> Option<FrameId> { fn get_top_level_frame_for_pipeline(&self, pipeline_id: Option<PipelineId>) -> FrameId {
if PREFS.is_mozbrowser_enabled() { if PREFS.is_mozbrowser_enabled() {
pipeline_id.and_then(|id| self.get_mozbrowser_ancestor_info(id)) pipeline_id.and_then(|id| self.get_mozbrowser_ancestor_info(id))
.and_then(|pipeline_info| self.pipelines.get(&pipeline_info.1)) .and_then(|pipeline_info| self.pipelines.get(&pipeline_info.1))
.and_then(|pipeline| pipeline.frame) .and_then(|pipeline| pipeline.frame)
.or(self.root_frame_id) .unwrap_or(self.root_frame_id)
} else { } else {
// If mozbrowser is not enabled, the root frame is the only top-level frame // If mozbrowser is not enabled, the root frame is the only top-level frame
self.root_frame_id self.root_frame_id
@ -1933,51 +1915,41 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
} }
let frame_id = frame_change.old_pipeline_id.and_then(|old_pipeline_id| { if let Some(old_pipeline_id) = frame_change.old_pipeline_id {
// The new pipeline is replacing an old one. // The new pipeline is replacing an old one.
// Remove paint permissions for the pipeline being replaced. // Remove paint permissions for the pipeline being replaced.
self.revoke_paint_permission(old_pipeline_id); self.revoke_paint_permission(old_pipeline_id);
};
self.pipelines.get(&old_pipeline_id).and_then(|pipeline| pipeline.frame) if self.frames.contains_key(&frame_change.frame_id) {
}); // Add new pipeline to navigation frame, and return frames evicted from history.
if let Some(ref mut pipeline) = self.pipelines.get_mut(&frame_change.new_pipeline_id) {
pipeline.frame = Some(frame_change.frame_id);
}
match frame_id { if frame_change.replace {
Some(frame_id) => { let evicted = self.frames.get_mut(&frame_change.frame_id).map(|frame| {
// Add new pipeline to navigation frame, and return frames evicted from history. frame.replace_current(frame_change.new_pipeline_id)
if let Some(ref mut pipeline) = self.pipelines.get_mut(&frame_change.new_pipeline_id) { });
pipeline.frame = Some(frame_id); if let Some(evicted) = evicted {
self.close_pipeline(evicted.pipeline_id, ExitPipelineMode::Normal);
} }
} else {
if frame_change.replace { if let Some(ref mut frame) = self.frames.get_mut(&frame_change.frame_id) {
let evicted = self.frames.get_mut(&frame_id).map(|frame| { frame.load(frame_change.new_pipeline_id);
frame.replace_current(frame_change.new_pipeline_id)
});
if let Some(evicted) = evicted {
self.close_pipeline(evicted.pipeline_id, ExitPipelineMode::Normal);
}
} else {
if let Some(ref mut frame) = self.frames.get_mut(&frame_id) {
frame.load(frame_change.new_pipeline_id);
}
} }
} }
None => { } else {
// The new pipeline is in a new frame with no history // The new pipeline is in a new frame with no history
let frame_id = self.new_frame(frame_change.new_pipeline_id); self.new_frame(frame_change.frame_id, frame_change.new_pipeline_id);
// If a child frame, add it to the parent pipeline. Otherwise // If a child frame, add it to the parent pipeline. Otherwise
// it must surely be the root frame being created! // it must surely be the root frame being created!
match self.pipelines.get(&frame_change.new_pipeline_id) let parent_info = self.pipelines.get(&frame_change.new_pipeline_id)
.and_then(|pipeline| pipeline.parent_info) { .and_then(|pipeline| pipeline.parent_info);
Some((parent_id, _)) => { if let Some((parent_id, _)) = parent_info {
if let Some(parent) = self.pipelines.get_mut(&parent_id) { if let Some(parent) = self.pipelines.get_mut(&parent_id) {
parent.add_child(frame_id); parent.add_child(frame_change.frame_id);
}
}
None => {
assert!(self.root_frame_id.is_none());
self.root_frame_id = Some(frame_id);
}
} }
} }
} }
@ -1987,11 +1959,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// This is the result of a link being clicked and a navigation completing. // This is the result of a link being clicked and a navigation completing.
self.trigger_mozbrowserlocationchange(frame_change.new_pipeline_id); self.trigger_mozbrowserlocationchange(frame_change.new_pipeline_id);
let frame_id = match self.get_top_level_frame_for_pipeline(Some(frame_change.new_pipeline_id)) { let top_level_frame_id = self.get_top_level_frame_for_pipeline(Some(frame_change.new_pipeline_id));
Some(frame_id) => frame_id, self.clear_joint_session_future(top_level_frame_id);
None => return warn!("Tried to remove forward history after root frame closure."),
};
self.clear_joint_session_future(frame_id);
} }
// Build frame tree and send permission // Build frame tree and send permission
@ -2052,13 +2021,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("handle_window_size_msg: {:?} {:?}", new_size.initial_viewport.to_untyped(), debug!("handle_window_size_msg: {:?} {:?}", new_size.initial_viewport.to_untyped(),
new_size.visible_viewport.to_untyped()); new_size.visible_viewport.to_untyped());
if let Some(root_frame_id) = self.root_frame_id { if let Some(frame) = self.frames.get(&self.root_frame_id) {
// Send Resize (or ResizeInactive) messages to each // Send Resize (or ResizeInactive) messages to each
// pipeline in the frame tree. // pipeline in the frame tree.
let frame = match self.frames.get(&root_frame_id) {
None => return warn!("Frame {:?} resized after closing.", root_frame_id),
Some(frame) => frame,
};
let pipeline_id = frame.current.pipeline_id; let pipeline_id = frame.current.pipeline_id;
let pipeline = match self.pipelines.get(&pipeline_id) { let pipeline = match self.pipelines.get(&pipeline_id) {
None => return warn!("Pipeline {:?} resized after closing.", pipeline_id), None => return warn!("Pipeline {:?} resized after closing.", pipeline_id),
@ -2127,7 +2092,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// //
// If there is no root frame yet, the initial page has // If there is no root frame yet, the initial page has
// not loaded, so there is nothing to save yet. // not loaded, so there is nothing to save yet.
if self.root_frame_id.is_none() { if !self.frames.contains_key(&self.root_frame_id) {
return ReadyToSave::NoRootFrame; return ReadyToSave::NoRootFrame;
} }
@ -2384,9 +2349,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Revoke paint permission from a pipeline, and all children. // Revoke paint permission from a pipeline, and all children.
fn revoke_paint_permission(&self, pipeline_id: PipelineId) { fn revoke_paint_permission(&self, pipeline_id: PipelineId) {
let frame_id = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame); if let Some(frame_id) = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame) {
for frame in self.current_frame_tree_iter(frame_id) { for frame in self.current_frame_tree_iter(frame_id) {
self.pipelines.get(&frame.current.pipeline_id).map(|pipeline| pipeline.revoke_paint_permission()); self.pipelines.get(&frame.current.pipeline_id).map(|pipeline| pipeline.revoke_paint_permission());
}
} }
} }
@ -2396,15 +2362,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Note that this function can panic, due to ipc-channel creation failure. // Note that this function can panic, due to ipc-channel creation failure.
// avoiding this panic would require a mechanism for dealing // avoiding this panic would require a mechanism for dealing
// with low-resource scenarios. // with low-resource scenarios.
if let Some(root_frame_id) = self.root_frame_id { if let Some(frame_tree) = self.frame_to_sendable(self.root_frame_id) {
if let Some(frame_tree) = self.frame_to_sendable(root_frame_id) { let (chan, port) = ipc::channel().expect("Failed to create IPC channel!");
let (chan, port) = ipc::channel().expect("Failed to create IPC channel!"); self.compositor_proxy.send(ToCompositorMsg::SetFrameTree(frame_tree,
self.compositor_proxy.send(ToCompositorMsg::SetFrameTree(frame_tree, chan));
chan)); if port.recv().is_err() {
if port.recv().is_err() { warn!("Compositor has discarded SetFrameTree");
warn!("Compositor has discarded SetFrameTree"); return; // Our message has been discarded, probably shutting down.
return; // Our message has been discarded, probably shutting down.
}
} }
} }
@ -2489,11 +2453,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
} }
if let Some(root_frame_id) = self.root_frame_id { if let Some(root_frame) = self.frames.get(&self.root_frame_id) {
if let Some(root_frame) = self.frames.get(&root_frame_id) { if let Some(root_pipeline) = self.pipelines.get(&root_frame.current.pipeline_id) {
if let Some(root_pipeline) = self.pipelines.get(&root_frame.current.pipeline_id) { return root_pipeline.trigger_mozbrowser_event(None, event);
return root_pipeline.trigger_mozbrowser_event(None, event);
}
} }
} }
@ -2502,7 +2464,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn focused_pipeline_in_tree(&self, frame_id: FrameId) -> bool { fn focused_pipeline_in_tree(&self, frame_id: FrameId) -> bool {
self.focus_pipeline_id.map_or(false, |pipeline_id| { self.focus_pipeline_id.map_or(false, |pipeline_id| {
self.pipeline_exists_in_tree(pipeline_id, Some(frame_id)) self.pipeline_exists_in_tree(pipeline_id, frame_id)
}) })
} }
@ -2512,7 +2474,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn pipeline_exists_in_tree(&self, fn pipeline_exists_in_tree(&self,
pipeline_id: PipelineId, pipeline_id: PipelineId,
root_frame_id: Option<FrameId>) -> bool { root_frame_id: FrameId) -> bool {
self.current_frame_tree_iter(root_frame_id) self.current_frame_tree_iter(root_frame_id)
.any(|current_frame| current_frame.current.pipeline_id == pipeline_id) .any(|current_frame| current_frame.current.pipeline_id == pipeline_id)
} }

View file

@ -221,9 +221,6 @@ pub enum TraversalDirection {
Back(usize), Back(usize),
} }
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, PartialOrd, Ord)]
pub struct FrameId(pub u32);
/// Each pipeline ID needs to be unique. However, it also needs to be possible to /// Each pipeline ID needs to be unique. However, it also needs to be possible to
/// generate the pipeline ID from an iframe element (this simplifies a lot of other /// generate the pipeline ID from an iframe element (this simplifies a lot of other
/// code that makes use of pipeline IDs). /// code that makes use of pipeline IDs).
@ -242,7 +239,7 @@ pub struct FrameId(pub u32);
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct PipelineNamespace { pub struct PipelineNamespace {
id: PipelineNamespaceId, id: PipelineNamespaceId,
next_index: PipelineIndex, index: u32,
} }
impl PipelineNamespace { impl PipelineNamespace {
@ -251,21 +248,29 @@ impl PipelineNamespace {
assert!(tls.get().is_none()); assert!(tls.get().is_none());
tls.set(Some(PipelineNamespace { tls.set(Some(PipelineNamespace {
id: namespace_id, id: namespace_id,
next_index: PipelineIndex(0), index: 0,
})); }));
}); });
} }
fn next(&mut self) -> PipelineId { fn next_index(&mut self) -> u32 {
let pipeline_id = PipelineId { let result = self.index;
self.index = result + 1;
result
}
fn next_pipeline_id(&mut self) -> PipelineId {
PipelineId {
namespace_id: self.id, namespace_id: self.id,
index: self.next_index, index: PipelineIndex(self.next_index()),
}; }
}
let PipelineIndex(current_index) = self.next_index; fn next_frame_id(&mut self) -> FrameId {
self.next_index = PipelineIndex(current_index + 1); FrameId {
namespace_id: self.id,
pipeline_id index: FrameIndex(self.next_index()),
}
} }
} }
@ -289,24 +294,12 @@ impl PipelineId {
pub fn new() -> PipelineId { pub fn new() -> PipelineId {
PIPELINE_NAMESPACE.with(|tls| { PIPELINE_NAMESPACE.with(|tls| {
let mut namespace = tls.get().expect("No namespace set for this thread!"); let mut namespace = tls.get().expect("No namespace set for this thread!");
let new_pipeline_id = namespace.next(); let new_pipeline_id = namespace.next_pipeline_id();
tls.set(Some(namespace)); tls.set(Some(namespace));
new_pipeline_id new_pipeline_id
}) })
} }
// TODO(gw): This should be removed. It's only required because of the code
// that uses it in the devtools lib.rs file (which itself is a TODO). Once
// that is fixed, this should be removed. It also relies on the first
// call to PipelineId::new() returning (0,0), which is checked with an
// assert in handle_init_load().
pub fn fake_root_pipeline_id() -> PipelineId {
PipelineId {
namespace_id: PipelineNamespaceId(0),
index: PipelineIndex(0),
}
}
pub fn to_webrender(&self) -> webrender_traits::PipelineId { pub fn to_webrender(&self) -> webrender_traits::PipelineId {
let PipelineNamespaceId(namespace_id) = self.namespace_id; let PipelineNamespaceId(namespace_id) = self.namespace_id;
let PipelineIndex(index) = self.index; let PipelineIndex(index) = self.index;
@ -331,6 +324,41 @@ impl fmt::Display for PipelineId {
} }
} }
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct FrameIndex(pub u32);
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct FrameId {
pub namespace_id: PipelineNamespaceId,
pub index: FrameIndex
}
impl FrameId {
pub fn new() -> FrameId {
PIPELINE_NAMESPACE.with(|tls| {
let mut namespace = tls.get().expect("No namespace set for this thread!");
let new_frame_id = namespace.next_frame_id();
tls.set(Some(namespace));
new_frame_id
})
}
}
impl fmt::Display for FrameId {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let PipelineNamespaceId(namespace_id) = self.namespace_id;
let FrameIndex(index) = self.index;
write!(fmt, "({},{})", namespace_id, index)
}
}
// We provide ids just for unit testing.
pub const TEST_NAMESPACE: PipelineNamespaceId = PipelineNamespaceId(1234);
pub const TEST_PIPELINE_INDEX: PipelineIndex = PipelineIndex(5678);
pub const TEST_PIPELINE_ID: PipelineId = PipelineId { namespace_id: TEST_NAMESPACE, index: TEST_PIPELINE_INDEX };
pub const TEST_FRAME_INDEX: FrameIndex = FrameIndex(8765);
pub const TEST_FRAME_ID: FrameId = FrameId { namespace_id: TEST_NAMESPACE, index: TEST_FRAME_INDEX };
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] #[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub enum FrameType { pub enum FrameType {
IFrame, IFrame,

View file

@ -57,7 +57,7 @@ use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind};
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::Runtime; use js::rust::Runtime;
use libc; use libc;
use msg::constellation_msg::{FrameType, PipelineId, ReferrerPolicy, WindowSizeType}; use msg::constellation_msg::{FrameId, FrameType, PipelineId, ReferrerPolicy, WindowSizeType};
use net_traits::{Metadata, NetworkError, ResourceThreads}; use net_traits::{Metadata, NetworkError, ResourceThreads};
use net_traits::filemanager_thread::RelativePos; use net_traits::filemanager_thread::RelativePos;
use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image::base::{Image, ImageMetadata};
@ -308,7 +308,7 @@ no_jsmanaged_fields!(PropertyDeclarationBlock);
no_jsmanaged_fields!(HashSet<T>); no_jsmanaged_fields!(HashSet<T>);
// These three are interdependent, if you plan to put jsmanaged data // These three are interdependent, if you plan to put jsmanaged data
// in one of these make sure it is propagated properly to containing structs // in one of these make sure it is propagated properly to containing structs
no_jsmanaged_fields!(FrameType, WindowSizeData, WindowSizeType, PipelineId); no_jsmanaged_fields!(FrameId, FrameType, WindowSizeData, WindowSizeType, PipelineId);
no_jsmanaged_fields!(TimerEventId, TimerSource); no_jsmanaged_fields!(TimerEventId, TimerSource);
no_jsmanaged_fields!(WorkerId); no_jsmanaged_fields!(WorkerId);
no_jsmanaged_fields!(QuirksMode); no_jsmanaged_fields!(QuirksMode);

View file

@ -38,7 +38,7 @@ use dom::window::{ReflowReason, Window};
use ipc_channel::ipc; use ipc_channel::ipc;
use js::jsapi::{JSAutoCompartment, JSContext, MutableHandleValue}; use js::jsapi::{JSAutoCompartment, JSContext, MutableHandleValue};
use js::jsval::{NullValue, UndefinedValue}; use js::jsval::{NullValue, UndefinedValue};
use msg::constellation_msg::{FrameType, LoadData, PipelineId, TraversalDirection}; use msg::constellation_msg::{FrameType, FrameId, LoadData, PipelineId, TraversalDirection};
use net_traits::response::HttpsState; use net_traits::response::HttpsState;
use script_layout_interface::message::ReflowQueryType; use script_layout_interface::message::ReflowQueryType;
use script_traits::{IFrameLoadInfo, MozBrowserEvent, ScriptMsg as ConstellationMsg}; use script_traits::{IFrameLoadInfo, MozBrowserEvent, ScriptMsg as ConstellationMsg};
@ -67,6 +67,7 @@ bitflags! {
#[dom_struct] #[dom_struct]
pub struct HTMLIFrameElement { pub struct HTMLIFrameElement {
htmlelement: HTMLElement, htmlelement: HTMLElement,
frame_id: FrameId,
pipeline_id: Cell<Option<PipelineId>>, pipeline_id: Cell<Option<PipelineId>>,
sandbox: MutNullableHeap<JS<DOMTokenList>>, sandbox: MutNullableHeap<JS<DOMTokenList>>,
sandbox_allowance: Cell<Option<SandboxAllowance>>, sandbox_allowance: Cell<Option<SandboxAllowance>>,
@ -130,6 +131,7 @@ impl HTMLIFrameElement {
let load_info = IFrameLoadInfo { let load_info = IFrameLoadInfo {
load_data: load_data, load_data: load_data,
parent_pipeline_id: global_scope.pipeline_id(), parent_pipeline_id: global_scope.pipeline_id(),
frame_id: self.frame_id,
old_pipeline_id: old_pipeline_id, old_pipeline_id: old_pipeline_id,
new_pipeline_id: new_pipeline_id, new_pipeline_id: new_pipeline_id,
sandbox: sandboxed, sandbox: sandboxed,
@ -181,6 +183,7 @@ impl HTMLIFrameElement {
document: &Document) -> HTMLIFrameElement { document: &Document) -> HTMLIFrameElement {
HTMLIFrameElement { HTMLIFrameElement {
htmlelement: HTMLElement::new_inherited(local_name, prefix, document), htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
frame_id: FrameId::new(),
pipeline_id: Cell::new(None), pipeline_id: Cell::new(None),
sandbox: Default::default(), sandbox: Default::default(),
sandbox_allowance: Cell::new(None), sandbox_allowance: Cell::new(None),

View file

@ -449,6 +449,8 @@ pub struct IFrameLoadInfo {
pub load_data: Option<LoadData>, pub load_data: Option<LoadData>,
/// Pipeline ID of the parent of this iframe /// Pipeline ID of the parent of this iframe
pub parent_pipeline_id: PipelineId, pub parent_pipeline_id: PipelineId,
/// The ID for this iframe.
pub frame_id: FrameId,
/// The old pipeline ID for this iframe, if a page was previously loaded. /// The old pipeline ID for this iframe, if a page was previously loaded.
pub old_pipeline_id: Option<PipelineId>, pub old_pipeline_id: Option<PipelineId>,
/// The new pipeline ID that the iframe has generated. /// The new pipeline ID that the iframe has generated.

View file

@ -19,7 +19,7 @@ use hyper::server::{Handler, Listening, Server};
use hyper::server::{Request as HyperRequest, Response as HyperResponse}; use hyper::server::{Request as HyperRequest, Response as HyperResponse};
use hyper::status::StatusCode; use hyper::status::StatusCode;
use hyper::uri::RequestUri; use hyper::uri::RequestUri;
use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use msg::constellation_msg::{ReferrerPolicy, TEST_PIPELINE_ID};
use net::fetch::cors_cache::CORSCache; use net::fetch::cors_cache::CORSCache;
use net::fetch::methods::{FetchContext, fetch, fetch_with_cors_cache}; use net::fetch::methods::{FetchContext, fetch, fetch_with_cors_cache};
use net::http_loader::HttpState; use net::http_loader::HttpState;
@ -776,8 +776,7 @@ fn test_fetch_with_devtools() {
let (mut server, url) = make_server(handler); let (mut server, url) = make_server(handler);
let origin = Origin::Origin(url.origin()); let origin = Origin::Origin(url.origin());
let pipeline_id = PipelineId::fake_root_pipeline_id(); let request = Request::new(url.clone(), Some(origin), false, Some(TEST_PIPELINE_ID));
let request = Request::new(url.clone(), Some(origin), false, Some(pipeline_id));
*request.referrer.borrow_mut() = Referrer::NoReferrer; *request.referrer.borrow_mut() = Referrer::NoReferrer;
let (devtools_chan, devtools_port) = channel::<DevtoolsControlMsg>(); let (devtools_chan, devtools_port) = channel::<DevtoolsControlMsg>();
@ -815,7 +814,7 @@ fn test_fetch_with_devtools() {
method: Method::Get, method: Method::Get,
headers: headers, headers: headers,
body: None, body: None,
pipeline_id: pipeline_id, pipeline_id: TEST_PIPELINE_ID,
startedDateTime: devhttprequest.startedDateTime, startedDateTime: devhttprequest.startedDateTime,
timeStamp: devhttprequest.timeStamp, timeStamp: devhttprequest.timeStamp,
connect_time: devhttprequest.connect_time, connect_time: devhttprequest.connect_time,
@ -832,7 +831,7 @@ fn test_fetch_with_devtools() {
headers: Some(response_headers), headers: Some(response_headers),
status: Some((200, b"OK".to_vec())), status: Some((200, b"OK".to_vec())),
body: None, body: None,
pipeline_id: pipeline_id, pipeline_id: TEST_PIPELINE_ID,
}; };
assert_eq!(devhttprequest, httprequest); assert_eq!(devhttprequest, httprequest);

View file

@ -18,7 +18,7 @@ use hyper::http::RawStatus;
use hyper::method::Method; use hyper::method::Method;
use hyper::mime::{Mime, SubLevel, TopLevel}; use hyper::mime::{Mime, SubLevel, TopLevel};
use hyper::status::StatusCode; use hyper::status::StatusCode;
use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use msg::constellation_msg::{PipelineId, ReferrerPolicy, TEST_PIPELINE_ID};
use net::cookie::Cookie; use net::cookie::Cookie;
use net::cookie_storage::CookieStorage; use net::cookie_storage::CookieStorage;
use net::hsts::HstsEntry; use net::hsts::HstsEntry;
@ -47,7 +47,7 @@ impl LoadOrigin for HttpTest {
None None
} }
fn pipeline_id(&self) -> Option<PipelineId> { fn pipeline_id(&self) -> Option<PipelineId> {
Some(PipelineId::fake_root_pipeline_id()) Some(TEST_PIPELINE_ID)
} }
} }
@ -472,8 +472,6 @@ fn test_request_and_response_data_with_network_messages() {
let url = Url::parse("https://mozilla.com").unwrap(); let url = Url::parse("https://mozilla.com").unwrap();
let (devtools_chan, devtools_port) = mpsc::channel::<DevtoolsControlMsg>(); let (devtools_chan, devtools_port) = mpsc::channel::<DevtoolsControlMsg>();
// This will probably have to be changed as it uses fake_root_pipeline_id which is marked for removal.
let pipeline_id = PipelineId::fake_root_pipeline_id();
let mut load_data = LoadData::new(LoadContext::Browsing, url.clone(), &HttpTest); let mut load_data = LoadData::new(LoadContext::Browsing, url.clone(), &HttpTest);
let mut request_headers = Headers::new(); let mut request_headers = Headers::new();
request_headers.set(Host { hostname: "bar.foo".to_owned(), port: None }); request_headers.set(Host { hostname: "bar.foo".to_owned(), port: None });
@ -521,7 +519,7 @@ fn test_request_and_response_data_with_network_messages() {
method: Method::Get, method: Method::Get,
headers: headers, headers: headers,
body: None, body: None,
pipeline_id: pipeline_id, pipeline_id: TEST_PIPELINE_ID,
startedDateTime: devhttprequest.startedDateTime, startedDateTime: devhttprequest.startedDateTime,
timeStamp: devhttprequest.timeStamp, timeStamp: devhttprequest.timeStamp,
connect_time: devhttprequest.connect_time, connect_time: devhttprequest.connect_time,
@ -538,7 +536,7 @@ fn test_request_and_response_data_with_network_messages() {
headers: Some(response_headers), headers: Some(response_headers),
status: Some((200, b"OK".to_vec())), status: Some((200, b"OK".to_vec())),
body: None, body: None,
pipeline_id: pipeline_id, pipeline_id: TEST_PIPELINE_ID,
}; };
assert_eq!(devhttprequest, httprequest); assert_eq!(devhttprequest, httprequest);