mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
Implement history state
This commit is contained in:
parent
e4472f7c1f
commit
17bd80a7b1
55 changed files with 316 additions and 359 deletions
|
@ -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,8 +2382,8 @@ 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;
|
||||
|
||||
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) {
|
||||
|
@ -2326,11 +2397,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
} 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;
|
||||
|
||||
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) {
|
||||
|
@ -2344,6 +2418,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
} else {
|
||||
Some(previous_load_data.clone())
|
||||
}
|
||||
},
|
||||
SessionHistoryDiff::PipelineDiff { .. } => Some(previous_load_data.clone()),
|
||||
}
|
||||
};
|
||||
|
||||
let mut entries: Vec<LoadData> = session_history.past.iter().rev()
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,6 +213,13 @@ impl PipelineNamespace {
|
|||
index: BrowsingContextIndex(self.next_index()),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_history_state_id(&mut self) -> HistoryStateId {
|
||||
HistoryStateId {
|
||||
namespace_id: self.id,
|
||||
index: HistoryStateIndex(self.next_index()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_local!(pub static PIPELINE_NAMESPACE: Cell<Option<PipelineNamespace>> = Cell::new(None));
|
||||
|
@ -351,6 +358,35 @@ impl PartialEq<BrowsingContextId> for TopLevelBrowsingContextId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
pub struct HistoryStateIndex(pub NonZeroU32);
|
||||
malloc_size_of_is_0!(HistoryStateIndex);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
pub struct HistoryStateId {
|
||||
pub namespace_id: PipelineNamespaceId,
|
||||
pub index: HistoryStateIndex,
|
||||
}
|
||||
|
||||
impl HistoryStateId {
|
||||
pub fn new() -> HistoryStateId {
|
||||
PIPELINE_NAMESPACE.with(|tls| {
|
||||
let mut namespace = tls.get().expect("No namespace set for this thread!");
|
||||
let next_history_state_id = namespace.next_history_state_id();
|
||||
tls.set(Some(namespace));
|
||||
next_history_state_id
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HistoryStateId {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let PipelineNamespaceId(namespace_id) = self.namespace_id;
|
||||
let HistoryStateIndex(index) = self.index;
|
||||
write!(fmt, "({},{})", namespace_id, index.get())
|
||||
}
|
||||
}
|
||||
|
||||
// We provide ids just for unit testing.
|
||||
pub const TEST_NAMESPACE: PipelineNamespaceId = PipelineNamespaceId(1234);
|
||||
#[allow(unsafe_code)]
|
||||
|
|
|
@ -32,7 +32,7 @@ use hyper::status::StatusCode;
|
|||
use hyper_openssl::OpensslClient;
|
||||
use hyper_serde::Serde;
|
||||
use log;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use msg::constellation_msg::{HistoryStateId, PipelineId};
|
||||
use net_traits::{CookieSource, FetchMetadata, NetworkError, ReferrerPolicy};
|
||||
use net_traits::request::{CacheMode, CredentialsMode, Destination, Origin};
|
||||
use net_traits::request::{RedirectMode, Referrer, Request, RequestMode};
|
||||
|
@ -40,7 +40,7 @@ use net_traits::request::{ResponseTainting, ServiceWorkersMode};
|
|||
use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
|
||||
use resource_thread::AuthCache;
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::error::Error;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::iter::FromIterator;
|
||||
|
@ -73,6 +73,7 @@ pub struct HttpState {
|
|||
pub cookie_jar: RwLock<CookieStorage>,
|
||||
pub http_cache: RwLock<HttpCache>,
|
||||
pub auth_cache: RwLock<AuthCache>,
|
||||
pub history_states: RwLock<HashMap<HistoryStateId, Vec<u8>>>,
|
||||
pub ssl_client: OpensslClient,
|
||||
pub connector: Pool<Connector>,
|
||||
}
|
||||
|
@ -83,6 +84,7 @@ impl HttpState {
|
|||
hsts_list: RwLock::new(HstsList::new()),
|
||||
cookie_jar: RwLock::new(CookieStorage::new(150)),
|
||||
auth_cache: RwLock::new(AuthCache::new()),
|
||||
history_states: RwLock::new(HashMap::new()),
|
||||
http_cache: RwLock::new(HttpCache::new()),
|
||||
ssl_client: ssl_client.clone(),
|
||||
connector: create_http_connector(ssl_client),
|
||||
|
|
|
@ -131,6 +131,7 @@ fn create_http_states(config_dir: Option<&Path>) -> (Arc<HttpState>, Arc<HttpSta
|
|||
auth_cache: RwLock::new(auth_cache),
|
||||
http_cache: RwLock::new(http_cache),
|
||||
hsts_list: RwLock::new(hsts_list),
|
||||
history_states: RwLock::new(HashMap::new()),
|
||||
ssl_client: ssl_client.clone(),
|
||||
connector: create_http_connector(ssl_client),
|
||||
};
|
||||
|
@ -243,6 +244,14 @@ impl ResourceChannelManager {
|
|||
let cookies = cookie_jar.cookies_data_for_url(&url, source).map(Serde).collect();
|
||||
consumer.send(cookies).unwrap();
|
||||
}
|
||||
CoreResourceMsg::GetHistoryState(history_state_id, consumer) => {
|
||||
let history_states = http_state.history_states.read().unwrap();
|
||||
consumer.send(history_states.get(&history_state_id).cloned()).unwrap();
|
||||
}
|
||||
CoreResourceMsg::SetHistoryState(history_state_id, history_state) => {
|
||||
let mut history_states = http_state.history_states.write().unwrap();
|
||||
history_states.insert(history_state_id, history_state);
|
||||
}
|
||||
CoreResourceMsg::Synchronize(sender) => {
|
||||
let _ = sender.send(());
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ use hyper_serde::Serde;
|
|||
use ipc_channel::Error as IpcError;
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use msg::constellation_msg::HistoryStateId;
|
||||
use request::{Request, RequestInit};
|
||||
use response::{HttpsState, Response, ResponseInit};
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -363,6 +364,10 @@ pub enum CoreResourceMsg {
|
|||
GetCookiesForUrl(ServoUrl, IpcSender<Option<String>>, CookieSource),
|
||||
/// Get a cookie by name for a given originating URL
|
||||
GetCookiesDataForUrl(ServoUrl, IpcSender<Vec<Serde<Cookie<'static>>>>, CookieSource),
|
||||
/// Get a history state by a given history state id
|
||||
GetHistoryState(HistoryStateId, IpcSender<Option<Vec<u8>>>),
|
||||
/// Set a history state for a given history state id
|
||||
SetHistoryState(HistoryStateId, Vec<u8>),
|
||||
/// Synchronization message solely for knowing the state of the ResourceChannelManager loop
|
||||
Synchronize(IpcSender<()>),
|
||||
/// Send the network sender in constellation to CoreResourceThread
|
||||
|
|
|
@ -65,7 +65,7 @@ use js::rust::{GCMethods, Handle, Runtime};
|
|||
use js::typedarray::TypedArray;
|
||||
use js::typedarray::TypedArrayElement;
|
||||
use metrics::{InteractiveMetrics, InteractiveWindow};
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TopLevelBrowsingContextId};
|
||||
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::filemanager_thread::RelativePos;
|
||||
use net_traits::image::base::{Image, ImageMetadata};
|
||||
|
@ -356,7 +356,7 @@ unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
|
|||
// These three are interdependent, if you plan to put jsmanaged data
|
||||
// in one of these make sure it is propagated properly to containing structs
|
||||
unsafe_no_jsmanaged_fields!(DocumentActivity, WindowSizeData, WindowSizeType);
|
||||
unsafe_no_jsmanaged_fields!(BrowsingContextId, PipelineId, TopLevelBrowsingContextId);
|
||||
unsafe_no_jsmanaged_fields!(BrowsingContextId, HistoryStateId, PipelineId, TopLevelBrowsingContextId);
|
||||
unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource);
|
||||
unsafe_no_jsmanaged_fields!(TimelineMarkerType);
|
||||
unsafe_no_jsmanaged_fields!(WorkerId);
|
||||
|
|
|
@ -12,15 +12,20 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
|
|||
use dom::bindings::root::{Dom, DomRoot};
|
||||
use dom::bindings::str::{DOMString, USVString};
|
||||
use dom::bindings::structuredclone::StructuredCloneData;
|
||||
use dom::eventtarget::EventTarget;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::popstateevent::PopStateEvent;
|
||||
use dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSContext};
|
||||
use js::jsval::{JSVal, NullValue, UndefinedValue};
|
||||
use js::rust::HandleValue;
|
||||
use msg::constellation_msg::TraversalDirection;
|
||||
use msg::constellation_msg::{HistoryStateId, TraversalDirection};
|
||||
use net_traits::{CoreResourceMsg, IpcSend};
|
||||
use profile_traits::ipc;
|
||||
use profile_traits::ipc::channel;
|
||||
use script_traits::ScriptMsg;
|
||||
use std::cell::Cell;
|
||||
|
||||
enum PushOrReplace {
|
||||
Push,
|
||||
|
@ -33,6 +38,7 @@ pub struct History {
|
|||
reflector_: Reflector,
|
||||
window: Dom<Window>,
|
||||
state: Heap<JSVal>,
|
||||
state_id: Cell<Option<HistoryStateId>>,
|
||||
}
|
||||
|
||||
impl History {
|
||||
|
@ -43,6 +49,7 @@ impl History {
|
|||
reflector_: Reflector::new(),
|
||||
window: Dom::from_ref(&window),
|
||||
state: state,
|
||||
state_id: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,6 +70,38 @@ impl History {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn activate_state(&self, state_id: Option<HistoryStateId>) {
|
||||
self.state_id.set(state_id);
|
||||
let serialized_data = match state_id {
|
||||
Some(state_id) => {
|
||||
let (tx, rx) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
|
||||
let _ = self.window
|
||||
.upcast::<GlobalScope>()
|
||||
.resource_threads()
|
||||
.send(CoreResourceMsg::GetHistoryState(state_id, tx));
|
||||
rx.recv().unwrap()
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
match serialized_data {
|
||||
Some(serialized_data) => {
|
||||
let global_scope = self.window.upcast::<GlobalScope>();
|
||||
rooted!(in(global_scope.get_cx()) let mut state = UndefinedValue());
|
||||
StructuredCloneData::Vector(serialized_data).read(&global_scope, state.handle_mut());
|
||||
self.state.set(state.get());
|
||||
},
|
||||
None => {
|
||||
self.state.set(NullValue());
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
PopStateEvent::dispatch_jsval(self.window.upcast::<EventTarget>(), &*self.window, self.state.handle());
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-history-pushstate
|
||||
// https://html.spec.whatwg.org/multipage/#dom-history-replacestate
|
||||
fn push_or_replace_state(&self,
|
||||
|
@ -70,7 +109,7 @@ impl History {
|
|||
data: HandleValue,
|
||||
_title: DOMString,
|
||||
_url: Option<USVString>,
|
||||
_push_or_replace: PushOrReplace) -> ErrorResult {
|
||||
push_or_replace: PushOrReplace) -> ErrorResult {
|
||||
// Step 1
|
||||
let document = self.window.Document();
|
||||
|
||||
|
@ -85,13 +124,40 @@ impl History {
|
|||
// TODO: Step 4
|
||||
|
||||
// Step 5
|
||||
let serialized_data = StructuredCloneData::write(cx, data)?;
|
||||
let serialized_data = StructuredCloneData::write(cx, data)?.move_to_arraybuffer();
|
||||
|
||||
// TODO: Steps 6-7 Url Handling
|
||||
// https://github.com/servo/servo/issues/19157
|
||||
|
||||
// TODO: Step 8 Push/Replace session history entry
|
||||
// https://github.com/servo/servo/issues/19156
|
||||
// Step 8
|
||||
let state_id = match push_or_replace {
|
||||
PushOrReplace::Push => {
|
||||
let state_id = HistoryStateId::new();
|
||||
self.state_id.set(Some(state_id));
|
||||
let msg = ScriptMsg::PushHistoryState(state_id);
|
||||
let _ = self.window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg);
|
||||
state_id
|
||||
},
|
||||
PushOrReplace::Replace => {
|
||||
let state_id = match self.state_id.get() {
|
||||
Some(state_id) => state_id,
|
||||
None => {
|
||||
let state_id = HistoryStateId::new();
|
||||
self.state_id.set(Some(state_id));
|
||||
state_id
|
||||
},
|
||||
};
|
||||
let msg = ScriptMsg::ReplaceHistoryState(state_id);
|
||||
let _ = self.window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg);
|
||||
state_id
|
||||
},
|
||||
};
|
||||
|
||||
let _ = self.window
|
||||
.upcast::<GlobalScope>()
|
||||
.resource_threads()
|
||||
.send(CoreResourceMsg::SetHistoryState(state_id, serialized_data.clone()));
|
||||
|
||||
|
||||
// TODO: Step 9 Update current entry to represent a GET request
|
||||
// https://github.com/servo/servo/issues/19156
|
||||
|
@ -102,7 +168,7 @@ impl History {
|
|||
// Step 11
|
||||
let global_scope = self.window.upcast::<GlobalScope>();
|
||||
rooted!(in(cx) let mut state = UndefinedValue());
|
||||
serialized_data.read(&global_scope, state.handle_mut());
|
||||
StructuredCloneData::Vector(serialized_data).read(&global_scope, state.handle_mut());
|
||||
|
||||
// Step 12
|
||||
self.state.set(state.get());
|
||||
|
|
|
@ -12,6 +12,7 @@ use dom::bindings::root::DomRoot;
|
|||
use dom::bindings::str::DOMString;
|
||||
use dom::bindings::trace::RootedTraceableBox;
|
||||
use dom::event::Event;
|
||||
use dom::eventtarget::EventTarget;
|
||||
use dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSContext};
|
||||
|
@ -66,6 +67,13 @@ impl PopStateEvent {
|
|||
init.parent.cancelable,
|
||||
init.state.handle()))
|
||||
}
|
||||
|
||||
pub fn dispatch_jsval(target: &EventTarget,
|
||||
window: &Window,
|
||||
state: HandleValue) {
|
||||
let event = PopStateEvent::new(window, atom!("popstate"), true, false, state);
|
||||
event.upcast::<Event>().fire(target);
|
||||
}
|
||||
}
|
||||
|
||||
impl PopStateEventMethods for PopStateEvent {
|
||||
|
|
|
@ -76,7 +76,8 @@ use js::jsapi::{JSTracer, SetWindowProxyClass};
|
|||
use js::jsval::UndefinedValue;
|
||||
use metrics::{MAX_TASK_NS, PaintTimeMetrics};
|
||||
use microtask::{MicrotaskQueue, Microtask};
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId, PipelineNamespace, TopLevelBrowsingContextId};
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId};
|
||||
use msg::constellation_msg::{PipelineNamespace, TopLevelBrowsingContextId};
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg};
|
||||
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::image_cache::{ImageCache, PendingImageResponse};
|
||||
|
@ -1168,6 +1169,7 @@ impl ScriptThread {
|
|||
Navigate(id, ..) => Some(id),
|
||||
PostMessage(id, ..) => Some(id),
|
||||
UpdatePipelineId(_, _, id, _) => Some(id),
|
||||
UpdateHistoryStateId(id, ..) => Some(id),
|
||||
FocusIFrame(id, ..) => Some(id),
|
||||
WebDriverScriptCommand(id, ..) => Some(id),
|
||||
TickAllAnimations(id) => Some(id),
|
||||
|
@ -1294,6 +1296,8 @@ impl ScriptThread {
|
|||
browsing_context_id,
|
||||
new_pipeline_id,
|
||||
reason),
|
||||
ConstellationControlMsg::UpdateHistoryStateId(pipeline_id, history_state_id) =>
|
||||
self.handle_update_history_state_id_msg(pipeline_id, history_state_id),
|
||||
ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id) =>
|
||||
self.handle_focus_iframe_msg(parent_pipeline_id, frame_id),
|
||||
ConstellationControlMsg::WebDriverScriptCommand(pipeline_id, msg) =>
|
||||
|
@ -1672,6 +1676,13 @@ impl ScriptThread {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_update_history_state_id_msg(&self, pipeline_id: PipelineId, history_state_id: Option<HistoryStateId>) {
|
||||
match { self.documents.borrow().find_window(pipeline_id) } {
|
||||
None => return warn!("update history state after pipeline {} closed.", pipeline_id),
|
||||
Some(window) => window.History().r().activate_state(history_state_id),
|
||||
}
|
||||
}
|
||||
|
||||
/// Window was resized, but this script was not active, so don't reflow yet
|
||||
fn handle_resize_inactive_msg(&self, id: PipelineId, new_size: WindowSizeData) {
|
||||
let window = self.documents.borrow().find_window(id)
|
||||
|
|
|
@ -48,8 +48,8 @@ use hyper::method::Method;
|
|||
use ipc_channel::{Error as IpcError};
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
use libc::c_void;
|
||||
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, Key, KeyModifiers, KeyState};
|
||||
use msg::constellation_msg::{PipelineId, PipelineNamespaceId, TraversalDirection};
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, Key, KeyModifiers, KeyState, PipelineId};
|
||||
use msg::constellation_msg::{PipelineNamespaceId, TraversalDirection, TopLevelBrowsingContextId};
|
||||
use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::image::base::Image;
|
||||
use net_traits::image::base::PixelFormat;
|
||||
|
@ -289,6 +289,8 @@ pub enum ConstellationControlMsg {
|
|||
/// Updates the current pipeline ID of a given iframe.
|
||||
/// First PipelineId is for the parent, second is the new PipelineId for the frame.
|
||||
UpdatePipelineId(PipelineId, BrowsingContextId, PipelineId, UpdatePipelineIdReason),
|
||||
/// Updates the history state of a given pipeline.
|
||||
UpdateHistoryStateId(PipelineId, Option<HistoryStateId>),
|
||||
/// Set an iframe to be focused. Used when an element in an iframe gains focus.
|
||||
/// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
|
||||
FocusIFrame(PipelineId, BrowsingContextId),
|
||||
|
@ -343,6 +345,7 @@ impl fmt::Debug for ConstellationControlMsg {
|
|||
Navigate(..) => "Navigate",
|
||||
PostMessage(..) => "PostMessage",
|
||||
UpdatePipelineId(..) => "UpdatePipelineId",
|
||||
UpdateHistoryStateId(..) => "UpdateHistoryStateId",
|
||||
FocusIFrame(..) => "FocusIFrame",
|
||||
WebDriverScriptCommand(..) => "WebDriverScriptCommand",
|
||||
TickAllAnimations(..) => "TickAllAnimations",
|
||||
|
|
|
@ -16,7 +16,7 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
|
|||
use euclid::{Size2D, TypedSize2D};
|
||||
use gfx_traits::Epoch;
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId, TraversalDirection};
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TraversalDirection};
|
||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||
use net_traits::CoreResourceMsg;
|
||||
use net_traits::request::RequestInit;
|
||||
|
@ -104,6 +104,10 @@ pub enum ScriptMsg {
|
|||
PostMessage(BrowsingContextId, Option<ImmutableOrigin>, Vec<u8>),
|
||||
/// HTMLIFrameElement Forward or Back traversal.
|
||||
TraverseHistory(TraversalDirection),
|
||||
/// Inform the constellation of a pushed history state.
|
||||
PushHistoryState(HistoryStateId),
|
||||
/// Inform the constellation of a replaced history state.
|
||||
ReplaceHistoryState(HistoryStateId),
|
||||
/// Gets the length of the joint session history from the constellation.
|
||||
JointSessionHistoryLength(IpcSender<u32>),
|
||||
/// Favicon detected
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
[popstate_event.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
bug: https://github.com/servo/servo/issues/19905
|
||||
[Queue a task to fire popstate event]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
[javascript-url-abort-return-value-undefined.tentative.html]
|
||||
expected: TIMEOUT
|
||||
[Not aborting fetch for javascript:undefined navigation]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -4,99 +4,3 @@
|
|||
[history.length should update when setting location.hash]
|
||||
expected: FAIL
|
||||
|
||||
[history.pushState must exist]
|
||||
expected: FAIL
|
||||
|
||||
[history.pushState must exist within iframes]
|
||||
expected: FAIL
|
||||
|
||||
[initial history.state should be null]
|
||||
expected: FAIL
|
||||
|
||||
[history.length should update when pushing a state]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should update after a state is pushed]
|
||||
expected: FAIL
|
||||
|
||||
[traversing history must traverse pushed states]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must not be allowed to create invalid URLs]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must not be allowed to create cross-origin URLs]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must not be allowed to create cross-origin URLs (about:blank)]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must not be allowed to create cross-origin URLs (data:URI)]
|
||||
expected: FAIL
|
||||
|
||||
[pushState should not actually load the new URL]
|
||||
expected: FAIL
|
||||
|
||||
[security errors are expected to be thrown in the context of the document that owns the history object]
|
||||
expected: FAIL
|
||||
|
||||
[location.hash must be allowed to change (part 1)]
|
||||
expected: FAIL
|
||||
|
||||
[location.hash must be allowed to change (part 2)]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must not alter location.hash when no URL is provided]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must remove all history after the current state]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must be able to set location.hash]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must remove any tasks queued by the history traversal task source]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must be able to set location.pathname]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must be able to set absolute URLs to the same host]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must not be able to use a function as data]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must not be able to use a DOM node as data]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must not be able to use an error object as data]
|
||||
expected: FAIL
|
||||
|
||||
[security errors are expected to be thrown in the context of the document that owns the history object (2)]
|
||||
expected: FAIL
|
||||
|
||||
[pushState must be able to make structured clones of complex objects]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should also reference a clone of the original object]
|
||||
expected: FAIL
|
||||
|
||||
[popstate event should fire when navigation occurs]
|
||||
expected: FAIL
|
||||
|
||||
[popstate event should pass the state data]
|
||||
expected: FAIL
|
||||
|
||||
[state data should cope with circular object references]
|
||||
expected: FAIL
|
||||
|
||||
[state data should be a clone of the original object, not a reference to it]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should also reference a clone of the original object (2)]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should be a separate clone of the object, not a reference to the object passed to the event handler]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -4,96 +4,3 @@
|
|||
[history.length should update when setting location.hash]
|
||||
expected: FAIL
|
||||
|
||||
[history.replaceState must exist]
|
||||
expected: FAIL
|
||||
|
||||
[history.replaceState must exist within iframes]
|
||||
expected: FAIL
|
||||
|
||||
[initial history.state should be null]
|
||||
expected: FAIL
|
||||
|
||||
[history.length should not update when replacing a state with no URL]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should update after a state is pushed]
|
||||
expected: FAIL
|
||||
|
||||
[hash should not change when replaceState is called without a URL]
|
||||
expected: FAIL
|
||||
|
||||
[history.length should not update when replacing a state with a URL]
|
||||
expected: FAIL
|
||||
|
||||
[hash should change when replaceState is called with a URL]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must replace the existing state without altering the forward history]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must not be allowed to create invalid URLs]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must not be allowed to create cross-origin URLs]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must not be allowed to create cross-origin URLs (about:blank)]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must not be allowed to create cross-origin URLs (data:URI)]
|
||||
expected: FAIL
|
||||
|
||||
[security errors are expected to be thrown in the context of the document that owns the history object]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must be able to set location.pathname]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must be able to set absolute URLs to the same host]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must not remove any tasks queued by the history traversal task source]
|
||||
expected: FAIL
|
||||
|
||||
[.go must queue a task with the history traversal task source (run asynchronously)]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must not be able to use a function as data]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must not be able to use a DOM node as data]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must not be able to use an error object as data]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState should not actually load the new URL]
|
||||
expected: FAIL
|
||||
|
||||
[security errors are expected to be thrown in the context of the document that owns the history object (2)]
|
||||
expected: FAIL
|
||||
|
||||
[replaceState must be able to make structured clones of complex objects]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should also reference a clone of the original object]
|
||||
expected: FAIL
|
||||
|
||||
[popstate event should fire when navigation occurs]
|
||||
expected: FAIL
|
||||
|
||||
[popstate event should pass the state data]
|
||||
expected: FAIL
|
||||
|
||||
[state data should cope with circular object references]
|
||||
expected: FAIL
|
||||
|
||||
[state data should be a clone of the original object, not a reference to it]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should also reference a clone of the original object (2)]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should be a separate clone of the object, not a reference to the object passed to the event handler]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[004.html]
|
||||
type: testharness
|
||||
[browser needs to support hashchange events for this testcase]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[005.html]
|
||||
type: testharness
|
||||
[<body onpopstate="..."> should register a listener for the popstate event]
|
||||
expected: FAIL
|
||||
|
||||
[window.onpopstate should register a listener for the popstate event]
|
||||
expected: FAIL
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
[007.html]
|
||||
type: testharness
|
||||
[popstate event should fire before onload fires]
|
||||
expected: FAIL
|
||||
|
||||
[the correct state should be restored when navigating during initial load]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should reflect the navigated state onload]
|
||||
expected: FAIL
|
||||
|
||||
[history.state should reflect the navigated state after onload]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
[008.html]
|
||||
type: testharness
|
||||
[history.pushState URL resolving should be done relative to the document, not the script]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[009.html]
|
||||
type: testharness
|
||||
[HTTP Referer should use the pushed state]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[010.html]
|
||||
type: testharness
|
||||
[HTTP Referer should use the pushed state (before onload)]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[011.html]
|
||||
type: testharness
|
||||
[pushed location should be reflected immediately]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[012.html]
|
||||
type: testharness
|
||||
[replaced location should be reflected immediately]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[combination_history_002.html]
|
||||
type: testharness
|
||||
[After calling of pushState method, check length]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[combination_history_003.html]
|
||||
type: testharness
|
||||
[After calling of pushState and replaceState methods, check length]
|
||||
expected: FAIL
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[combination_history_004.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[After calling of back method, check length]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[combination_history_005.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[After calling of forward method, check length]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[combination_history_006.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[After calling of go method, check length]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[combination_history_007.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[After calling of back and pushState method, check length]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[history_back.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[history back]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
[history_back_1.html]
|
||||
type: testharness
|
||||
[history.back() with session history]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[history_forward.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[history forward]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
[history_forward_1.html]
|
||||
type: testharness
|
||||
[history.forward() with session history]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[history_go_minus.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[history go minus]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
[history_go_no_argument.html]
|
||||
type: testharness
|
||||
[history.go()]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[history_go_plus.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[history go plus]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
[history_go_to_uri.html]
|
||||
type: testharness
|
||||
[history.go() negative tests]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[history_go_undefined.html]
|
||||
type: testharness
|
||||
[history.forward() with session history]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[history_go_zero.html]
|
||||
type: testharness
|
||||
[history.go(0)]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[history_properties_only_fully_active.html]
|
||||
type: testharness
|
||||
[history properties should throw SecurityError when not in a fully active Document]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[history_pushstate_err.html]
|
||||
type: testharness
|
||||
[history pushState SECURITY_ERR]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[history_replacestate_err.html]
|
||||
type: testharness
|
||||
[history replaceState SECURITY_ERR]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_1.html]
|
||||
type: testharness
|
||||
[Multiple history traversals from the same task]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_2.html]
|
||||
type: testharness
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_3.html]
|
||||
type: testharness
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_4.html]
|
||||
type: testharness
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_5.html]
|
||||
type: testharness
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_unload_1.html]
|
||||
type: testharness
|
||||
[Traversing the history, unload event is fired on doucment]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_write_after_load_1.html]
|
||||
type: testharness
|
||||
[Traverse the history after document.write after the load event]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_write_after_load_2.html]
|
||||
type: testharness
|
||||
[Traverse the history back and forward when a history entry is written after the load event]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_write_onload_1.html]
|
||||
type: testharness
|
||||
[Traverse the history when a history entry is written in the load event]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[traverse_the_history_write_onload_2.html]
|
||||
type: testharness
|
||||
[Traverse the history back and forward when a history entry is written in the load event]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue