Auto merge of #12909 - ConnorGBrewster:framestate, r=asajeffrey

Add FrameState

<!-- Please describe your changes on the following line: -->
r? @asajeffrey
Might as well get this in now, since it may be a while before I can figure out what is causing the panics on the pending pipelines PR.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [X] These changes do not require tests because refactoring.

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/12909)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-08-17 22:11:59 -05:00 committed by GitHub
commit 4e7c689a81

View file

@ -219,12 +219,29 @@ pub struct InitialConstellationState {
pub webrender_api_sender: Option<webrender_traits::RenderApiSender>, pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
} }
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct FrameState {
instant: Instant,
pipeline_id: PipelineId,
frame_id: FrameId,
}
impl FrameState {
fn new(pipeline_id: PipelineId, frame_id: FrameId) -> FrameState {
FrameState {
instant: Instant::now(),
pipeline_id: pipeline_id,
frame_id: frame_id,
}
}
}
/// Stores the navigation context for a single frame in the frame tree. /// Stores the navigation context for a single frame in the frame tree.
struct Frame { struct Frame {
id: FrameId, id: FrameId,
prev: Vec<(PipelineId, Instant)>, prev: Vec<FrameState>,
current: (PipelineId, Instant), current: FrameState,
next: Vec<(PipelineId, Instant)>, next: Vec<FrameState>,
} }
impl Frame { impl Frame {
@ -232,17 +249,17 @@ impl Frame {
Frame { Frame {
id: id, id: id,
prev: vec!(), prev: vec!(),
current: (pipeline_id, Instant::now()), current: FrameState::new(pipeline_id, id),
next: vec!(), next: vec!(),
} }
} }
fn load(&mut self, pipeline_id: PipelineId) { fn load(&mut self, pipeline_id: PipelineId) {
self.prev.push(self.current); self.prev.push(self.current.clone());
self.current = (pipeline_id, Instant::now()); self.current = FrameState::new(pipeline_id, self.id);
} }
fn remove_forward_entries(&mut self) -> Vec<(PipelineId, Instant)> { fn remove_forward_entries(&mut self) -> Vec<FrameState> {
replace(&mut self.next, vec!()) replace(&mut self.next, vec!())
} }
} }
@ -279,10 +296,10 @@ impl<'a> Iterator for FrameTreeIterator<'a> {
continue; continue;
}, },
}; };
let pipeline = match self.pipelines.get(&frame.current.0) { let pipeline = match self.pipelines.get(&frame.current.pipeline_id) {
Some(pipeline) => pipeline, Some(pipeline) => pipeline,
None => { None => {
warn!("Pipeline {:?} iterated after closure.", frame.current.0); warn!("Pipeline {:?} iterated after closure.", frame.current.pipeline_id);
continue; continue;
}, },
}; };
@ -313,8 +330,8 @@ impl<'a> Iterator for FullFrameTreeIterator<'a> {
continue; continue;
}, },
}; };
for &(pipeline_id, _) in frame.prev.iter().chain(frame.next.iter()).chain(once(&frame.current)) { for entry in frame.prev.iter().chain(frame.next.iter()).chain(once(&frame.current)) {
if let Some(pipeline) = self.pipelines.get(&pipeline_id) { if let Some(pipeline) = self.pipelines.get(&entry.pipeline_id) {
self.stack.extend(pipeline.children.iter().map(|&c| c)); self.stack.extend(pipeline.children.iter().map(|&c| c));
} }
} }
@ -622,7 +639,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn joint_session_future(&self, frame_id_root: FrameId) -> Vec<(Instant, FrameId, PipelineId)> { fn joint_session_future(&self, frame_id_root: FrameId) -> Vec<(Instant, FrameId, PipelineId)> {
let mut future = vec!(); let mut future = vec!();
for frame in self.full_frame_tree_iter(frame_id_root) { for frame in self.full_frame_tree_iter(frame_id_root) {
future.extend(frame.next.iter().map(|&(pipeline_id, instant)| (instant, frame.id, pipeline_id))); future.extend(frame.next.iter().map(|entry| (entry.instant, entry.frame_id, entry.pipeline_id)));
} }
// reverse sorting // reverse sorting
@ -633,10 +650,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn joint_session_past(&self, frame_id_root: FrameId) -> Vec<(Instant, FrameId, PipelineId)> { fn joint_session_past(&self, frame_id_root: FrameId) -> Vec<(Instant, FrameId, PipelineId)> {
let mut past = vec!(); let mut past = vec!();
for frame in self.full_frame_tree_iter(frame_id_root) { for frame in self.full_frame_tree_iter(frame_id_root) {
let mut prev_instant = frame.current.1; let mut prev_instant = frame.current.instant;
for &(pipeline_id, instant) in frame.prev.iter().rev() { for entry in frame.prev.iter().rev() {
past.push((prev_instant, frame.id, pipeline_id)); past.push((prev_instant, entry.frame_id, entry.pipeline_id));
prev_instant = instant; prev_instant = entry.instant;
} }
} }
@ -1327,7 +1344,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
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.root_frame_id
.and_then(|root_frame_id| self.frames.get(&root_frame_id)) .and_then(|root_frame_id| self.frames.get(&root_frame_id))
.map(|root_frame| root_frame.current.0); .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);
if let Some((ancestor_id, subpage_id)) = ancestor_info { if let Some((ancestor_id, subpage_id)) = ancestor_info {
@ -1517,7 +1534,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// the compositor below. // the compositor below.
let root_pipeline_id = self.root_frame_id let root_pipeline_id = self.root_frame_id
.and_then(|root_frame_id| self.frames.get(&root_frame_id)) .and_then(|root_frame_id| self.frames.get(&root_frame_id))
.map(|root_frame| root_frame.current.0); .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);
match pipeline_id { match pipeline_id {
@ -1543,7 +1560,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// 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.root_frame_id
.and_then(|root_frame_id| self.frames.get(&root_frame_id)) .and_then(|root_frame_id| self.frames.get(&root_frame_id))
.map(|root_frame| root_frame.current.0); .map(|root_frame| root_frame.current.pipeline_id);
if let Some(pipeline_id) = root_pipeline_id { if let Some(pipeline_id) = root_pipeline_id {
let msg = ConstellationControlMsg::Reload(pipeline_id); let msg = ConstellationControlMsg::Reload(pipeline_id);
@ -1587,7 +1604,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
resp_chan: IpcSender<Option<(PipelineId, bool)>>) { resp_chan: IpcSender<Option<(PipelineId, bool)>>) {
let current_pipeline_id = frame_id.or(self.root_frame_id) let current_pipeline_id = frame_id.or(self.root_frame_id)
.and_then(|frame_id| self.frames.get(&frame_id)) .and_then(|frame_id| self.frames.get(&frame_id))
.map(|frame| frame.current.0); .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));
let pipeline_id_loaded = self.pending_frames.iter().rev() let pipeline_id_loaded = self.pending_frames.iter().rev()
@ -1657,7 +1674,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_set_visible_msg(&mut self, pipeline_id: PipelineId, visible: bool) { fn handle_set_visible_msg(&mut self, pipeline_id: PipelineId, visible: bool) {
let frame_id = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame); let frame_id = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame);
let child_pipeline_ids: Vec<PipelineId> = self.current_frame_tree_iter(frame_id) let child_pipeline_ids: Vec<PipelineId> = self.current_frame_tree_iter(frame_id)
.map(|frame| frame.current.0) .map(|frame| frame.current.pipeline_id)
.collect(); .collect();
for id in child_pipeline_ids { for id in child_pipeline_ids {
if let Some(pipeline) = self.pipelines.get_mut(&id) { if let Some(pipeline) = self.pipelines.get_mut(&id) {
@ -1755,7 +1772,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.root_frame_id
.and_then(|root_frame_id| self.frames.get(&root_frame_id)) .and_then(|root_frame_id| self.frames.get(&root_frame_id))
.map(|root_frame| root_frame.current.0); .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));
} else { } else {
@ -1775,16 +1792,16 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let prev_pipeline_id = match self.frames.get_mut(&frame_id) { let prev_pipeline_id = match self.frames.get_mut(&frame_id) {
Some(frame) => { Some(frame) => {
let prev = frame.current.0; let prev = frame.current.pipeline_id;
// Check that this frame contains the pipeline passed in, so that this does not // Check that this frame contains the pipeline passed in, so that this does not
// change Frame's state before realizing `next_pipeline_id` is invalid. // change Frame's state before realizing `next_pipeline_id` is invalid.
let mut contains_pipeline = false; let mut contains_pipeline = false;
if frame.next.iter().find(|&&(pipeline_id, _)| next_pipeline_id == pipeline_id).is_some() { if frame.next.iter().find(|entry| next_pipeline_id == entry.pipeline_id).is_some() {
contains_pipeline = true; contains_pipeline = true;
frame.prev.push(frame.current); frame.prev.push(frame.current.clone());
while let Some(entry) = frame.next.pop() { while let Some(entry) = frame.next.pop() {
if entry.0 == next_pipeline_id { if entry.pipeline_id == next_pipeline_id {
frame.current = entry; frame.current = entry;
break; break;
} else { } else {
@ -1794,11 +1811,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
if !contains_pipeline && if !contains_pipeline &&
frame.prev.iter().find(|&&(pipeline_id, _)| next_pipeline_id == pipeline_id).is_some() { frame.prev.iter().find(|entry| next_pipeline_id == entry.pipeline_id).is_some() {
contains_pipeline = true; contains_pipeline = true;
frame.next.push(frame.current); frame.next.push(frame.current.clone());
while let Some(entry) = frame.prev.pop() { while let Some(entry) = frame.prev.pop() {
if entry.0 == next_pipeline_id { if entry.pipeline_id == next_pipeline_id {
frame.current = entry; frame.current = entry;
break; break;
} else { } else {
@ -2011,7 +2028,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
None => return warn!("Frame {:?} resized after closing.", root_frame_id), None => return warn!("Frame {:?} resized after closing.", root_frame_id),
Some(frame) => frame, Some(frame) => frame,
}; };
let pipeline_id = frame.current.0; 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),
Some(pipeline) => pipeline, Some(pipeline) => pipeline,
@ -2021,8 +2038,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
new_size, new_size,
size_type size_type
)); ));
for &(pipeline_id, _) in frame.prev.iter().chain(&frame.next) { for entry in frame.prev.iter().chain(&frame.next) {
let pipeline = match self.pipelines.get(&pipeline_id) { let pipeline = match self.pipelines.get(&entry.pipeline_id) {
None => { None => {
warn!("Inactive pipeline {:?} resized after closing.", pipeline_id); warn!("Inactive pipeline {:?} resized after closing.", pipeline_id);
continue; continue;
@ -2097,7 +2114,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// are met, then the output image should not change and a reftest // are met, then the output image should not change and a reftest
// screenshot can safely be written. // screenshot can safely be written.
for frame in self.current_frame_tree_iter(self.root_frame_id) { for frame in self.current_frame_tree_iter(self.root_frame_id) {
let pipeline_id = frame.current.0; let pipeline_id = frame.current.pipeline_id;
let pipeline = match self.pipelines.get(&pipeline_id) { let pipeline = match self.pipelines.get(&pipeline_id) {
None => { None => {
@ -2124,7 +2141,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
// See if this pipeline has reached idle script state yet. // See if this pipeline has reached idle script state yet.
match self.document_states.get(&frame.current.0) { match self.document_states.get(&frame.current.pipeline_id) {
Some(&DocumentState::Idle) => {} Some(&DocumentState::Idle) => {}
Some(&DocumentState::Pending) | None => { Some(&DocumentState::Pending) | None => {
return ReadyToSave::DocumentLoading; return ReadyToSave::DocumentLoading;
@ -2144,7 +2161,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
// Get the epoch that the compositor has drawn for this pipeline. // Get the epoch that the compositor has drawn for this pipeline.
let compositor_epoch = pipeline_states.get(&frame.current.0); let compositor_epoch = pipeline_states.get(&frame.current.pipeline_id);
match compositor_epoch { match compositor_epoch {
Some(compositor_epoch) => { Some(compositor_epoch) => {
// Synchronously query the layout thread to see if the current // Synchronously query the layout thread to see if the current
@ -2187,19 +2204,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
}; };
evicted_pipelines.extend_from_slice(&frame.remove_forward_entries()); evicted_pipelines.extend_from_slice(&frame.remove_forward_entries());
for &(pipeline_id, _) in frame.next.iter().chain(frame.prev.iter()).chain(once(&frame.current)) { for entry in frame.next.iter().chain(frame.prev.iter()).chain(once(&frame.current)) {
let pipeline = match self.pipelines.get(&pipeline_id) { let pipeline = match self.pipelines.get(&entry.pipeline_id) {
Some(pipeline) => pipeline, Some(pipeline) => pipeline,
None => { None => {
warn!("Removed forward history after pipeline {:?} closure.", pipeline_id); warn!("Removed forward history after pipeline {:?} closure.", entry.pipeline_id);
continue; continue;
} }
}; };
frames_to_clear.extend_from_slice(&pipeline.children); frames_to_clear.extend_from_slice(&pipeline.children);
} }
} }
for (pipeline_id, _) in evicted_pipelines { for entry in evicted_pipelines {
self.close_pipeline(pipeline_id, ExitPipelineMode::Normal); self.close_pipeline(entry.pipeline_id, ExitPipelineMode::Normal);
} }
} }
@ -2210,7 +2227,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// ordering is vital - so that if close_pipeline() ends up closing // ordering is vital - so that if close_pipeline() ends up closing
// any child frames, they can be removed from the parent frame correctly. // any child frames, they can be removed from the parent frame correctly.
let parent_info = self.frames.get(&frame_id) let parent_info = self.frames.get(&frame_id)
.and_then(|frame| self.pipelines.get(&frame.current.0)) .and_then(|frame| self.pipelines.get(&frame.current.pipeline_id))
.and_then(|pipeline| pipeline.parent_info); .and_then(|pipeline| pipeline.parent_info);
let pipelines_to_close = { let pipelines_to_close = {
@ -2218,15 +2235,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
if let Some(frame) = self.frames.get(&frame_id) { if let Some(frame) = self.frames.get(&frame_id) {
pipelines_to_close.extend_from_slice(&frame.next); pipelines_to_close.extend_from_slice(&frame.next);
pipelines_to_close.push(frame.current); pipelines_to_close.push(frame.current.clone());
pipelines_to_close.extend_from_slice(&frame.prev); pipelines_to_close.extend_from_slice(&frame.prev);
} }
pipelines_to_close pipelines_to_close
}; };
for (pipeline_id, _) in pipelines_to_close { for entry in pipelines_to_close {
self.close_pipeline(pipeline_id, exit_mode); self.close_pipeline(entry.pipeline_id, exit_mode);
} }
if self.frames.remove(&frame_id).is_none() { if self.frames.remove(&frame_id).is_none() {
@ -2320,7 +2337,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Convert a frame to a sendable form to pass to the compositor // Convert a frame to a sendable form to pass to the compositor
fn frame_to_sendable(&self, frame_id: FrameId) -> Option<SendableFrameTree> { fn frame_to_sendable(&self, frame_id: FrameId) -> Option<SendableFrameTree> {
self.frames.get(&frame_id).and_then(|frame: &Frame| { self.frames.get(&frame_id).and_then(|frame: &Frame| {
self.pipelines.get(&frame.current.0).map(|pipeline: &Pipeline| { self.pipelines.get(&frame.current.pipeline_id).map(|pipeline: &Pipeline| {
let mut frame_tree = SendableFrameTree { let mut frame_tree = SendableFrameTree {
pipeline: pipeline.to_sendable(), pipeline: pipeline.to_sendable(),
size: pipeline.size, size: pipeline.size,
@ -2342,7 +2359,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
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); let 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.0).map(|pipeline| pipeline.revoke_paint_permission()); self.pipelines.get(&frame.current.pipeline_id).map(|pipeline| pipeline.revoke_paint_permission());
} }
} }
@ -2365,7 +2382,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
for frame in self.current_frame_tree_iter(self.root_frame_id) { for frame in self.current_frame_tree_iter(self.root_frame_id) {
self.pipelines.get(&frame.current.0).map(|pipeline| pipeline.grant_paint_permission()); self.pipelines.get(&frame.current.pipeline_id).map(|pipeline| pipeline.grant_paint_permission());
} }
} }
@ -2447,7 +2464,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
if let Some(root_frame_id) = self.root_frame_id { if let Some(root_frame_id) = self.root_frame_id {
if let Some(root_frame) = self.frames.get(&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.0) { 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);
} }
} }
@ -2470,7 +2487,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
pipeline_id: PipelineId, pipeline_id: PipelineId,
root_frame_id: Option<FrameId>) -> bool { root_frame_id: Option<FrameId>) -> bool {
self.current_frame_tree_iter(root_frame_id) self.current_frame_tree_iter(root_frame_id)
.any(|current_frame| current_frame.current.0 == pipeline_id) .any(|current_frame| current_frame.current.pipeline_id == pipeline_id)
} }
} }