mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
Implement beginnings of joint session history
Fix backward navigation make use of history iterator Add frame iterator add different back logic cleanup navigation_info Add extra explanation for iter logic Remove forward history on full frame tree Rename navigation to traversal where appropriate check full tree for can go back/forward simplify frame iter logic remove FrameIterator cleanup history iter reduce amount of vec allocations removed extra parenthesis Remove history iterator cleanup after rebasing avoid recursive vec allocation remove full_frame_tree remove_forward_history_in_frame_tree -> clear_joint_session_future
This commit is contained in:
parent
4ae0897175
commit
f131818763
7 changed files with 328 additions and 201 deletions
|
@ -29,7 +29,7 @@ use layers::rendergl;
|
||||||
use layers::rendergl::RenderContext;
|
use layers::rendergl::RenderContext;
|
||||||
use layers::scene::Scene;
|
use layers::scene::Scene;
|
||||||
use msg::constellation_msg::{Image, PixelFormat, Key, KeyModifiers, KeyState};
|
use msg::constellation_msg::{Image, PixelFormat, Key, KeyModifiers, KeyState};
|
||||||
use msg::constellation_msg::{LoadData, NavigationDirection, PipelineId};
|
use msg::constellation_msg::{LoadData, TraversalDirection, PipelineId};
|
||||||
use msg::constellation_msg::{PipelineIndex, PipelineNamespaceId, WindowSizeType};
|
use msg::constellation_msg::{PipelineIndex, PipelineNamespaceId, WindowSizeType};
|
||||||
use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest};
|
use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest};
|
||||||
use profile_traits::time::{self, ProfilerCategory, profile};
|
use profile_traits::time::{self, ProfilerCategory, profile};
|
||||||
|
@ -1862,10 +1862,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
|
|
||||||
fn on_navigation_window_event(&self, direction: WindowNavigateMsg) {
|
fn on_navigation_window_event(&self, direction: WindowNavigateMsg) {
|
||||||
let direction = match direction {
|
let direction = match direction {
|
||||||
windowing::WindowNavigateMsg::Forward => NavigationDirection::Forward(1),
|
windowing::WindowNavigateMsg::Forward => TraversalDirection::Forward(1),
|
||||||
windowing::WindowNavigateMsg::Back => NavigationDirection::Back(1),
|
windowing::WindowNavigateMsg::Back => TraversalDirection::Back(1),
|
||||||
};
|
};
|
||||||
let msg = ConstellationMsg::Navigate(None, direction);
|
let msg = ConstellationMsg::TraverseHistory(None, direction);
|
||||||
if let Err(e) = self.constellation_chan.send(msg) {
|
if let Err(e) = self.constellation_chan.send(msg) {
|
||||||
warn!("Sending navigation to constellation failed ({}).", e);
|
warn!("Sending navigation to constellation failed ({}).", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ use layout_traits::LayoutThreadFactory;
|
||||||
use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
|
use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
|
||||||
use msg::constellation_msg::{FrameId, FrameType, PipelineId};
|
use msg::constellation_msg::{FrameId, FrameType, PipelineId};
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
|
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
|
||||||
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, NavigationDirection};
|
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
||||||
use msg::constellation_msg::{SubpageId, WindowSizeType};
|
use msg::constellation_msg::{SubpageId, WindowSizeType};
|
||||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::filemanager_thread::FileManagerThreadMsg;
|
use net_traits::filemanager_thread::FileManagerThreadMsg;
|
||||||
|
@ -50,12 +50,14 @@ use script_traits::{webdriver_msg, LogEntry, ServiceWorkerMsg};
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::io::Error as IOError;
|
use std::io::Error as IOError;
|
||||||
|
use std::iter::once;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::mpsc::{Sender, channel, Receiver};
|
use std::sync::mpsc::{Sender, channel, Receiver};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use std::time::Instant;
|
||||||
use style_traits::PagePx;
|
use style_traits::PagePx;
|
||||||
use style_traits::cursor::Cursor;
|
use style_traits::cursor::Cursor;
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
|
@ -219,26 +221,26 @@ pub struct InitialConstellationState {
|
||||||
|
|
||||||
/// 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 {
|
||||||
prev: Vec<PipelineId>,
|
prev: Vec<(PipelineId, Instant)>,
|
||||||
current: PipelineId,
|
current: (PipelineId, Instant),
|
||||||
next: Vec<PipelineId>,
|
next: Vec<(PipelineId, Instant)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
fn new(pipeline_id: PipelineId) -> Frame {
|
fn new(pipeline_id: PipelineId) -> Frame {
|
||||||
Frame {
|
Frame {
|
||||||
prev: vec!(),
|
prev: vec!(),
|
||||||
current: pipeline_id,
|
current: (pipeline_id, Instant::now()),
|
||||||
next: vec!(),
|
next: vec!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(&mut self, pipeline_id: PipelineId) -> Vec<PipelineId> {
|
fn load(&mut self, pipeline_id: PipelineId) {
|
||||||
// TODO(gw): To also allow navigations within subframes
|
|
||||||
// to affect the parent navigation history, this should bubble
|
|
||||||
// up the navigation change to each parent.
|
|
||||||
self.prev.push(self.current);
|
self.prev.push(self.current);
|
||||||
self.current = pipeline_id;
|
self.current = (pipeline_id, Instant::now());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_forward_entries(&mut self) -> Vec<(PipelineId, Instant)> {
|
||||||
replace(&mut self.next, vec!())
|
replace(&mut self.next, vec!())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,10 +277,10 @@ impl<'a> Iterator for FrameTreeIterator<'a> {
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let pipeline = match self.pipelines.get(&frame.current) {
|
let pipeline = match self.pipelines.get(&frame.current.0) {
|
||||||
Some(pipeline) => pipeline,
|
Some(pipeline) => pipeline,
|
||||||
None => {
|
None => {
|
||||||
warn!("Pipeline {:?} iterated after closure.", frame.current);
|
warn!("Pipeline {:?} iterated after closure.", frame.current.0);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -578,6 +580,70 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn joint_session_future(&self, frame_id_root: FrameId) -> Vec<(Instant, FrameId, PipelineId)> {
|
||||||
|
let mut future = vec!();
|
||||||
|
self.get_future_entries(frame_id_root, &mut future);
|
||||||
|
|
||||||
|
// reverse sorting
|
||||||
|
future.sort_by(|a, b| b.cmp(a));
|
||||||
|
future
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_future_entries(&self, frame_id_root: FrameId, mut future: &mut Vec<(Instant, FrameId, PipelineId)>) {
|
||||||
|
let frame = match self.frames.get(&frame_id_root) {
|
||||||
|
Some(frame) => frame,
|
||||||
|
None => return warn!("Tried to get frame future after frame {:?} closed.", frame_id_root),
|
||||||
|
};
|
||||||
|
|
||||||
|
future.extend(frame.next.iter().map(|&(pipeline_id, instant)| (instant, frame_id_root, pipeline_id)));
|
||||||
|
|
||||||
|
for &(pipeline_id, _) in frame.next.iter().chain(once(&frame.current)) {
|
||||||
|
let pipeline = match self.pipelines.get(&pipeline_id) {
|
||||||
|
Some(pipeline) => pipeline,
|
||||||
|
None => {
|
||||||
|
warn!("Tried to get pipeline {:?} for child lookup after closure.", pipeline_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for &frame_id in &pipeline.children {
|
||||||
|
self.get_future_entries(frame_id, &mut future);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn joint_session_past(&self, frame_id_root: FrameId) -> Vec<(Instant, FrameId, PipelineId)> {
|
||||||
|
let mut past = vec!();
|
||||||
|
self.get_past_entries(frame_id_root, &mut past);
|
||||||
|
|
||||||
|
past.sort();
|
||||||
|
past
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_past_entries(&self, frame_id_root: FrameId, mut past: &mut Vec<(Instant, FrameId, PipelineId)>) {
|
||||||
|
let frame = match self.frames.get(&frame_id_root) {
|
||||||
|
Some(frame) => frame,
|
||||||
|
None => return warn!("Tried to get frame past after frame {:?} closed.", frame_id_root),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut prev_instant = frame.current.1;
|
||||||
|
for &(pipeline_id, instant) in frame.prev.iter().rev() {
|
||||||
|
past.push((prev_instant, frame_id_root, pipeline_id));
|
||||||
|
prev_instant = instant;
|
||||||
|
}
|
||||||
|
for &(pipeline_id, _) in frame.prev.iter().chain(once(&frame.current)) {
|
||||||
|
let pipeline = match self.pipelines.get(&pipeline_id) {
|
||||||
|
Some(pipeline) => pipeline,
|
||||||
|
None => {
|
||||||
|
warn!("Tried to get pipeline {:?} for child lookup after closure.", pipeline_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for frame_id in &pipeline.children {
|
||||||
|
self.get_past_entries(*frame_id, &mut past);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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, pipeline_id: PipelineId) -> FrameId {
|
||||||
let id = self.next_frame_id;
|
let id = self.next_frame_id;
|
||||||
|
@ -710,9 +776,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
self.handle_init_load(url);
|
self.handle_init_load(url);
|
||||||
}
|
}
|
||||||
// Handle a forward or back request
|
// Handle a forward or back request
|
||||||
FromCompositorMsg::Navigate(pipeline_info, direction) => {
|
FromCompositorMsg::TraverseHistory(pipeline_id, direction) => {
|
||||||
debug!("constellation got navigation message from compositor");
|
debug!("constellation got traverse history message from compositor");
|
||||||
self.handle_navigate_msg(pipeline_info, direction);
|
self.handle_traverse_history_msg(pipeline_id, direction);
|
||||||
}
|
}
|
||||||
FromCompositorMsg::WindowSize(new_size, size_type) => {
|
FromCompositorMsg::WindowSize(new_size, size_type) => {
|
||||||
debug!("constellation got window resize message");
|
debug!("constellation got window resize message");
|
||||||
|
@ -760,7 +826,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
// A page loaded has completed all parsing, script, and reflow messages have been sent.
|
// A page loaded has completed all parsing, script, and reflow messages have been sent.
|
||||||
FromScriptMsg::LoadComplete(pipeline_id) => {
|
FromScriptMsg::LoadComplete(pipeline_id) => {
|
||||||
debug!("constellation got load complete message");
|
debug!("constellation got load complete message");
|
||||||
self.handle_load_complete_msg(&pipeline_id)
|
self.handle_load_complete_msg(pipeline_id)
|
||||||
}
|
}
|
||||||
// The DOM load event fired on a document
|
// The DOM load event fired on a document
|
||||||
FromScriptMsg::DOMLoad(pipeline_id) => {
|
FromScriptMsg::DOMLoad(pipeline_id) => {
|
||||||
|
@ -768,9 +834,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
self.handle_dom_load(pipeline_id)
|
self.handle_dom_load(pipeline_id)
|
||||||
}
|
}
|
||||||
// Handle a forward or back request
|
// Handle a forward or back request
|
||||||
FromScriptMsg::Navigate(pipeline_info, direction) => {
|
FromScriptMsg::TraverseHistory(pipeline_id, direction) => {
|
||||||
debug!("constellation got navigation message from script");
|
debug!("constellation got traverse history message from script");
|
||||||
self.handle_navigate_msg(pipeline_info, direction);
|
self.handle_traverse_history_msg(pipeline_id, direction);
|
||||||
}
|
}
|
||||||
// Notification that the new document is ready to become active
|
// Notification that the new document is ready to become active
|
||||||
FromScriptMsg::ActivateDocument(pipeline_id) => {
|
FromScriptMsg::ActivateDocument(pipeline_id) => {
|
||||||
|
@ -1092,7 +1158,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
debug_assert!(PipelineId::fake_root_pipeline_id() == root_pipeline_id);
|
debug_assert!(PipelineId::fake_root_pipeline_id() == root_pipeline_id);
|
||||||
self.new_pipeline(root_pipeline_id, None, Some(window_size), None,
|
self.new_pipeline(root_pipeline_id, 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.push_pending_frame(root_pipeline_id, None);
|
self.push_pending_frame(root_pipeline_id, None);
|
||||||
self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url));
|
self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url));
|
||||||
}
|
}
|
||||||
|
@ -1263,7 +1329,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
if let Some(_) = parent_pipeline_info {
|
if let Some(_) = parent_pipeline_info {
|
||||||
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);
|
.map(|root_frame| root_frame.current.0);
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -1307,7 +1373,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
let parent_info = self.pipelines.get(&source_id).and_then(|source| source.parent_info);
|
let parent_info = self.pipelines.get(&source_id).and_then(|source| source.parent_info);
|
||||||
match parent_info {
|
match parent_info {
|
||||||
Some((parent_pipeline_id, subpage_id, _)) => {
|
Some((parent_pipeline_id, subpage_id, _)) => {
|
||||||
self.handle_load_start_msg(&source_id);
|
self.handle_load_start_msg(source_id);
|
||||||
// Message the constellation to find the script thread for this iframe
|
// Message the constellation to find the script thread for this iframe
|
||||||
// and issue an iframe load through there.
|
// and issue an iframe load through there.
|
||||||
let msg = ConstellationControlMsg::Navigate(parent_pipeline_id, subpage_id, load_data);
|
let msg = ConstellationControlMsg::Navigate(parent_pipeline_id, subpage_id, load_data);
|
||||||
|
@ -1340,7 +1406,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handle_load_start_msg(&source_id);
|
self.handle_load_start_msg(source_id);
|
||||||
// Being here means either there are no pending frames, or none of the pending
|
// Being here means either there are no pending frames, or none of the pending
|
||||||
// changes would be overridden by changing the subframe associated with source_id.
|
// changes would be overridden by changing the subframe associated with source_id.
|
||||||
|
|
||||||
|
@ -1360,24 +1426,20 @@ 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.pipelines.get(pipeline_id).and_then(|pipeline| pipeline.frame) {
|
if let Some(frame_id) = self.get_top_level_frame_for_pipeline(Some(pipeline_id)) {
|
||||||
if let Some(frame) = self.frames.get(&frame_id) {
|
let forward = !self.joint_session_future(frame_id).is_empty();
|
||||||
let forward = !frame.next.is_empty();
|
let back = !self.joint_session_past(frame_id).is_empty();
|
||||||
let back = !frame.prev.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) {
|
||||||
if let Some(frame_id) = self.pipelines.get(pipeline_id).and_then(|pipeline| pipeline.frame) {
|
if let Some(frame_id) = self.get_top_level_frame_for_pipeline(Some(pipeline_id)) {
|
||||||
if let Some(frame) = self.frames.get(&frame_id) {
|
let forward = !self.joint_session_future(frame_id).is_empty();
|
||||||
let forward = frame.next.is_empty();
|
let back = !self.joint_session_past(frame_id).is_empty();
|
||||||
let back = frame.prev.is_empty();
|
let root = self.root_frame_id.is_none() || self.root_frame_id == Some(frame_id);
|
||||||
let root = self.root_frame_id.is_none() || self.root_frame_id == Some(frame_id);
|
self.compositor_proxy.send(ToCompositorMsg::LoadComplete(back, forward, root));
|
||||||
self.compositor_proxy.send(ToCompositorMsg::LoadComplete(back, forward, root));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1397,115 +1459,42 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
self.handle_subframe_loaded(pipeline_id);
|
self.handle_subframe_loaded(pipeline_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_navigate_msg(&mut self,
|
fn handle_traverse_history_msg(&mut self,
|
||||||
pipeline_info: Option<(PipelineId, SubpageId)>,
|
pipeline_id: Option<PipelineId>,
|
||||||
direction: NavigationDirection) {
|
direction: TraversalDirection) {
|
||||||
debug!("received message to navigate {:?}", direction);
|
let frame_id = match self.get_top_level_frame_for_pipeline(pipeline_id) {
|
||||||
|
|
||||||
// Get the frame id associated with the pipeline that sent
|
|
||||||
// the navigate message, or use root frame id by default.
|
|
||||||
let frame_id = pipeline_info
|
|
||||||
.and_then(|info| self.subpage_map.get(&info))
|
|
||||||
.and_then(|pipeline_id| self.pipelines.get(&pipeline_id))
|
|
||||||
.and_then(|pipeline| pipeline.frame)
|
|
||||||
.or(self.root_frame_id);
|
|
||||||
|
|
||||||
// If the frame_id lookup fails, then we are in the middle of tearing down
|
|
||||||
// the root frame, so it is reasonable to silently ignore the navigation.
|
|
||||||
let frame_id = match frame_id {
|
|
||||||
None => return warn!("Navigation after root's closure."),
|
|
||||||
Some(frame_id) => frame_id,
|
Some(frame_id) => frame_id,
|
||||||
|
None => return warn!("Traverse message received after root's closure."),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the currently focused pipeline is the pipeline being replaced
|
let mut traversal_info = HashMap::new();
|
||||||
// (or a child of it). This has to be done here, before the current
|
|
||||||
// frame tree is modified below.
|
|
||||||
let update_focus_pipeline = self.focused_pipeline_in_tree(frame_id);
|
|
||||||
|
|
||||||
// Get the ids for the previous and next pipelines.
|
match direction {
|
||||||
let (prev_pipeline_id, next_pipeline_id) = match self.frames.get_mut(&frame_id) {
|
TraversalDirection::Forward(delta) => {
|
||||||
Some(frame) => {
|
let mut future = self.joint_session_future(frame_id);
|
||||||
let prev = frame.current;
|
for _ in 0..delta {
|
||||||
let next = match direction {
|
match future.pop() {
|
||||||
NavigationDirection::Forward(delta) => {
|
Some((_, frame_id, pipeline_id)) => {
|
||||||
if delta > frame.next.len() && delta > 0 {
|
traversal_info.insert(frame_id, pipeline_id);
|
||||||
return warn!("Invalid navigation delta");
|
},
|
||||||
}
|
None => return warn!("invalid traversal delta"),
|
||||||
let new_next_len = frame.next.len() - (delta - 1);
|
|
||||||
frame.prev.push(frame.current);
|
|
||||||
frame.prev.extend(frame.next.drain(new_next_len..).rev());
|
|
||||||
frame.current = match frame.next.pop() {
|
|
||||||
Some(frame) => frame,
|
|
||||||
None => return warn!("Could not get next frame for forward navigation"),
|
|
||||||
};
|
|
||||||
frame.current
|
|
||||||
}
|
}
|
||||||
NavigationDirection::Back(delta) => {
|
}
|
||||||
if delta > frame.prev.len() && delta > 0 {
|
|
||||||
return warn!("Invalid navigation delta");
|
|
||||||
}
|
|
||||||
let new_prev_len = frame.prev.len() - (delta - 1);
|
|
||||||
frame.next.push(frame.current);
|
|
||||||
frame.next.extend(frame.prev.drain(new_prev_len..).rev());
|
|
||||||
frame.current = match frame.prev.pop() {
|
|
||||||
Some(frame) => frame,
|
|
||||||
None => return warn!("Could not get prev frame for back navigation"),
|
|
||||||
};
|
|
||||||
frame.current
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(prev, next)
|
|
||||||
},
|
},
|
||||||
None => {
|
TraversalDirection::Back(delta) => {
|
||||||
warn!("no frame to navigate from");
|
let mut past = self.joint_session_past(frame_id);
|
||||||
return;
|
for _ in 0..delta {
|
||||||
|
match past.pop() {
|
||||||
|
Some((_, frame_id, pipeline_id)) => {
|
||||||
|
traversal_info.insert(frame_id, pipeline_id);
|
||||||
|
},
|
||||||
|
None => return warn!("invalid traversal delta"),
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
for (frame_id, pipeline_id) in traversal_info {
|
||||||
// If the currently focused pipeline is the one being changed (or a child
|
self.traverse_frame_to_pipeline(frame_id, pipeline_id);
|
||||||
// of the pipeline being changed) then update the focus pipeline to be
|
|
||||||
// the replacement.
|
|
||||||
if update_focus_pipeline {
|
|
||||||
self.focus_pipeline_id = Some(next_pipeline_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Suspend the old pipeline, and resume the new one.
|
|
||||||
if let Some(prev_pipeline) = self.pipelines.get(&prev_pipeline_id) {
|
|
||||||
prev_pipeline.freeze();
|
|
||||||
}
|
|
||||||
if let Some(next_pipeline) = self.pipelines.get(&next_pipeline_id) {
|
|
||||||
next_pipeline.thaw();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set paint permissions correctly for the compositor layers.
|
|
||||||
self.revoke_paint_permission(prev_pipeline_id);
|
|
||||||
self.send_frame_tree_and_grant_paint_permission();
|
|
||||||
|
|
||||||
// Update the owning iframe to point to the new subpage id.
|
|
||||||
// This makes things like contentDocument work correctly.
|
|
||||||
if let Some((parent_pipeline_id, subpage_id)) = pipeline_info {
|
|
||||||
let new_subpage_id = match self.pipelines.get(&next_pipeline_id) {
|
|
||||||
None => return warn!("Pipeline {:?} navigated to after closure.", next_pipeline_id),
|
|
||||||
Some(pipeline) => match pipeline.parent_info {
|
|
||||||
None => return warn!("Pipeline {:?} has no parent info.", next_pipeline_id),
|
|
||||||
Some((_, new_subpage_id, _)) => new_subpage_id,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let msg = ConstellationControlMsg::UpdateSubpageId(parent_pipeline_id,
|
|
||||||
subpage_id,
|
|
||||||
new_subpage_id,
|
|
||||||
next_pipeline_id);
|
|
||||||
let result = match self.pipelines.get(&parent_pipeline_id) {
|
|
||||||
None => return warn!("Pipeline {:?} child navigated after closure.", parent_pipeline_id),
|
|
||||||
Some(pipeline) => pipeline.script_chan.send(msg),
|
|
||||||
};
|
|
||||||
if let Err(e) = result {
|
|
||||||
self.handle_send_error(parent_pipeline_id, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is an iframe, send a mozbrowser location change event.
|
|
||||||
// This is the result of a back/forward navigation.
|
|
||||||
self.trigger_mozbrowserlocationchange(next_pipeline_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1515,7 +1504,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);
|
.map(|root_frame| root_frame.current.0);
|
||||||
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 {
|
||||||
|
@ -1541,7 +1530,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);
|
.map(|root_frame| root_frame.current.0);
|
||||||
|
|
||||||
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);
|
||||||
|
@ -1585,7 +1574,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);
|
.map(|frame| frame.current.0);
|
||||||
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()
|
||||||
|
@ -1655,7 +1644,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)
|
.map(|frame| frame.current.0)
|
||||||
.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) {
|
||||||
|
@ -1753,7 +1742,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);
|
.map(|root_frame| root_frame.current.0);
|
||||||
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 {
|
||||||
|
@ -1765,6 +1754,118 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn traverse_frame_to_pipeline(&mut self, frame_id: FrameId, next_pipeline_id: PipelineId) {
|
||||||
|
// Check if the currently focused pipeline is the pipeline being replaced
|
||||||
|
// (or a child of it). This has to be done here, before the current
|
||||||
|
// frame tree is modified below.
|
||||||
|
let update_focus_pipeline = self.focused_pipeline_in_tree(frame_id);
|
||||||
|
|
||||||
|
let prev_pipeline_id = match self.frames.get_mut(&frame_id) {
|
||||||
|
Some(frame) => {
|
||||||
|
let prev = frame.current.0;
|
||||||
|
// 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.
|
||||||
|
let mut contains_pipeline = false;
|
||||||
|
|
||||||
|
if frame.next.iter().find(|&&(pipeline_id, _)| next_pipeline_id == pipeline_id).is_some() {
|
||||||
|
contains_pipeline = true;
|
||||||
|
frame.prev.push(frame.current);
|
||||||
|
while let Some(entry) = frame.next.pop() {
|
||||||
|
if entry.0 == next_pipeline_id {
|
||||||
|
frame.current = entry;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
frame.prev.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !contains_pipeline &&
|
||||||
|
frame.prev.iter().find(|&&(pipeline_id, _)| next_pipeline_id == pipeline_id).is_some() {
|
||||||
|
contains_pipeline = true;
|
||||||
|
frame.next.push(frame.current);
|
||||||
|
while let Some(entry) = frame.prev.pop() {
|
||||||
|
if entry.0 == next_pipeline_id {
|
||||||
|
frame.current = entry;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
frame.next.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !contains_pipeline {
|
||||||
|
return warn!("Tried to traverse frame {:?} to pipeline {:?} it does not contain.",
|
||||||
|
frame_id, next_pipeline_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
prev
|
||||||
|
},
|
||||||
|
None => return warn!("no frame to traverse"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let pipeline_info = self.pipelines.get(&prev_pipeline_id).and_then(|p| p.parent_info);
|
||||||
|
|
||||||
|
// If the currently focused pipeline is the one being changed (or a child
|
||||||
|
// of the pipeline being changed) then update the focus pipeline to be
|
||||||
|
// the replacement.
|
||||||
|
if update_focus_pipeline {
|
||||||
|
self.focus_pipeline_id = Some(next_pipeline_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suspend the old pipeline, and resume the new one.
|
||||||
|
if let Some(prev_pipeline) = self.pipelines.get(&prev_pipeline_id) {
|
||||||
|
prev_pipeline.freeze();
|
||||||
|
}
|
||||||
|
if let Some(next_pipeline) = self.pipelines.get(&next_pipeline_id) {
|
||||||
|
next_pipeline.thaw();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set paint permissions correctly for the compositor layers.
|
||||||
|
self.revoke_paint_permission(prev_pipeline_id);
|
||||||
|
self.send_frame_tree_and_grant_paint_permission();
|
||||||
|
|
||||||
|
// Update the owning iframe to point to the new subpage id.
|
||||||
|
// This makes things like contentDocument work correctly.
|
||||||
|
if let Some((parent_pipeline_id, subpage_id, _)) = pipeline_info {
|
||||||
|
let new_subpage_id = match self.pipelines.get(&next_pipeline_id) {
|
||||||
|
None => return warn!("Pipeline {:?} traversed to after closure.", next_pipeline_id),
|
||||||
|
Some(pipeline) => match pipeline.parent_info {
|
||||||
|
None => return warn!("Pipeline {:?} has no parent info.", next_pipeline_id),
|
||||||
|
Some((_, new_subpage_id, _)) => new_subpage_id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let msg = ConstellationControlMsg::UpdateSubpageId(parent_pipeline_id,
|
||||||
|
subpage_id,
|
||||||
|
new_subpage_id,
|
||||||
|
next_pipeline_id);
|
||||||
|
let result = match self.pipelines.get(&parent_pipeline_id) {
|
||||||
|
None => return warn!("Pipeline {:?} child traversed after closure.", parent_pipeline_id),
|
||||||
|
Some(pipeline) => pipeline.script_chan.send(msg),
|
||||||
|
};
|
||||||
|
if let Err(e) = result {
|
||||||
|
self.handle_send_error(parent_pipeline_id, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is an iframe, send a mozbrowser location change event.
|
||||||
|
// This is the result of a back/forward traversal.
|
||||||
|
self.trigger_mozbrowserlocationchange(next_pipeline_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_top_level_frame_for_pipeline(&self, pipeline_id: Option<PipelineId>) -> Option<FrameId> {
|
||||||
|
if PREFS.is_mozbrowser_enabled() {
|
||||||
|
pipeline_id.and_then(|id| self.get_mozbrowser_ancestor_info(id))
|
||||||
|
.and_then(|info| self.subpage_map.get(&info))
|
||||||
|
.and_then(|pipeline_id| self.pipelines.get(&pipeline_id))
|
||||||
|
.and_then(|pipeline| pipeline.frame)
|
||||||
|
.or(self.root_frame_id)
|
||||||
|
} else {
|
||||||
|
// If mozbrowser is not enabled, the root frame is the only top-level frame
|
||||||
|
self.root_frame_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn load_url_for_webdriver(&mut self,
|
fn load_url_for_webdriver(&mut self,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
load_data: LoadData,
|
load_data: LoadData,
|
||||||
|
@ -1787,7 +1888,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let evicted_frames = frame_change.old_pipeline_id.and_then(|old_pipeline_id| {
|
let frame_id = frame_change.old_pipeline_id.and_then(|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);
|
||||||
|
@ -1796,14 +1897,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
self.pipelines
|
self.pipelines
|
||||||
.get(&old_pipeline_id)
|
.get(&old_pipeline_id)
|
||||||
.and_then(|pipeline| pipeline.frame)
|
.and_then(|pipeline| pipeline.frame)
|
||||||
.and_then(|frame_id| {
|
.map(|frame_id| {
|
||||||
self.pipelines.get_mut(&frame_change.new_pipeline_id)
|
self.pipelines.get_mut(&frame_change.new_pipeline_id)
|
||||||
.map(|pipeline| pipeline.frame = Some(frame_id));
|
.map(|pipeline| pipeline.frame = Some(frame_id));
|
||||||
self.frames.get_mut(&frame_id).map(|frame| frame.load(frame_change.new_pipeline_id))
|
self.frames.get_mut(&frame_id).map(|frame| frame.load(frame_change.new_pipeline_id));
|
||||||
|
frame_id
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if let None = evicted_frames {
|
if let None = frame_id {
|
||||||
// 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);
|
let frame_id = self.new_frame(frame_change.new_pipeline_id);
|
||||||
|
|
||||||
|
@ -1829,11 +1931,12 @@ 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);
|
||||||
|
|
||||||
// Remove any evicted frames
|
let frame_id = match self.get_top_level_frame_for_pipeline(Some(frame_change.new_pipeline_id)) {
|
||||||
for pipeline_id in evicted_frames.unwrap_or_default() {
|
Some(frame_id) => frame_id,
|
||||||
self.close_pipeline(pipeline_id, ExitPipelineMode::Normal);
|
None => return warn!("Tried to remove forward history after root frame closure."),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
self.clear_joint_session_future(frame_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_activate_document_msg(&mut self, pipeline_id: PipelineId) {
|
fn handle_activate_document_msg(&mut self, pipeline_id: PipelineId) {
|
||||||
|
@ -1897,7 +2000,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;
|
let pipeline_id = frame.current.0;
|
||||||
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,
|
||||||
|
@ -1907,7 +2010,7 @@ 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 &(pipeline_id, _) in frame.prev.iter().chain(&frame.next) {
|
||||||
let pipeline = match self.pipelines.get(&pipeline_id) {
|
let pipeline = match self.pipelines.get(&pipeline_id) {
|
||||||
None => {
|
None => {
|
||||||
warn!("Inactive pipeline {:?} resized after closing.", pipeline_id);
|
warn!("Inactive pipeline {:?} resized after closing.", pipeline_id);
|
||||||
|
@ -1983,7 +2086,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;
|
let pipeline_id = frame.current.0;
|
||||||
|
|
||||||
let pipeline = match self.pipelines.get(&pipeline_id) {
|
let pipeline = match self.pipelines.get(&pipeline_id) {
|
||||||
None => { warn!("Pipeline {:?} screenshot while closing.", pipeline_id); continue; },
|
None => { warn!("Pipeline {:?} screenshot while closing.", pipeline_id); continue; },
|
||||||
|
@ -2007,7 +2110,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) {
|
match self.document_states.get(&frame.current.0) {
|
||||||
Some(&DocumentState::Idle) => {}
|
Some(&DocumentState::Idle) => {}
|
||||||
Some(&DocumentState::Pending) | None => {
|
Some(&DocumentState::Pending) | None => {
|
||||||
return ReadyToSave::DocumentLoading;
|
return ReadyToSave::DocumentLoading;
|
||||||
|
@ -2027,7 +2130,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);
|
let compositor_epoch = pipeline_states.get(&frame.current.0);
|
||||||
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
|
||||||
|
@ -2058,6 +2161,34 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
ReadyToSave::Ready
|
ReadyToSave::Ready
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear_joint_session_future(&mut self, frame_id: FrameId) {
|
||||||
|
let mut evicted_pipelines = vec!();
|
||||||
|
let mut frames_to_clear = vec!(frame_id);
|
||||||
|
while let Some(frame_id) = frames_to_clear.pop() {
|
||||||
|
let frame = match self.frames.get_mut(&frame_id) {
|
||||||
|
Some(frame) => frame,
|
||||||
|
None => {
|
||||||
|
warn!("Removed forward history after frame {:?} closure.", frame_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
evicted_pipelines.extend_from_slice(&frame.remove_forward_entries());
|
||||||
|
for &(pipeline_id, _) in frame.next.iter().chain(frame.prev.iter()).chain(once(&frame.current)) {
|
||||||
|
let pipeline = match self.pipelines.get(&pipeline_id) {
|
||||||
|
Some(pipeline) => pipeline,
|
||||||
|
None => {
|
||||||
|
warn!("Removed forward history after pipeline {:?} closure.", pipeline_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
frames_to_clear.extend_from_slice(&pipeline.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (pipeline_id, _) in evicted_pipelines {
|
||||||
|
self.close_pipeline(pipeline_id, ExitPipelineMode::Normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Close a frame (and all children)
|
// Close a frame (and all children)
|
||||||
fn close_frame(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
|
fn close_frame(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
|
||||||
// Store information about the pipelines to be closed. Then close the
|
// Store information about the pipelines to be closed. Then close the
|
||||||
|
@ -2065,7 +2196,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))
|
.and_then(|frame| self.pipelines.get(&frame.current.0))
|
||||||
.and_then(|pipeline| pipeline.parent_info);
|
.and_then(|pipeline| pipeline.parent_info);
|
||||||
|
|
||||||
let pipelines_to_close = {
|
let pipelines_to_close = {
|
||||||
|
@ -2080,8 +2211,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
pipelines_to_close
|
pipelines_to_close
|
||||||
};
|
};
|
||||||
|
|
||||||
for pipeline_id in &pipelines_to_close {
|
for (pipeline_id, _) in pipelines_to_close {
|
||||||
self.close_pipeline(*pipeline_id, exit_mode);
|
self.close_pipeline(pipeline_id, exit_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.frames.remove(&frame_id).is_none() {
|
if self.frames.remove(&frame_id).is_none() {
|
||||||
|
@ -2175,7 +2306,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).map(|pipeline: &Pipeline| {
|
self.pipelines.get(&frame.current.0).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,
|
||||||
|
@ -2197,7 +2328,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).map(|pipeline| pipeline.revoke_paint_permission());
|
self.pipelines.get(&frame.current.0).map(|pipeline| pipeline.revoke_paint_permission());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2220,7 +2351,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).map(|pipeline| pipeline.grant_paint_permission());
|
self.pipelines.get(&frame.current.0).map(|pipeline| pipeline.grant_paint_permission());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2247,20 +2378,20 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) {
|
fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) {
|
||||||
if !PREFS.is_mozbrowser_enabled() { return; }
|
if !PREFS.is_mozbrowser_enabled() { return; }
|
||||||
|
|
||||||
let event_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| {
|
let url = match self.pipelines.get(&pipeline_id) {
|
||||||
pipeline.parent_info.map(|(containing_pipeline_id, subpage_id, frame_type)| {
|
Some(pipeline) => pipeline.url.to_string(),
|
||||||
(containing_pipeline_id, subpage_id, frame_type, pipeline.url.to_string())
|
None => return warn!("triggered mozbrowser location change on closed pipeline {:?}", pipeline_id),
|
||||||
})
|
};
|
||||||
});
|
|
||||||
|
|
||||||
// If this is a mozbrowser iframe, then send the event with new url
|
// If this is a mozbrowser iframe, then send the event with new url
|
||||||
if let Some((containing_pipeline_id, subpage_id, FrameType::MozBrowserIFrame, url)) = event_info {
|
if let Some((containing_pipeline_id, subpage_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) {
|
||||||
if let Some(parent_pipeline) = self.pipelines.get(&containing_pipeline_id) {
|
if let Some(parent_pipeline) = self.pipelines.get(&containing_pipeline_id) {
|
||||||
if let Some(frame_id) = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.frame) {
|
let pipeline_id = self.subpage_map.get(&(containing_pipeline_id, subpage_id));
|
||||||
if let Some(frame) = self.frames.get(&frame_id) {
|
if let Some(pipeline) = pipeline_id.and_then(|pipeline_id| self.pipelines.get(pipeline_id)) {
|
||||||
let can_go_backward = !frame.prev.is_empty();
|
if let Some(frame_id) = pipeline.frame {
|
||||||
let can_go_forward = !frame.next.is_empty();
|
let can_go_forward = !self.joint_session_future(frame_id).is_empty();
|
||||||
let event = MozBrowserEvent::LocationChange(url, can_go_backward, can_go_forward);
|
let can_go_back = !self.joint_session_past(frame_id).is_empty();
|
||||||
|
let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward);
|
||||||
parent_pipeline.trigger_mozbrowser_event(Some(subpage_id), event);
|
parent_pipeline.trigger_mozbrowser_event(Some(subpage_id), event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2302,7 +2433,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) {
|
if let Some(root_pipeline) = self.pipelines.get(&root_frame.current.0) {
|
||||||
return root_pipeline.trigger_mozbrowser_event(None, event);
|
return root_pipeline.trigger_mozbrowser_event(None, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2325,7 +2456,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 == pipeline_id)
|
.any(|current_frame| current_frame.current.0 == pipeline_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,12 +212,12 @@ impl LoadData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)]
|
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)]
|
||||||
pub enum NavigationDirection {
|
pub enum TraversalDirection {
|
||||||
Forward(usize),
|
Forward(usize),
|
||||||
Back(usize),
|
Back(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)]
|
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, PartialOrd, Ord)]
|
||||||
pub struct FrameId(pub u32);
|
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
|
||||||
|
|
|
@ -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::{UndefinedValue, NullValue};
|
use js::jsval::{UndefinedValue, NullValue};
|
||||||
use msg::constellation_msg::{FrameType, LoadData, NavigationDirection, PipelineId, SubpageId};
|
use msg::constellation_msg::{FrameType, LoadData, TraversalDirection, PipelineId, SubpageId};
|
||||||
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::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
||||||
|
@ -419,15 +419,11 @@ unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn Navigate(iframe: &HTMLIFrameElement, direction: TraversalDirection) -> ErrorResult {
|
||||||
pub fn Navigate(iframe: &HTMLIFrameElement, direction: NavigationDirection) -> ErrorResult {
|
|
||||||
if iframe.Mozbrowser() {
|
if iframe.Mozbrowser() {
|
||||||
if iframe.upcast::<Node>().is_in_doc() {
|
if iframe.upcast::<Node>().is_in_doc() {
|
||||||
let window = window_from_node(iframe);
|
let window = window_from_node(iframe);
|
||||||
|
let msg = ConstellationMsg::TraverseHistory(iframe.pipeline(), direction);
|
||||||
let pipeline_info = Some((window.pipeline(),
|
|
||||||
iframe.subpage_id().unwrap()));
|
|
||||||
let msg = ConstellationMsg::Navigate(pipeline_info, direction);
|
|
||||||
window.constellation_chan().send(msg).unwrap();
|
window.constellation_chan().send(msg).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,12 +496,12 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack
|
||||||
fn GoBack(&self) -> ErrorResult {
|
fn GoBack(&self) -> ErrorResult {
|
||||||
Navigate(self, NavigationDirection::Back(1))
|
Navigate(self, TraversalDirection::Back(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goForward
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goForward
|
||||||
fn GoForward(&self) -> ErrorResult {
|
fn GoForward(&self) -> ErrorResult {
|
||||||
Navigate(self, NavigationDirection::Forward(1))
|
Navigate(self, TraversalDirection::Forward(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/reload
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/reload
|
||||||
|
|
|
@ -51,8 +51,8 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use msg::constellation_msg::{FrameId, FrameType, Image, Key, KeyModifiers, KeyState, LoadData};
|
use msg::constellation_msg::{FrameId, FrameType, Image, Key, KeyModifiers, KeyState, LoadData};
|
||||||
use msg::constellation_msg::{NavigationDirection, PipelineId, ReferrerPolicy};
|
use msg::constellation_msg::{PipelineId, PipelineNamespaceId, ReferrerPolicy};
|
||||||
use msg::constellation_msg::{PipelineNamespaceId, SubpageId, WindowSizeType};
|
use msg::constellation_msg::{SubpageId, TraversalDirection, WindowSizeType};
|
||||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use net_traits::response::HttpsState;
|
use net_traits::response::HttpsState;
|
||||||
|
@ -621,8 +621,8 @@ pub enum ConstellationMsg {
|
||||||
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
||||||
/// Request to load a page.
|
/// Request to load a page.
|
||||||
LoadUrl(PipelineId, LoadData),
|
LoadUrl(PipelineId, LoadData),
|
||||||
/// Request to navigate a frame.
|
/// Request to traverse the joint session history.
|
||||||
Navigate(Option<(PipelineId, SubpageId)>, NavigationDirection),
|
TraverseHistory(Option<PipelineId>, TraversalDirection),
|
||||||
/// Inform the constellation of a window being resized.
|
/// Inform the constellation of a window being resized.
|
||||||
WindowSize(WindowSizeData, WindowSizeType),
|
WindowSize(WindowSizeData, WindowSizeType),
|
||||||
/// Requests that the constellation instruct layout to begin a new tick of the animation.
|
/// Requests that the constellation instruct layout to begin a new tick of the animation.
|
||||||
|
|
|
@ -17,7 +17,7 @@ use euclid::size::Size2D;
|
||||||
use gfx_traits::LayerId;
|
use gfx_traits::LayerId;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
|
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
|
||||||
use msg::constellation_msg::{NavigationDirection, PipelineId, SubpageId};
|
use msg::constellation_msg::{PipelineId, SubpageId, TraversalDirection};
|
||||||
use net_traits::CoreResourceMsg;
|
use net_traits::CoreResourceMsg;
|
||||||
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
||||||
use style_traits::cursor::Cursor;
|
use style_traits::cursor::Cursor;
|
||||||
|
@ -91,8 +91,8 @@ pub enum ScriptMsg {
|
||||||
/// Dispatch a mozbrowser event to a given iframe,
|
/// Dispatch a mozbrowser event to a given iframe,
|
||||||
/// or to the window if no subpage id is provided.
|
/// or to the window if no subpage id is provided.
|
||||||
MozBrowserEvent(PipelineId, Option<SubpageId>, MozBrowserEvent),
|
MozBrowserEvent(PipelineId, Option<SubpageId>, MozBrowserEvent),
|
||||||
/// HTMLIFrameElement Forward or Back navigation.
|
/// HTMLIFrameElement Forward or Back traversal.
|
||||||
Navigate(Option<(PipelineId, SubpageId)>, NavigationDirection),
|
TraverseHistory(Option<PipelineId>, TraversalDirection),
|
||||||
/// Favicon detected
|
/// Favicon detected
|
||||||
NewFavicon(Url),
|
NewFavicon(Url),
|
||||||
/// Status message to be displayed in the chrome, eg. a link URL on mouseover.
|
/// Status message to be displayed in the chrome, eg. a link URL on mouseover.
|
||||||
|
|
|
@ -32,7 +32,7 @@ use image::{DynamicImage, ImageFormat, RgbImage};
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
use keys::keycodes_to_keys;
|
use keys::keycodes_to_keys;
|
||||||
use msg::constellation_msg::{FrameId, LoadData, PipelineId};
|
use msg::constellation_msg::{FrameId, LoadData, PipelineId};
|
||||||
use msg::constellation_msg::{NavigationDirection, PixelFormat};
|
use msg::constellation_msg::{TraversalDirection, PixelFormat};
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
|
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
|
||||||
use rustc_serialize::json::{Json, ToJson};
|
use rustc_serialize::json::{Json, ToJson};
|
||||||
|
@ -440,12 +440,12 @@ impl Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_go_back(&self) -> WebDriverResult<WebDriverResponse> {
|
fn handle_go_back(&self) -> WebDriverResult<WebDriverResponse> {
|
||||||
self.constellation_chan.send(ConstellationMsg::Navigate(None, NavigationDirection::Back(1))).unwrap();
|
self.constellation_chan.send(ConstellationMsg::TraverseHistory(None, TraversalDirection::Back(1))).unwrap();
|
||||||
Ok(WebDriverResponse::Void)
|
Ok(WebDriverResponse::Void)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_go_forward(&self) -> WebDriverResult<WebDriverResponse> {
|
fn handle_go_forward(&self) -> WebDriverResult<WebDriverResponse> {
|
||||||
self.constellation_chan.send(ConstellationMsg::Navigate(None, NavigationDirection::Forward(1))).unwrap();
|
self.constellation_chan.send(ConstellationMsg::TraverseHistory(None, TraversalDirection::Forward(1))).unwrap();
|
||||||
Ok(WebDriverResponse::Void)
|
Ok(WebDriverResponse::Void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue