Skip to content
Permalink
Browse files

Implement history state

  • Loading branch information
cbrewster committed Apr 16, 2018
1 parent e4472f7 commit 17bd80a7b17e002e325985dbe3135a318f2fbaca
Showing with 316 additions and 359 deletions.
  1. +1 −0 components/atoms/static_atoms.txt
  2. +112 −32 components/constellation/constellation.rs
  3. +11 −3 components/constellation/pipeline.rs
  4. +33 −7 components/constellation/session_history.rs
  5. +36 −0 components/msg/constellation_msg.rs
  6. +4 −2 components/net/http_loader.rs
  7. +9 −0 components/net/resource_thread.rs
  8. +5 −0 components/net_traits/lib.rs
  9. +2 −2 components/script/dom/bindings/trace.rs
  10. +72 −6 components/script/dom/history.rs
  11. +8 −0 components/script/dom/popstateevent.rs
  12. +12 −1 components/script/script_thread.rs
  13. +5 −2 components/script_traits/lib.rs
  14. +5 −1 components/script_traits/script_msg.rs
  15. +0 −7 tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/popstate_event.html.ini
  16. +1 −2 ...oss-documents/javascript-url-abort/javascript-url-abort-return-value-undefined.tentative.html.ini
  17. +0 −96 tests/wpt/metadata/html/browsers/history/the-history-interface/001.html.ini
  18. +0 −93 tests/wpt/metadata/html/browsers/history/the-history-interface/002.html.ini
  19. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini
  20. +0 −8 tests/wpt/metadata/html/browsers/history/the-history-interface/005.html.ini
  21. +0 −14 tests/wpt/metadata/html/browsers/history/the-history-interface/007.html.ini
  22. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/008.html.ini
  23. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/009.html.ini
  24. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/010.html.ini
  25. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/011.html.ini
  26. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/012.html.ini
  27. +0 −5 tests/wpt/metadata/html/browsers/history/the-history-interface/combination_history_002.html.ini
  28. +0 −5 tests/wpt/metadata/html/browsers/history/the-history-interface/combination_history_003.html.ini
  29. +0 −6 tests/wpt/metadata/html/browsers/history/the-history-interface/combination_history_004.html.ini
  30. +0 −6 tests/wpt/metadata/html/browsers/history/the-history-interface/combination_history_005.html.ini
  31. +0 −6 tests/wpt/metadata/html/browsers/history/the-history-interface/combination_history_006.html.ini
  32. +0 −6 tests/wpt/metadata/html/browsers/history/the-history-interface/combination_history_007.html.ini
  33. +0 −6 tests/wpt/metadata/html/browsers/history/the-history-interface/history_back.html.ini
  34. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/history_back_1.html.ini
  35. +0 −6 tests/wpt/metadata/html/browsers/history/the-history-interface/history_forward.html.ini
  36. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/history_forward_1.html.ini
  37. +0 −6 tests/wpt/metadata/html/browsers/history/the-history-interface/history_go_minus.html.ini
  38. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/history_go_no_argument.html.ini
  39. +0 −6 tests/wpt/metadata/html/browsers/history/the-history-interface/history_go_plus.html.ini
  40. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/history_go_to_uri.html.ini
  41. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/history_go_undefined.html.ini
  42. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/history_go_zero.html.ini
  43. +0 −1 ...etadata/html/browsers/history/the-history-interface/history_properties_only_fully_active.html.ini
  44. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/history_pushstate_err.html.ini
  45. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/history_replacestate_err.html.ini
  46. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_1.html.ini
  47. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_2.html.ini
  48. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_3.html.ini
  49. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_4.html.ini
  50. +0 −1 tests/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_5.html.ini
  51. +0 −1 ...s/wpt/metadata/html/browsers/history/the-history-interface/traverse_the_history_unload_1.html.ini
  52. +0 −1 ...data/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_1.html.ini
  53. +0 −1 ...data/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_2.html.ini
  54. +0 −1 ...metadata/html/browsers/history/the-history-interface/traverse_the_history_write_onload_1.html.ini
  55. +0 −1 ...metadata/html/browsers/history/the-history-interface/traverse_the_history_write_onload_2.html.ini
@@ -52,6 +52,7 @@ password
pause
play
playing
popstate
print
progress
radio
@@ -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();
}
}
}
}
}

0 comments on commit 17bd80a

Please sign in to comment.
You can’t perform that action at this time.