mirror of
https://github.com/servo/servo.git
synced 2025-08-12 00:45:33 +01:00
Implement history state
This commit is contained in:
parent
e4472f7c1f
commit
17bd80a7b1
55 changed files with 316 additions and 359 deletions
|
@ -111,7 +111,7 @@ use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
|
|||
use ipc_channel::router::ROUTER;
|
||||
use layout_traits::LayoutThreadFactory;
|
||||
use log::{Log, Level, LevelFilter, Metadata, Record};
|
||||
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, PipelineId};
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId, HistoryStateId, TopLevelBrowsingContextId};
|
||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
||||
use net_traits::{self, IpcSend, FetchResponseMsg, ResourceThreads};
|
||||
|
@ -1073,6 +1073,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
debug!("constellation got traverse history message from script");
|
||||
self.handle_traverse_history_msg(source_top_ctx_id, direction);
|
||||
}
|
||||
// Handle a push history state request.
|
||||
FromScriptMsg::PushHistoryState(history_state_id) => {
|
||||
debug!("constellation got push history state message from script");
|
||||
self.handle_push_history_state_msg(source_pipeline_id, history_state_id);
|
||||
}
|
||||
FromScriptMsg::ReplaceHistoryState(history_state_id) => {
|
||||
debug!("constellation got replace history state message from script");
|
||||
self.handle_replace_history_state_msg(source_pipeline_id, history_state_id);
|
||||
}
|
||||
// Handle a joint session history length request.
|
||||
FromScriptMsg::JointSessionHistoryLength(sender) => {
|
||||
debug!("constellation got joint session history length message from script");
|
||||
|
@ -1929,6 +1938,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
direction: TraversalDirection)
|
||||
{
|
||||
let mut browsing_context_changes = HashMap::<BrowsingContextId, NeedsToReload>::new();
|
||||
let mut pipeline_changes = HashMap::<PipelineId, Option<HistoryStateId>>::new();
|
||||
{
|
||||
let session_history = self.joint_session_histories
|
||||
.entry(top_level_browsing_context_id).or_insert(JointSessionHistory::new());
|
||||
|
@ -1945,7 +1955,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
match diff {
|
||||
SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, ref new_reloader, .. } => {
|
||||
browsing_context_changes.insert(browsing_context_id, new_reloader.clone());
|
||||
}
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { ref pipeline_reloader, new_history_state_id, .. } => {
|
||||
// TODO(cbrewster): Handle the case where the pipeline needs to be reloaded.
|
||||
// We should use the history state URL to change the URL that is reloaded.
|
||||
if let NeedsToReload::No(pipeline_id) = *pipeline_reloader {
|
||||
pipeline_changes.insert(pipeline_id, Some(new_history_state_id));
|
||||
}
|
||||
},
|
||||
}
|
||||
session_history.past.push(diff);
|
||||
}
|
||||
|
@ -1961,7 +1978,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
match diff {
|
||||
SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, ref old_reloader, .. } => {
|
||||
browsing_context_changes.insert(browsing_context_id, old_reloader.clone());
|
||||
}
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { ref pipeline_reloader, old_history_state_id, .. } => {
|
||||
// TODO(cbrewster): Handle the case where the pipeline needs to be reloaded.
|
||||
// We should use the history state URL to change the URL that is reloaded.
|
||||
if let NeedsToReload::No(pipeline_id) = *pipeline_reloader {
|
||||
pipeline_changes.insert(pipeline_id, old_history_state_id);
|
||||
}
|
||||
},
|
||||
}
|
||||
session_history.future.push(diff);
|
||||
}
|
||||
|
@ -1973,6 +1997,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
self.update_browsing_context(browsing_context_id, pipeline_id);
|
||||
}
|
||||
|
||||
for (pipeline_id, history_state_id) in pipeline_changes.drain() {
|
||||
self.update_pipeline(pipeline_id, history_state_id);
|
||||
}
|
||||
|
||||
self.notify_history_changed(top_level_browsing_context_id);
|
||||
|
||||
self.trim_history(top_level_browsing_context_id);
|
||||
|
@ -2048,6 +2076,20 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
}
|
||||
|
||||
fn update_pipeline(&mut self, pipeline_id: PipelineId, history_state_id: Option<HistoryStateId>) {
|
||||
let result = match self.pipelines.get_mut(&pipeline_id) {
|
||||
None => return warn!("Pipeline {} history state updated after closure", pipeline_id),
|
||||
Some(pipeline) => {
|
||||
let msg = ConstellationControlMsg::UpdateHistoryStateId(pipeline_id, history_state_id);
|
||||
pipeline.history_state_id = history_state_id;
|
||||
pipeline.event_loop.send(msg)
|
||||
},
|
||||
};
|
||||
if let Err(e) = result {
|
||||
self.handle_send_error(pipeline_id, e);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_joint_session_history_length(&self,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
sender: IpcSender<u32>)
|
||||
|
@ -2058,6 +2100,35 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
let _ = sender.send(length as u32);
|
||||
}
|
||||
|
||||
fn handle_push_history_state_msg(&mut self, pipeline_id: PipelineId, history_state_id: HistoryStateId) {
|
||||
let (top_level_browsing_context_id, old_state_id) = match self.pipelines.get_mut(&pipeline_id) {
|
||||
Some(pipeline) => {
|
||||
let old_history_state_id = pipeline.history_state_id;
|
||||
pipeline.history_state_id = Some(history_state_id);
|
||||
pipeline.history_states.insert(history_state_id);
|
||||
(pipeline.top_level_browsing_context_id, old_history_state_id)
|
||||
}
|
||||
None => return warn!("Push history state {} for closed pipeline {}", history_state_id, pipeline_id),
|
||||
};
|
||||
|
||||
let session_history = self.get_joint_session_history(top_level_browsing_context_id);
|
||||
let diff = SessionHistoryDiff::PipelineDiff {
|
||||
pipeline_reloader: NeedsToReload::No(pipeline_id),
|
||||
new_history_state_id: history_state_id,
|
||||
old_history_state_id: old_state_id,
|
||||
};
|
||||
session_history.push_diff(diff);
|
||||
}
|
||||
|
||||
fn handle_replace_history_state_msg(&mut self, pipeline_id: PipelineId, history_state_id: HistoryStateId) {
|
||||
match self.pipelines.get_mut(&pipeline_id) {
|
||||
Some(pipeline) => {
|
||||
pipeline.history_state_id = Some(history_state_id);
|
||||
}
|
||||
None => return warn!("Replace history state {} for closed pipeline {}", history_state_id, pipeline_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_key_msg(&mut self, ch: Option<char>, key: Key, state: KeyState, mods: KeyModifiers) {
|
||||
// Send to the explicitly focused pipeline. If it doesn't exist, fall back to sending to
|
||||
// the compositor.
|
||||
|
@ -2311,38 +2382,44 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
// If LoadData was ignored, use the LoadData of the previous SessionHistoryEntry, which
|
||||
// is the LoadData of the parent browsing context.
|
||||
let resolve_load_data_future = |previous_load_data: &mut LoadData, diff: &SessionHistoryDiff| {
|
||||
let SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, ref new_reloader, .. } = *diff;
|
||||
|
||||
if browsing_context_id == top_level_browsing_context_id {
|
||||
let load_data = match *new_reloader {
|
||||
NeedsToReload::No(pipeline_id) => match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => pipeline.load_data.clone(),
|
||||
None => previous_load_data.clone(),
|
||||
},
|
||||
NeedsToReload::Yes(_, ref load_data) => load_data.clone(),
|
||||
};
|
||||
*previous_load_data = load_data.clone();
|
||||
Some(load_data)
|
||||
} else {
|
||||
Some(previous_load_data.clone())
|
||||
match *diff {
|
||||
SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, ref new_reloader, .. } => {
|
||||
if browsing_context_id == top_level_browsing_context_id {
|
||||
let load_data = match *new_reloader {
|
||||
NeedsToReload::No(pipeline_id) => match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => pipeline.load_data.clone(),
|
||||
None => previous_load_data.clone(),
|
||||
},
|
||||
NeedsToReload::Yes(_, ref load_data) => load_data.clone(),
|
||||
};
|
||||
*previous_load_data = load_data.clone();
|
||||
Some(load_data)
|
||||
} else {
|
||||
Some(previous_load_data.clone())
|
||||
}
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { .. } => Some(previous_load_data.clone()),
|
||||
}
|
||||
};
|
||||
|
||||
let resolve_load_data_past = |previous_load_data: &mut LoadData, diff: &SessionHistoryDiff| {
|
||||
let SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, ref old_reloader, .. } = *diff;
|
||||
|
||||
if browsing_context_id == top_level_browsing_context_id {
|
||||
let load_data = match *old_reloader {
|
||||
NeedsToReload::No(pipeline_id) => match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => pipeline.load_data.clone(),
|
||||
None => previous_load_data.clone(),
|
||||
},
|
||||
NeedsToReload::Yes(_, ref load_data) => load_data.clone(),
|
||||
};
|
||||
*previous_load_data = load_data.clone();
|
||||
Some(load_data)
|
||||
} else {
|
||||
Some(previous_load_data.clone())
|
||||
match *diff {
|
||||
SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, ref old_reloader, .. } => {
|
||||
if browsing_context_id == top_level_browsing_context_id {
|
||||
let load_data = match *old_reloader {
|
||||
NeedsToReload::No(pipeline_id) => match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => pipeline.load_data.clone(),
|
||||
None => previous_load_data.clone(),
|
||||
},
|
||||
NeedsToReload::Yes(_, ref load_data) => load_data.clone(),
|
||||
};
|
||||
*previous_load_data = load_data.clone();
|
||||
Some(load_data)
|
||||
} else {
|
||||
Some(previous_load_data.clone())
|
||||
}
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { .. } => Some(previous_load_data.clone()),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2433,7 +2510,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
};
|
||||
|
||||
session_history.push_diff(diff).into_iter()
|
||||
.map(|SessionHistoryDiff::BrowsingContextDiff { new_reloader, .. }| new_reloader)
|
||||
.filter_map(|diff| match diff {
|
||||
SessionHistoryDiff::BrowsingContextDiff { new_reloader, .. } => Some(new_reloader),
|
||||
SessionHistoryDiff::PipelineDiff { .. } => None,
|
||||
})
|
||||
.filter_map(|pipeline_id| pipeline_id.alive_pipeline_id())
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
|
|
@ -16,7 +16,8 @@ use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
|||
use ipc_channel::router::ROUTER;
|
||||
use layout_traits::LayoutThreadFactory;
|
||||
use metrics::PaintTimeMetrics;
|
||||
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, PipelineId, PipelineNamespaceId};
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespaceId};
|
||||
use msg::constellation_msg::TopLevelBrowsingContextId;
|
||||
use net::image_cache::ImageCacheImpl;
|
||||
use net_traits::{IpcSend, ResourceThreads};
|
||||
use net_traits::image_cache::ImageCache;
|
||||
|
@ -30,7 +31,7 @@ use script_traits::{ScriptThreadFactory, TimerSchedulerMsg, WindowSizeData};
|
|||
use servo_config::opts::{self, Opts};
|
||||
use servo_config::prefs::{PREFS, Pref};
|
||||
use servo_url::ServoUrl;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
#[cfg(not(windows))]
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
|
@ -92,6 +93,12 @@ pub struct Pipeline {
|
|||
|
||||
/// The Load Data used to create this pipeline.
|
||||
pub load_data: LoadData,
|
||||
|
||||
/// The active history state for this pipeline.
|
||||
pub history_state_id: Option<HistoryStateId>,
|
||||
|
||||
/// The history states owned by this pipeline.
|
||||
pub history_states: HashSet<HistoryStateId>,
|
||||
}
|
||||
|
||||
/// Initial setup data needed to construct a pipeline.
|
||||
|
@ -157,7 +164,6 @@ pub struct InitialPipelineState {
|
|||
/// Information about the page to load.
|
||||
pub load_data: LoadData,
|
||||
|
||||
|
||||
/// The ID of the pipeline namespace for this script thread.
|
||||
pub pipeline_namespace_id: PipelineNamespaceId,
|
||||
|
||||
|
@ -333,6 +339,8 @@ impl Pipeline {
|
|||
visible: visible,
|
||||
is_private: is_private,
|
||||
load_data: load_data,
|
||||
history_state_id: None,
|
||||
history_states: HashSet::new(),
|
||||
};
|
||||
|
||||
pipeline.notify_visibility();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TopLevelBrowsingContextId};
|
||||
use script_traits::LoadData;
|
||||
use std::{fmt, mem};
|
||||
use std::cmp::PartialEq;
|
||||
|
@ -44,11 +44,21 @@ impl JointSessionHistory {
|
|||
}
|
||||
|
||||
pub fn remove_entries_for_browsing_context(&mut self, context_id: BrowsingContextId) {
|
||||
self.past.retain(|&SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, .. }| {
|
||||
browsing_context_id != context_id
|
||||
self.past.retain(|diff| {
|
||||
match diff {
|
||||
SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, .. } => {
|
||||
*browsing_context_id != context_id
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { .. } => true,
|
||||
}
|
||||
});
|
||||
self.future.retain(|&SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, .. }| {
|
||||
browsing_context_id != context_id
|
||||
self.future.retain(|diff| {
|
||||
match diff {
|
||||
SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, .. } => {
|
||||
*browsing_context_id != context_id
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { .. } => true,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +140,15 @@ pub enum SessionHistoryDiff {
|
|||
/// The next pipeline (used when traversing into the future)
|
||||
new_reloader: NeedsToReload,
|
||||
},
|
||||
/// Represents a diff where the active state of a pipeline changed.
|
||||
PipelineDiff {
|
||||
/// The pipeline whose history state changed.
|
||||
pipeline_reloader: NeedsToReload,
|
||||
/// The old history state id.
|
||||
old_history_state_id: Option<HistoryStateId>,
|
||||
/// The new history state id.
|
||||
new_history_state_id: HistoryStateId,
|
||||
},
|
||||
}
|
||||
|
||||
impl SessionHistoryDiff {
|
||||
|
@ -141,7 +160,8 @@ impl SessionHistoryDiff {
|
|||
NeedsToReload::No(pipeline_id) => Some(pipeline_id),
|
||||
NeedsToReload::Yes(..) => None,
|
||||
}
|
||||
}
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +173,8 @@ impl SessionHistoryDiff {
|
|||
NeedsToReload::No(pipeline_id) => Some(pipeline_id),
|
||||
NeedsToReload::Yes(..) => None,
|
||||
}
|
||||
}
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,6 +189,11 @@ impl SessionHistoryDiff {
|
|||
*new_reloader = reloader.clone();
|
||||
}
|
||||
}
|
||||
SessionHistoryDiff::PipelineDiff { ref mut pipeline_reloader, .. } => {
|
||||
if *pipeline_reloader == *replaced_reloader {
|
||||
*pipeline_reloader = reloader.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue