From 61442cce4b93ef6b88b4ce59bad2358e8ce8bf4e Mon Sep 17 00:00:00 2001 From: Connor Brewster Date: Tue, 12 Jun 2018 22:12:17 +0200 Subject: [PATCH] Track hash changes in session history Notify history changed on pushState and scroll to frag --- components/constellation/constellation.rs | 73 ++++++++++++++++--- components/constellation/session_history.rs | 22 ++++-- components/script/dom/history.rs | 5 +- components/script/dom/window.rs | 25 ++++++- components/script_traits/script_msg.rs | 3 + .../scroll-behavior-smooth.html.ini | 5 +- .../encoding/single-byte-decoder.html.ini | 2 - .../request/request-keepalive-quota.html.ini | 2 - .../hashchange_event.html.ini | 6 -- .../scroll-to-fragid/004.html.ini | 6 -- .../scroll-to-fragid/005.html.ini | 6 -- .../scroll-to-fragid/006.html.ini | 6 -- .../scroll-to-fragid/007.html.ini | 6 -- .../the-history-interface/004.html.ini | 10 --- .../parsing.html.ini | 4 - .../metadata/websockets/binary/001.html.ini | 2 - .../metadata/websockets/binary/002.html.ini | 2 - .../metadata/websockets/binary/004.html.ini | 2 - .../metadata/websockets/binary/005.html.ini | 2 - .../bufferedAmount-arraybuffer.html.ini | 2 - .../bufferedAmount-blob.html.ini | 2 - .../metadata/xhr/sync-no-timeout.any.js.ini | 4 - 22 files changed, 110 insertions(+), 87 deletions(-) delete mode 100644 tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/hashchange_event.html.ini delete mode 100644 tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/004.html.ini delete mode 100644 tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/005.html.ini delete mode 100644 tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/006.html.ini delete mode 100644 tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/007.html.ini delete mode 100644 tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index c2b14985f3ab..ff5bfa1fd0f2 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1063,6 +1063,10 @@ impl Constellation FromScriptMsg::LoadComplete => { self.handle_load_complete_msg(source_top_ctx_id, source_pipeline_id) } + // Handle navigating to a fragment + FromScriptMsg::NavigatedToFragment(new_url, replacement_enabled) => { + self.handle_navigated_to_fragment(source_pipeline_id, new_url, replacement_enabled); + } // Handle a forward or back request FromScriptMsg::TraverseHistory(direction) => { self.handle_traverse_history_msg(source_top_ctx_id, direction); @@ -1853,6 +1857,26 @@ impl Constellation self.handle_subframe_loaded(pipeline_id); } + fn handle_navigated_to_fragment(&mut self, pipeline_id: PipelineId, new_url: ServoUrl, replacement_enabled: bool) { + let (top_level_browsing_context_id, old_url) = match self.pipelines.get_mut(&pipeline_id) { + Some(pipeline) => { + let old_url = replace(&mut pipeline.url, new_url.clone()); + (pipeline.top_level_browsing_context_id, old_url) + } + None => return warn!("Pipeline {} navigated to fragment after closure", pipeline_id), + }; + + if !replacement_enabled { + let diff = SessionHistoryDiff::HashDiff { + pipeline_reloader: NeedsToReload::No(pipeline_id), + new_url, + old_url, + }; + self.get_joint_session_history(top_level_browsing_context_id).push_diff(diff); + self.notify_history_changed(top_level_browsing_context_id); + } + } + fn handle_traverse_history_msg(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId, direction: TraversalDirection) @@ -1874,7 +1898,7 @@ impl Constellation 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, @@ -1883,10 +1907,23 @@ impl Constellation } => match *pipeline_reloader { NeedsToReload::No(pipeline_id) => { pipeline_changes.insert(pipeline_id, (Some(new_history_state_id), new_url.clone())); - } + }, NeedsToReload::Yes(pipeline_id, ..) => { url_to_load.insert(pipeline_id, new_url.clone()); - } + }, + }, + SessionHistoryDiff::HashDiff { + ref pipeline_reloader, + ref new_url, + .. + } => match *pipeline_reloader { + NeedsToReload::No(pipeline_id) => { + let state = pipeline_changes.get(&pipeline_id).and_then(|change| change.0); + pipeline_changes.insert(pipeline_id, (state, new_url.clone())); + }, + NeedsToReload::Yes(pipeline_id, ..) => { + url_to_load.insert(pipeline_id, new_url.clone()); + }, }, } session_history.past.push(diff); @@ -1912,10 +1949,23 @@ impl Constellation } => match *pipeline_reloader { NeedsToReload::No(pipeline_id) => { pipeline_changes.insert(pipeline_id, (old_history_state_id, old_url.clone())); - } + }, NeedsToReload::Yes(pipeline_id, ..) => { url_to_load.insert(pipeline_id, old_url.clone()); - } + }, + }, + SessionHistoryDiff::HashDiff { + ref pipeline_reloader, + ref old_url, + .. + } => match *pipeline_reloader { + NeedsToReload::No(pipeline_id) => { + let state = pipeline_changes.get(&pipeline_id).and_then(|change| change.0); + pipeline_changes.insert(pipeline_id, (state, old_url.clone())); + }, + NeedsToReload::Yes(pipeline_id, ..) => { + url_to_load.insert(pipeline_id, old_url.clone()); + }, }, } session_history.future.push(diff); @@ -2054,7 +2104,6 @@ impl Constellation 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, @@ -2062,7 +2111,8 @@ impl Constellation old_history_state_id: old_state_id, old_url: old_url, }; - session_history.push_diff(diff); + self.get_joint_session_history(top_level_browsing_context_id).push_diff(diff); + self.notify_history_changed(top_level_browsing_context_id); } fn handle_replace_history_state_msg( @@ -2367,7 +2417,7 @@ impl Constellation Some(previous_load_data.clone()) } }, - SessionHistoryDiff::PipelineDiff { .. } => Some(previous_load_data.clone()), + _ => Some(previous_load_data.clone()), } }; @@ -2388,7 +2438,7 @@ impl Constellation Some(previous_load_data.clone()) } }, - SessionHistoryDiff::PipelineDiff { .. } => Some(previous_load_data.clone()), + _ => Some(previous_load_data.clone()), } }; @@ -2491,13 +2541,14 @@ impl Constellation if let Some(pipeline_id) = new_reloader.alive_pipeline_id() { pipelines_to_close.push(pipeline_id); } - } + }, SessionHistoryDiff::PipelineDiff { pipeline_reloader, new_history_state_id, .. } => { if let Some(pipeline_id) = pipeline_reloader.alive_pipeline_id() { let states = states_to_close.entry(pipeline_id).or_insert(Vec::new()); states.push(new_history_state_id); } - } + }, + _ => {}, } } diff --git a/components/constellation/session_history.rs b/components/constellation/session_history.rs index b4de8d0f6d48..adfa7cf347f6 100644 --- a/components/constellation/session_history.rs +++ b/components/constellation/session_history.rs @@ -70,7 +70,7 @@ impl JointSessionHistory { SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, .. } => { *browsing_context_id != context_id }, - SessionHistoryDiff::PipelineDiff { .. } => true, + _ => true, } }); self.future.retain(|diff| { @@ -78,7 +78,7 @@ impl JointSessionHistory { SessionHistoryDiff::BrowsingContextDiff { browsing_context_id, .. } => { *browsing_context_id != context_id }, - SessionHistoryDiff::PipelineDiff { .. } => true, + _ => true, } }); } @@ -174,6 +174,11 @@ pub enum SessionHistoryDiff { /// The new url new_url: ServoUrl, }, + HashDiff { + pipeline_reloader: NeedsToReload, + old_url: ServoUrl, + new_url: ServoUrl, + }, } impl SessionHistoryDiff { @@ -186,7 +191,7 @@ impl SessionHistoryDiff { NeedsToReload::Yes(..) => None, } }, - SessionHistoryDiff::PipelineDiff { .. } => None, + _ => None, } } @@ -199,7 +204,7 @@ impl SessionHistoryDiff { NeedsToReload::Yes(..) => None, } }, - SessionHistoryDiff::PipelineDiff { .. } => None, + _ => None, } } @@ -213,12 +218,17 @@ impl SessionHistoryDiff { if *new_reloader == *replaced_reloader { *new_reloader = reloader.clone(); } - } + }, SessionHistoryDiff::PipelineDiff { ref mut pipeline_reloader, .. } => { if *pipeline_reloader == *replaced_reloader { *pipeline_reloader = reloader.clone(); } - } + }, + SessionHistoryDiff::HashDiff { ref mut pipeline_reloader, .. } => { + if *pipeline_reloader == *replaced_reloader { + *pipeline_reloader = reloader.clone(); + } + }, } } } diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index 369c59b524c5..939cf9a8c20a 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -85,7 +85,10 @@ impl History { // Step 6 let hash_changed = old_url.fragment() != url.fragment(); - // TODO: Step 8 - scroll restoration + // Step 8 + if let Some(fragment) = url.fragment() { + document.check_and_scroll_fragment(fragment); + } // Step 11 let state_changed = state_id != self.state_id.get(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index ea3a92e0f379..a26570edb1cc 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -33,7 +33,10 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt use dom::customelementregistry::CustomElementRegistry; use dom::document::{AnimationFrameCallback, Document}; use dom::element::Element; +use dom::event::Event; +use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; +use dom::hashchangeevent::HashChangeEvent; use dom::history::History; use dom::location::Location; use dom::mediaquerylist::{MediaQueryList, WeakMediaQueryListVec}; @@ -1582,13 +1585,33 @@ impl Window { referrer_policy: Option) { let doc = self.Document(); let referrer_policy = referrer_policy.or(doc.get_referrer_policy()); - // https://html.spec.whatwg.org/multipage/#navigating-across-documents if !force_reload && url.as_url()[..Position::AfterQuery] == doc.url().as_url()[..Position::AfterQuery] { // Step 6 if let Some(fragment) = url.fragment() { + self.send_to_constellation(ScriptMsg::NavigatedToFragment(url.clone(), replace)); doc.check_and_scroll_fragment(fragment); + let this = Trusted::new(self); + let old_url = doc.url().into_string(); + let new_url = url.clone().into_string(); + let task = task!(hashchange_event: move || { + let this = this.root(); + let event = HashChangeEvent::new( + &this, + atom!("hashchange"), + false, + false, + old_url, + new_url); + event.upcast::().fire(this.upcast::()); + }); + // FIXME(nox): Why are errors silenced here? + let _ = self.script_chan.send(CommonScriptMsg::Task( + ScriptThreadEventCategory::DomEvent, + Box::new(self.task_canceller(TaskSourceName::DOMManipulation).wrap_task(task)), + self.pipeline_id() + )); doc.set_url(url.clone()); return } diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 4487cb10d5dc..762300827c84 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -116,6 +116,8 @@ pub enum ScriptMsg { AbortLoadUrl, /// Post a message to the currently active window of a given browsing context. PostMessage(BrowsingContextId, Option, Vec), + /// Inform the constellation that a fragment was navigated to and whether or not it was a replacement navigation. + NavigatedToFragment(ServoUrl, bool), /// HTMLIFrameElement Forward or Back traversal. TraverseHistory(TraversalDirection), /// Inform the constellation of a pushed history state. @@ -184,6 +186,7 @@ impl fmt::Debug for ScriptMsg { LoadUrl(..) => "LoadUrl", AbortLoadUrl => "AbortLoadUrl", PostMessage(..) => "PostMessage", + NavigatedToFragment(..) => "NavigatedToFragment", TraverseHistory(..) => "TraverseHistory", PushHistoryState(..) => "PushHistoryState", ReplaceHistoryState(..) => "ReplaceHistoryState", diff --git a/tests/wpt/metadata/css/cssom-view/scroll-behavior-smooth.html.ini b/tests/wpt/metadata/css/cssom-view/scroll-behavior-smooth.html.ini index 08d8292ecc4b..bcd187f508ce 100644 --- a/tests/wpt/metadata/css/cssom-view/scroll-behavior-smooth.html.ini +++ b/tests/wpt/metadata/css/cssom-view/scroll-behavior-smooth.html.ini @@ -4,8 +4,5 @@ expected: FAIL [Instant scrolling while doing history navigation.] - expected: TIMEOUT - - [Smooth scrolling while doing history navigation.] - expected: NOTRUN + expected: FAIL diff --git a/tests/wpt/metadata/encoding/single-byte-decoder.html.ini b/tests/wpt/metadata/encoding/single-byte-decoder.html.ini index b98c1201f0b9..4957cfd5c0b0 100644 --- a/tests/wpt/metadata/encoding/single-byte-decoder.html.ini +++ b/tests/wpt/metadata/encoding/single-byte-decoder.html.ini @@ -34,5 +34,3 @@ [windows-1254: iso_8859-9:1989 (XMLHttpRequest)] expected: FAIL - -[single-byte-decoder.html?TextDecoder] diff --git a/tests/wpt/metadata/fetch/api/request/request-keepalive-quota.html.ini b/tests/wpt/metadata/fetch/api/request/request-keepalive-quota.html.ini index 2319416bd2ba..c2a729a1e630 100644 --- a/tests/wpt/metadata/fetch/api/request/request-keepalive-quota.html.ini +++ b/tests/wpt/metadata/fetch/api/request/request-keepalive-quota.html.ini @@ -15,8 +15,6 @@ expected: FAIL -[request-keepalive-quota.html?include=slow-1] - [request-keepalive-quota.html?include=slow-2] [A Keep-Alive fetch() should return only its allocated Quota upon promise resolution.] expected: FAIL diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/hashchange_event.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/hashchange_event.html.ini deleted file mode 100644 index 013f79ec2c84..000000000000 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/hashchange_event.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[hashchange_event.html] - type: testharness - expected: TIMEOUT - [Queue a task to fire hashchange event] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/004.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/004.html.ini deleted file mode 100644 index 4b321adce13b..000000000000 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/004.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[004.html] - type: testharness - expected: TIMEOUT - [Fragment Navigation: hashchange event] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/005.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/005.html.ini deleted file mode 100644 index 1d923794e935..000000000000 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/005.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[005.html] - type: testharness - expected: TIMEOUT - [Fragment Navigation: hashchange event] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/006.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/006.html.ini deleted file mode 100644 index 9f43b5e089c9..000000000000 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/006.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[006.html] - type: testharness - expected: TIMEOUT - [Fragment Navigation: hashchange event multiple changes old/newURL] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/007.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/007.html.ini deleted file mode 100644 index 212e307f65ec..000000000000 --- a/tests/wpt/metadata/html/browsers/browsing-the-web/scroll-to-fragid/007.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[007.html] - type: testharness - expected: TIMEOUT - [Fragment Navigation: hashchange event multiple changes old/newURL] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini b/tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini deleted file mode 100644 index cb0147ab4bf9..000000000000 --- a/tests/wpt/metadata/html/browsers/history/the-history-interface/004.html.ini +++ /dev/null @@ -1,10 +0,0 @@ -[004.html] - [browser needs to support hashchange events for this testcase] - expected: FAIL - - [queued .go commands should all be executed when the queue is processed] - expected: FAIL - - [history position should be calculated when executing, not when calling the .go command] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html.ini b/tests/wpt/metadata/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html.ini index 71cbf369791e..a3331003f7bc 100644 --- a/tests/wpt/metadata/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html.ini +++ b/tests/wpt/metadata/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html.ini @@ -98,8 +98,6 @@ expected: TIMEOUT -[parsing.html?81-90] - [parsing.html?91-100] expected: TIMEOUT [: "0; url=foo"] @@ -247,8 +245,6 @@ expected: TIMEOUT -[parsing.html?131-last] - [parsing.html?1-10] expected: TIMEOUT [: "1"] diff --git a/tests/wpt/metadata/websockets/binary/001.html.ini b/tests/wpt/metadata/websockets/binary/001.html.ini index 5bd89b3b338d..e951021f33db 100644 --- a/tests/wpt/metadata/websockets/binary/001.html.ini +++ b/tests/wpt/metadata/websockets/binary/001.html.ini @@ -4,5 +4,3 @@ [WebSockets: Send/Receive blob, blob size less than network array buffer] expected: TIMEOUT - -[001.html] diff --git a/tests/wpt/metadata/websockets/binary/002.html.ini b/tests/wpt/metadata/websockets/binary/002.html.ini index 95f1b8e77c84..e147562b3560 100644 --- a/tests/wpt/metadata/websockets/binary/002.html.ini +++ b/tests/wpt/metadata/websockets/binary/002.html.ini @@ -3,5 +3,3 @@ [WebSockets: Send/Receive blob, blob size greater than network array buffer] expected: TIMEOUT - -[002.html] diff --git a/tests/wpt/metadata/websockets/binary/004.html.ini b/tests/wpt/metadata/websockets/binary/004.html.ini index 1c519088836d..81e00c88a709 100644 --- a/tests/wpt/metadata/websockets/binary/004.html.ini +++ b/tests/wpt/metadata/websockets/binary/004.html.ini @@ -3,5 +3,3 @@ [WebSockets: Send/Receive ArrayBuffer, size greater than network array buffer] expected: TIMEOUT - -[004.html] diff --git a/tests/wpt/metadata/websockets/binary/005.html.ini b/tests/wpt/metadata/websockets/binary/005.html.ini index 12097e48faa1..bf6e162f08da 100644 --- a/tests/wpt/metadata/websockets/binary/005.html.ini +++ b/tests/wpt/metadata/websockets/binary/005.html.ini @@ -4,5 +4,3 @@ [WebSockets: Send/Receive ArrayBuffer, size less than network array buffer] expected: TIMEOUT - -[005.html] diff --git a/tests/wpt/metadata/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html.ini b/tests/wpt/metadata/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html.ini index 03f0d0a344cd..01192f9a402a 100644 --- a/tests/wpt/metadata/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html.ini +++ b/tests/wpt/metadata/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html.ini @@ -4,5 +4,3 @@ [WebSockets: bufferedAmount for ArrayBuffer] expected: TIMEOUT - -[bufferedAmount-arraybuffer.html] diff --git a/tests/wpt/metadata/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html.ini b/tests/wpt/metadata/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html.ini index 8c7df5100a09..06242c11870b 100644 --- a/tests/wpt/metadata/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html.ini +++ b/tests/wpt/metadata/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html.ini @@ -4,5 +4,3 @@ [WebSockets: bufferedAmount for blob] expected: TIMEOUT - -[bufferedAmount-blob.html] diff --git a/tests/wpt/metadata/xhr/sync-no-timeout.any.js.ini b/tests/wpt/metadata/xhr/sync-no-timeout.any.js.ini index 842f7f5f93f5..ecff1270f564 100644 --- a/tests/wpt/metadata/xhr/sync-no-timeout.any.js.ini +++ b/tests/wpt/metadata/xhr/sync-no-timeout.any.js.ini @@ -5,7 +5,3 @@ [sync-no-timeout] expected: FAIL - -[sync-no-timeout.any.worker.html] - -[sync-no-timeout.any.html]