diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2018-04-16 11:21:41 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-16 11:21:41 -0400 |
commit | 11733d3d8a10353338a40da4cea4b4a2763308c4 (patch) | |
tree | d924826763ea61abb920c3d62a65635432877493 /components/script/dom | |
parent | 1c9bbce38c51c5226f407f456f29136b78d60807 (diff) | |
parent | 17bd80a7b17e002e325985dbe3135a318f2fbaca (diff) | |
download | servo-11733d3d8a10353338a40da4cea4b4a2763308c4.tar.gz servo-11733d3d8a10353338a40da4cea4b4a2763308c4.zip |
Auto merge of #20638 - cbrewster:history_state, r=asajeffrey
Implement History State
<!-- Please describe your changes on the following line: -->
This just handles history states in the session history. URL handling and hashchange events still nee to be implemented.
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach build-geckolib` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #19156 (github issue number if applicable).
<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20638)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 4 | ||||
-rw-r--r-- | components/script/dom/history.rs | 78 | ||||
-rw-r--r-- | components/script/dom/popstateevent.rs | 8 |
3 files changed, 82 insertions, 8 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 44369fef756..a12d9f5140a 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -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); diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index 4b296fb236f..b158a9d44fd 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -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()); diff --git a/components/script/dom/popstateevent.rs b/components/script/dom/popstateevent.rs index e483a9a55a5..a10d19e3002 100644 --- a/components/script/dom/popstateevent.rs +++ b/components/script/dom/popstateevent.rs @@ -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 { |