aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/atoms/static_atoms.txt2
-rw-r--r--components/constellation/constellation.rs27
-rw-r--r--components/script/dom/document.rs170
-rw-r--r--components/script/dom/event.rs53
-rw-r--r--components/script/dom/eventtarget.rs34
-rw-r--r--components/script/dom/webidls/Document.webidl2
-rw-r--r--components/script/dom/webidls/Window.webidl2
-rw-r--r--components/script/dom/window.rs23
-rw-r--r--components/script/script_thread.rs10
-rw-r--r--components/script/timers.rs2
-rw-r--r--components/script_traits/lib.rs3
-rw-r--r--components/script_traits/script_msg.rs2
-rw-r--r--tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini3
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/001.html.ini6
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-main-frame-navigation.sub.html.ini2
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-sub-frame-navigation.sub.html.ini6
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-main-frame-navigation.sub.html.ini2
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-sub-frame-navigation.sub.html.ini6
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini3
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/child_navigates_parent_location.html.ini6
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/001.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/002.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/003.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/004.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/005.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/__dir__.ini1
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-history-back.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-navigation-of-parent.html.ini6
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/navigation-within-beforeunload.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/unload/003.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/unload/006.html.ini5
-rw-r--r--tests/wpt/metadata/html/browsers/history/the-location-interface/assign_after_load.html.ini4
-rw-r--r--tests/wpt/metadata/html/browsers/history/the-location-interface/assign_before_load.html.ini6
-rw-r--r--tests/wpt/metadata/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html.ini16
-rw-r--r--tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini3
-rw-r--r--tests/wpt/metadata/html/dom/interfaces.https.html.ini12
-rw-r--r--tests/wpt/metadata/html/semantics/scripting-1/the-script-element/execution-timing/079.html.ini5
37 files changed, 341 insertions, 113 deletions
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt
index ba159bafdfa..8b168ae2fd5 100644
--- a/components/atoms/static_atoms.txt
+++ b/components/atoms/static_atoms.txt
@@ -48,6 +48,7 @@ none
number
onchange
open
+pagehide
pageshow
password
pause
@@ -77,6 +78,7 @@ time
timeupdate
toggle
transitionend
+unload
url
waiting
webglcontextcreationerror
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index f70b9b2834f..3237ce8d033 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -1033,6 +1033,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::PipelineExited => {
self.handle_pipeline_exited(source_pipeline_id);
}
+ FromScriptMsg::DiscardDocument => {
+ self.handle_discard_document(source_top_ctx_id, source_pipeline_id);
+ }
FromScriptMsg::InitiateNavigateRequest(req_init, cancel_chan) => {
debug!("constellation got initiate navigate request message");
self.handle_navigate_request(source_pipeline_id, req_init, cancel_chan);
@@ -2544,6 +2547,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.notify_history_changed(change.top_level_browsing_context_id);
},
Some(old_pipeline_id) => {
+ // https://html.spec.whatwg.org/multipage/#unload-a-document
+ self.unload_document(old_pipeline_id);
// Deactivate the old pipeline, and activate the new one.
let (pipelines_to_close, states_to_close) = if let Some(replace_reloader) = change.replace {
let session_history = self.joint_session_histories
@@ -2994,6 +2999,28 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("Closed browsing context children {}.", browsing_context_id);
}
+ // Discard the pipeline for a given document, udpdate the joint session history.
+ fn handle_discard_document(&mut self,
+ top_level_browsing_context_id: TopLevelBrowsingContextId,
+ pipeline_id: PipelineId) {
+ let load_data = match self.pipelines.get(&pipeline_id) {
+ Some(pipeline) => pipeline.load_data.clone(),
+ None => return
+ };
+ self.joint_session_histories
+ .entry(top_level_browsing_context_id).or_insert(JointSessionHistory::new())
+ .replace_reloader(NeedsToReload::No(pipeline_id), NeedsToReload::Yes(pipeline_id, load_data));
+ self.close_pipeline(pipeline_id, DiscardBrowsingContext::No, ExitPipelineMode::Normal);
+ }
+
+ // Send a message to script requesting the document associated with this pipeline runs the 'unload' algorithm.
+ fn unload_document(&self, pipeline_id: PipelineId) {
+ if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
+ let msg = ConstellationControlMsg::UnloadDocument(pipeline_id);
+ let _ = pipeline.event_loop.send(msg);
+ }
+ }
+
// Close all pipelines at and beneath a given browsing context
fn close_pipeline(&mut self, pipeline_id: PipelineId, dbc: DiscardBrowsingContext, exit_mode: ExitPipelineMode) {
debug!("Closing pipeline {:?}.", pipeline_id);
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 5c9cd57b128..af58c8e53b7 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -63,7 +63,8 @@ use dom::keyboardevent::KeyboardEvent;
use dom::location::Location;
use dom::messageevent::MessageEvent;
use dom::mouseevent::MouseEvent;
-use dom::node::{self, CloneChildrenFlag, Node, NodeDamage, window_from_node, NodeFlags, LayoutNodeHelpers};
+use dom::node::{self, CloneChildrenFlag, document_from_node, window_from_node};
+use dom::node::{Node, NodeDamage, NodeFlags, LayoutNodeHelpers};
use dom::node::VecPreOrderInsertionHelper;
use dom::nodeiterator::NodeIterator;
use dom::nodelist::NodeList;
@@ -348,6 +349,8 @@ pub struct Document {
last_click_info: DomRefCell<Option<(Instant, Point2D<f32>)>>,
/// <https://html.spec.whatwg.org/multipage/#ignore-destructive-writes-counter>
ignore_destructive_writes_counter: Cell<u32>,
+ /// <https://html.spec.whatwg.org/multipage/#ignore-opens-during-unload-counter>
+ ignore_opens_during_unload_counter: Cell<u32>,
/// The number of spurious `requestAnimationFrame()` requests we've received.
///
/// A rAF request is considered spurious if nothing was actually reflowed.
@@ -375,6 +378,10 @@ pub struct Document {
throw_on_dynamic_markup_insertion_counter: Cell<u64>,
/// https://html.spec.whatwg.org/multipage/#page-showing
page_showing: Cell<bool>,
+ /// Whether the document is salvageable.
+ salvageable: Cell<bool>,
+ /// Whether the unload event has already been fired.
+ fired_unload: Cell<bool>,
}
#[derive(JSTraceable, MallocSizeOf)]
@@ -483,6 +490,39 @@ impl Document {
self.dirty_all_nodes();
self.window().reflow(ReflowGoal::Full, ReflowReason::CachedPageNeededReflow);
self.window().resume();
+ // html.spec.whatwg.org/multipage/#history-traversal
+ // Step 4.6
+ if self.ready_state.get() == DocumentReadyState::Complete {
+ let document = Trusted::new(self);
+ self.window.dom_manipulation_task_source().queue(
+ task!(fire_pageshow_event: move || {
+ let document = document.root();
+ let window = document.window();
+ // Step 4.6.1
+ if document.page_showing.get() {
+ return;
+ }
+ // Step 4.6.2
+ document.page_showing.set(true);
+ // Step 4.6.4
+ let event = PageTransitionEvent::new(
+ window,
+ atom!("pageshow"),
+ false, // bubbles
+ false, // cancelable
+ true, // persisted
+ );
+ let event = event.upcast::<Event>();
+ event.set_trusted(true);
+ // FIXME(nox): Why are errors silenced here?
+ let _ = window.upcast::<EventTarget>().dispatch_event_with_target(
+ document.upcast(),
+ &event,
+ );
+ }),
+ self.window.upcast(),
+ ).unwrap();
+ }
} else {
self.window().suspend();
}
@@ -1593,6 +1633,113 @@ impl Document {
ScriptThread::mark_document_with_no_blocked_loads(self);
}
+ // https://html.spec.whatwg.org/multipage/#prompt-to-unload-a-document
+ pub fn prompt_to_unload(&self, recursive_flag: bool) -> bool {
+ // TODO: Step 1, increase the event loop's termination nesting level by 1.
+ // Step 2
+ self.incr_ignore_opens_during_unload_counter();
+ //Step 3-5.
+ let document = Trusted::new(self);
+ let beforeunload_event = BeforeUnloadEvent::new(&self.window,
+ atom!("beforeunload"),
+ EventBubbles::Bubbles,
+ EventCancelable::Cancelable);
+ let event = beforeunload_event.upcast::<Event>();
+ event.set_trusted(true);
+ let event_target = self.window.upcast::<EventTarget>();
+ let has_listeners = event.has_listeners_for(&event_target, &atom!("beforeunload"));
+ event_target.dispatch_event_with_target(
+ document.root().upcast(),
+ &event,
+ );
+ // TODO: Step 6, decrease the event loop's termination nesting level by 1.
+ // Step 7
+ self.salvageable.set(!has_listeners);
+ let mut can_unload = true;
+ // TODO: Step 8 send a message to embedder to prompt user.
+ // Step 9
+ if !recursive_flag {
+ for iframe in self.iter_iframes() {
+ // TODO: handle the case of cross origin iframes.
+ let document = document_from_node(&*iframe);
+ if !document.prompt_to_unload(true) {
+ self.salvageable.set(document.salvageable());
+ can_unload = false;
+ break;
+ }
+ }
+ }
+ // Step 10
+ self.decr_ignore_opens_during_unload_counter();
+ can_unload
+ }
+
+ // https://html.spec.whatwg.org/multipage/#unload-a-document
+ pub fn unload(&self, recursive_flag: bool, recycle: bool) {
+ // TODO: Step 1, increase the event loop's termination nesting level by 1.
+ // Step 2
+ self.incr_ignore_opens_during_unload_counter();
+ let document = Trusted::new(self);
+ // Step 3-6
+ if self.page_showing.get() {
+ self.page_showing.set(false);
+ let event = PageTransitionEvent::new(
+ &self.window,
+ atom!("pagehide"),
+ false, // bubbles
+ false, // cancelable
+ self.salvageable.get(), // persisted
+ );
+ let event = event.upcast::<Event>();
+ event.set_trusted(true);
+ let _ = self.window.upcast::<EventTarget>().dispatch_event_with_target(
+ document.root().upcast(),
+ &event,
+ );
+ // TODO Step 6, document visibility steps.
+ }
+ // Step 7
+ if !self.fired_unload.get() {
+ let event = Event::new(
+ &self.window.upcast(),
+ atom!("unload"),
+ EventBubbles::Bubbles,
+ EventCancelable::Cancelable,
+ );
+ event.set_trusted(true);
+ let event_target = self.window.upcast::<EventTarget>();
+ let has_listeners = event.has_listeners_for(&event_target, &atom!("unload"));
+ let _ = event_target.dispatch_event_with_target(
+ document.root().upcast(),
+ &event,
+ );
+ self.fired_unload.set(true);
+ // Step 9
+ self.salvageable.set(!has_listeners);
+ }
+ // TODO: Step 8, decrease the event loop's termination nesting level by 1.
+
+ // Step 13
+ if !recursive_flag {
+ for iframe in self.iter_iframes() {
+ // TODO: handle the case of cross origin iframes.
+ let document = document_from_node(&*iframe);
+ document.unload(true, recycle);
+ if !document.salvageable() {
+ self.salvageable.set(false);
+ }
+ }
+ }
+ // Step 10, 14
+ if !self.salvageable.get() {
+ // https://html.spec.whatwg.org/multipage/#unloading-document-cleanup-steps
+ let msg = ScriptMsg::DiscardDocument;
+ let _ = self.window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg);
+ }
+ // Step 15, End
+ self.decr_ignore_opens_during_unload_counter();
+ }
+
// https://html.spec.whatwg.org/multipage/#the-end
pub fn maybe_queue_document_completion(&self) {
if self.loader.borrow().is_blocked() {
@@ -2267,6 +2414,7 @@ impl Document {
target_element: MutNullableDom::new(None),
last_click_info: DomRefCell::new(None),
ignore_destructive_writes_counter: Default::default(),
+ ignore_opens_during_unload_counter: Default::default(),
spurious_animation_frames: Cell::new(0),
dom_count: Cell::new(1),
fullscreen_element: MutNullableDom::new(None),
@@ -2276,6 +2424,8 @@ impl Document {
canceller: canceller,
throw_on_dynamic_markup_insertion_counter: Cell::new(0),
page_showing: Cell::new(false),
+ salvageable: Cell::new(true),
+ fired_unload: Cell::new(false)
}
}
@@ -2455,6 +2605,10 @@ impl Document {
self.stylesheets.borrow().len()
}
+ pub fn salvageable(&self) -> bool {
+ self.salvageable.get()
+ }
+
pub fn stylesheet_at(&self, index: usize) -> Option<DomRoot<CSSStyleSheet>> {
let stylesheets = self.stylesheets.borrow();
@@ -2578,6 +2732,20 @@ impl Document {
self.ignore_destructive_writes_counter.get() - 1);
}
+ pub fn is_prompting_or_unloading(&self) -> bool {
+ self.ignore_opens_during_unload_counter.get() > 0
+ }
+
+ fn incr_ignore_opens_during_unload_counter(&self) {
+ self.ignore_opens_during_unload_counter.set(
+ self.ignore_opens_during_unload_counter.get() + 1);
+ }
+
+ fn decr_ignore_opens_during_unload_counter(&self) {
+ self.ignore_opens_during_unload_counter.set(
+ self.ignore_opens_during_unload_counter.get() - 1);
+ }
+
/// Whether we've seen so many spurious animation frames (i.e. animation frames that didn't
/// mutate the DOM) that we've decided to fall back to fake ones.
fn is_faking_animation_frames(&self) -> bool {
diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs
index 607469ca6bd..71b456e24cc 100644
--- a/components/script/dom/event.rs
+++ b/components/script/dom/event.rs
@@ -11,7 +11,7 @@ use dom::bindings::error::Fallible;
use dom::bindings::inheritance::Castable;
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
-use dom::bindings::root::{Dom, DomRoot, MutNullableDom, RootedReference};
+use dom::bindings::root::{DomRoot, MutNullableDom, RootedReference};
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::eventtarget::{CompiledEventListener, EventTarget, ListenerPhase};
@@ -103,6 +103,36 @@ impl Event {
self.cancelable.set(cancelable);
}
+ // Determine if there are any listeners for a given target and type.
+ // See https://github.com/whatwg/dom/issues/453
+ pub fn has_listeners_for(&self, target: &EventTarget, type_: &Atom) -> bool {
+ // TODO: take 'removed' into account? Not implemented in Servo yet.
+ // https://dom.spec.whatwg.org/#event-listener-removed
+ let mut event_path = self.construct_event_path(&target);
+ event_path.push(DomRoot::from_ref(target));
+ event_path.iter().any(|target| target.has_listeners_for(type_))
+ }
+
+ // https://dom.spec.whatwg.org/#event-path
+ fn construct_event_path(&self, target: &EventTarget) -> Vec<DomRoot<EventTarget>> {
+ let mut event_path = vec![];
+ // The "invoke" algorithm is only used on `target` separately,
+ // so we don't put it in the path.
+ if let Some(target_node) = target.downcast::<Node>() {
+ for ancestor in target_node.ancestors() {
+ event_path.push(DomRoot::from_ref(ancestor.upcast::<EventTarget>()));
+ }
+ let top_most_ancestor_or_target =
+ event_path.last().cloned().unwrap_or(DomRoot::from_ref(target));
+ if let Some(document) = DomRoot::downcast::<Document>(top_most_ancestor_or_target) {
+ if self.type_() != atom!("load") && document.browsing_context().is_some() {
+ event_path.push(DomRoot::from_ref(document.window().upcast()));
+ }
+ }
+ }
+ event_path
+ }
+
// https://dom.spec.whatwg.org/#concept-event-dispatch
pub fn dispatch(&self,
target: &EventTarget,
@@ -130,24 +160,9 @@ impl Event {
return self.status();
}
- // Step 3. The "invoke" algorithm is only used on `target` separately,
- // so we don't put it in the path.
- rooted_vec!(let mut event_path);
-
- // Step 4.
- if let Some(target_node) = target.downcast::<Node>() {
- for ancestor in target_node.ancestors() {
- event_path.push(Dom::from_ref(ancestor.upcast::<EventTarget>()));
- }
- let top_most_ancestor_or_target =
- DomRoot::from_ref(event_path.r().last().cloned().unwrap_or(target));
- if let Some(document) = DomRoot::downcast::<Document>(top_most_ancestor_or_target) {
- if self.type_() != atom!("load") && document.browsing_context().is_some() {
- event_path.push(Dom::from_ref(document.window().upcast()));
- }
- }
- }
-
+ // Step 3-4.
+ let path = self.construct_event_path(&target);
+ rooted_vec!(let event_path <- path.into_iter());
// Steps 5-9. In a separate function to short-circuit various things easily.
dispatch_to_listeners(self, target, event_path.r());
diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs
index f909d97e253..3d028a00cdb 100644
--- a/components/script/dom/eventtarget.rs
+++ b/components/script/dom/eventtarget.rs
@@ -187,22 +187,21 @@ impl CompiledEventListener {
CommonEventHandler::BeforeUnloadEventHandler(ref handler) => {
if let Some(event) = event.downcast::<BeforeUnloadEvent>() {
- let rv = event.ReturnValue();
-
+ // Step 5
if let Ok(value) = handler.Call_(object,
event.upcast::<Event>(),
exception_handle) {
- match value {
- Some(value) => {
- if rv.is_empty() {
- event.SetReturnValue(value);
- }
- }
- None => {
- event.upcast::<Event>().PreventDefault();
+ let rv = event.ReturnValue();
+ if let Some(v) = value {
+ if rv.is_empty() {
+ event.SetReturnValue(v);
}
+ event.upcast::<Event>().PreventDefault();
}
}
+ } else {
+ // Step 5, "Otherwise" clause
+ let _ = handler.Call_(object, event.upcast::<Event>(), exception_handle);
}
}
@@ -278,6 +277,12 @@ impl EventListeners {
}
}).collect()
}
+
+ fn has_listeners(&self) -> bool {
+ // TODO: add, and take into account, a 'removed' field?
+ // https://dom.spec.whatwg.org/#event-listener-removed
+ self.0.len() > 0
+ }
}
#[dom_struct]
@@ -304,6 +309,15 @@ impl EventTarget {
Ok(EventTarget::new(global))
}
+ pub fn has_listeners_for(&self,
+ type_: &Atom)
+ -> bool {
+ match self.handlers.borrow().get(type_) {
+ Some(listeners) => listeners.has_listeners(),
+ None => false
+ }
+ }
+
pub fn get_listeners_for(&self,
type_: &Atom,
specific_phase: Option<ListenerPhase>)
diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl
index fbb4787ab89..9212bb4b99b 100644
--- a/components/script/dom/webidls/Document.webidl
+++ b/components/script/dom/webidls/Document.webidl
@@ -83,7 +83,7 @@ dictionary ElementCreationOptions {
// [OverrideBuiltins]
partial /*sealed*/ interface Document {
// resource metadata management
- [/*PutForwards=href, */Unforgeable]
+ [PutForwards=href, Unforgeable]
readonly attribute Location? location;
[SetterThrows] attribute DOMString domain;
readonly attribute DOMString referrer;
diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl
index 034684c1744..37bba020622 100644
--- a/components/script/dom/webidls/Window.webidl
+++ b/components/script/dom/webidls/Window.webidl
@@ -12,7 +12,7 @@
attribute DOMString name;
- [/*PutForwards=href, */Unforgeable] readonly attribute Location location;
+ [PutForwards=href, Unforgeable] readonly attribute Location location;
readonly attribute History history;
[Pref="dom.customelements.enabled"]
readonly attribute CustomElementRegistry customElements;
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 3a672291e8d..88156737e11 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1550,7 +1550,7 @@ impl Window {
// https://html.spec.whatwg.org/multipage/#navigating-across-documents
if !force_reload && url.as_url()[..Position::AfterQuery] ==
doc.url().as_url()[..Position::AfterQuery] {
- // Step 5
+ // Step 6
if let Some(fragment) = url.fragment() {
doc.check_and_scroll_fragment(fragment);
doc.set_url(url.clone());
@@ -1559,9 +1559,24 @@ impl Window {
}
let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
- self.main_thread_script_chan().send(
- MainThreadScriptMsg::Navigate(pipeline_id,
- LoadData::new(url, Some(pipeline_id), referrer_policy, Some(doc.url())), replace)).unwrap();
+
+ // Step 4
+ let window_proxy = self.window_proxy();
+ if let Some(active) = window_proxy.currently_active() {
+ if pipeline_id == active {
+ if doc.is_prompting_or_unloading() {
+ return;
+ }
+ }
+ }
+
+ // Step 7
+ if doc.prompt_to_unload(false) {
+ self.main_thread_script_chan().send(
+ MainThreadScriptMsg::Navigate(pipeline_id,
+ LoadData::new(url, Some(pipeline_id), referrer_policy, Some(doc.url())), replace)).unwrap();
+ };
+
}
pub fn handle_fire_timer(&self, timer_id: TimerEventId) {
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 6ee0ec46d33..613918f6a76 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -1157,6 +1157,7 @@ impl ScriptThread {
AttachLayout(ref new_layout_info) => Some(new_layout_info.new_pipeline_id),
Resize(id, ..) => Some(id),
ResizeInactive(id, ..) => Some(id),
+ UnloadDocument(id) => Some(id),
ExitPipeline(id, ..) => Some(id),
ExitScriptThread => None,
SendEvent(id, ..) => Some(id),
@@ -1275,6 +1276,8 @@ impl ScriptThread {
},
ConstellationControlMsg::Navigate(parent_pipeline_id, browsing_context_id, load_data, replace) =>
self.handle_navigate(parent_pipeline_id, Some(browsing_context_id), load_data, replace),
+ ConstellationControlMsg::UnloadDocument(pipeline_id) =>
+ self.handle_unload_document(pipeline_id),
ConstellationControlMsg::SendEvent(id, event) =>
self.handle_event(id, event),
ConstellationControlMsg::ResizeInactive(id, new_size) =>
@@ -1668,6 +1671,13 @@ impl ScriptThread {
}
}
+ fn handle_unload_document(&self, pipeline_id: PipelineId) {
+ let document = self.documents.borrow().find_document(pipeline_id);
+ if let Some(document) = document {
+ document.unload(false, false);
+ }
+ }
+
fn handle_update_pipeline_id(&self,
parent_pipeline_id: PipelineId,
browsing_context_id: BrowsingContextId,
diff --git a/components/script/timers.rs b/components/script/timers.rs
index 50f95d8400a..202a8edc8ae 100644
--- a/components/script/timers.rs
+++ b/components/script/timers.rs
@@ -241,7 +241,7 @@ impl OneshotTimers {
}
pub fn resume(&self) {
- // Suspend is idempotent: do nothing if the timers are already suspended.
+ // Resume is idempotent: do nothing if the timers are already resumed.
let additional_offset = match self.suspended_since.get() {
Some(suspended_since) => precise_time_ms() - suspended_since,
None => return warn!("Resuming an already resumed timer."),
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index 98cf57116a7..5cbdd8456d7 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -262,6 +262,8 @@ pub enum ConstellationControlMsg {
Resize(PipelineId, WindowSizeData, WindowSizeType),
/// Notifies script that window has been resized but to not take immediate action.
ResizeInactive(PipelineId, WindowSizeData),
+ /// Notifies the script that the document associated with this pipeline should 'unload'.
+ UnloadDocument(PipelineId),
/// Notifies the script that a pipeline should be closed.
ExitPipeline(PipelineId, DiscardBrowsingContext),
/// Notifies the script that the whole thread should be closed.
@@ -335,6 +337,7 @@ impl fmt::Debug for ConstellationControlMsg {
AttachLayout(..) => "AttachLayout",
Resize(..) => "Resize",
ResizeInactive(..) => "ResizeInactive",
+ UnloadDocument(..) => "UnloadDocument",
ExitPipeline(..) => "ExitPipeline",
ExitScriptThread => "ExitScriptThread",
SendEvent(..) => "SendEvent",
diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs
index e8c26c3cf2f..b14d162320d 100644
--- a/components/script_traits/script_msg.rs
+++ b/components/script_traits/script_msg.rs
@@ -145,6 +145,8 @@ pub enum ScriptMsg {
TouchEventProcessed(EventResult),
/// A log entry, with the top-level browsing context id and thread name
LogEntry(Option<String>, LogEntry),
+ /// Discard the document.
+ DiscardDocument,
/// Notifies the constellation that this pipeline has exited.
PipelineExited,
/// Send messages from postMessage calls from serviceworker
diff --git a/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini b/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini
index cac5158543c..ed43d371770 100644
--- a/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini
+++ b/tests/wpt/metadata/FileAPI/url/url-in-tags-revoke.window.js.ini
@@ -1,10 +1,7 @@
[url-in-tags-revoke.window.html]
- expected: TIMEOUT
[Fetching a blob URL immediately before revoking it works in an iframe.]
expected: FAIL
- [Fetching a blob URL immediately before revoking it works in <script> tags.]
- expected: TIMEOUT
[Fetching a blob URL immediately before revoking it works in an iframe navigation.]
expected: TIMEOUT
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/001.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/001.html.ini
deleted file mode 100644
index 402d2e8d213..00000000000
--- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/001.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[001.html]
- type: testharness
- expected: TIMEOUT
- [pageshow event from traversal]
- expected: TIMEOUT
-
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-main-frame-navigation.sub.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-main-frame-navigation.sub.html.ini
index e845bbb5ca0..605731aa123 100644
--- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-main-frame-navigation.sub.html.ini
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-main-frame-navigation.sub.html.ini
@@ -1,3 +1,3 @@
[window-name-after-cross-origin-main-frame-navigation.sub.html]
type: testharness
- expected: TIMEOUT
+ expected: ERROR
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-sub-frame-navigation.sub.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-sub-frame-navigation.sub.html.ini
deleted file mode 100644
index 4aee46d8f3b..00000000000
--- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-cross-origin-sub-frame-navigation.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[window-name-after-cross-origin-sub-frame-navigation.sub.html]
- type: testharness
- expected: TIMEOUT
- [Test that the window name is correct]
- expected: NOTRUN
-
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-main-frame-navigation.sub.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-main-frame-navigation.sub.html.ini
index ba6fc505ce8..3e329c6d560 100644
--- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-main-frame-navigation.sub.html.ini
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-main-frame-navigation.sub.html.ini
@@ -1,3 +1,3 @@
[window-name-after-same-origin-main-frame-navigation.sub.html]
type: testharness
- expected: TIMEOUT
+ expected: ERROR
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-sub-frame-navigation.sub.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-sub-frame-navigation.sub.html.ini
deleted file mode 100644
index 7f5b039093c..00000000000
--- a/tests/wpt/metadata/html/browsers/browsing-the-web/history-traversal/window-name-after-same-origin-sub-frame-navigation.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[window-name-after-same-origin-sub-frame-navigation.sub.html]
- type: testharness
- expected: TIMEOUT
- [Test that the window name is correct]
- expected: NOTRUN
-
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini
index d2689f1a8a9..aadbdc0beda 100644
--- a/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/007.html.ini
@@ -1,3 +1,4 @@
[007.html]
type: testharness
- expected: TIMEOUT
+ [Link with onclick javascript url and href navigation ]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/child_navigates_parent_location.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/child_navigates_parent_location.html.ini
deleted file mode 100644
index b623e34998a..00000000000
--- a/tests/wpt/metadata/html/browsers/browsing-the-web/navigating-across-documents/child_navigates_parent_location.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[child_navigates_parent_location.html]
- type: testharness
- expected: TIMEOUT
- [Child document navigating parent via location ]
- expected: TIMEOUT
-
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/001.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/001.html.ini
new file mode 100644
index 00000000000..ea827596bf4
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/001.html.ini
@@ -0,0 +1,4 @@
+[001.html]
+ type: testharness
+ [document.open in unload]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/002.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/002.html.ini
new file mode 100644
index 00000000000..93d509d1609
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/002.html.ini
@@ -0,0 +1,4 @@
+[002.html]
+ type: testharness
+ [document.open in unload]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/003.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/003.html.ini
new file mode 100644
index 00000000000..5eebab7723d
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/003.html.ini
@@ -0,0 +1,4 @@
+[003.html]
+ type: testharness
+ [document.open in beforeunload with link]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/004.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/004.html.ini
new file mode 100644
index 00000000000..a52c3225f46
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/004.html.ini
@@ -0,0 +1,4 @@
+[004.html]
+ type: testharness
+ [document.open in beforeunload with button]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/005.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/005.html.ini
new file mode 100644
index 00000000000..7765d7e2549
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/005.html.ini
@@ -0,0 +1,4 @@
+[005.html]
+ type: testharness
+ [document.open in pagehide in iframe]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/__dir__.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/__dir__.ini
deleted file mode 100644
index 163ca23a12f..00000000000
--- a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/__dir__.ini
+++ /dev/null
@@ -1 +0,0 @@
-disabled: for now
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-history-back.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-history-back.html.ini
new file mode 100644
index 00000000000..a7665ba15a5
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-history-back.html.ini
@@ -0,0 +1,4 @@
+[beforeunload-on-history-back.html]
+ type: testharness
+ [beforeunload event fires on history navigation back]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-navigation-of-parent.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-navigation-of-parent.html.ini
new file mode 100644
index 00000000000..2ec2483f679
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-navigation-of-parent.html.ini
@@ -0,0 +1,6 @@
+[beforeunload-on-navigation-of-parent.html]
+ type: testharness
+ [Triggering navigation from within beforeunload event]
+ expected: FAIL
+ [beforeunload in iframe on navigation of parent]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/navigation-within-beforeunload.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/navigation-within-beforeunload.html.ini
new file mode 100644
index 00000000000..d8e44b25fd7
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/navigation-within-beforeunload.html.ini
@@ -0,0 +1,4 @@
+[navigation-within-beforeunload.html]
+ type: testharness
+ [Triggering navigation from within beforeunload event]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/unload/003.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/unload/003.html.ini
new file mode 100644
index 00000000000..f23c18eaad0
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/unload/003.html.ini
@@ -0,0 +1,4 @@
+[003.html]
+ type: testharness
+ [unload event properties]
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/unload/006.html.ini b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/unload/006.html.ini
new file mode 100644
index 00000000000..45b39bde1b2
--- /dev/null
+++ b/tests/wpt/metadata/html/browsers/browsing-the-web/unloading-documents/unload/006.html.ini
@@ -0,0 +1,5 @@
+[006.html]
+ type: testharness
+ expected: TIMEOUT
+ [salvagable state of document after setting pagehide listener]
+ expected: TIMEOUT
diff --git a/tests/wpt/metadata/html/browsers/history/the-location-interface/assign_after_load.html.ini b/tests/wpt/metadata/html/browsers/history/the-location-interface/assign_after_load.html.ini
index 4d70a77e3a2..0ac3627e072 100644
--- a/tests/wpt/metadata/html/browsers/history/the-location-interface/assign_after_load.html.ini
+++ b/tests/wpt/metadata/html/browsers/history/the-location-interface/assign_after_load.html.ini
@@ -1,6 +1,4 @@
[assign_after_load.html]
type: testharness
- expected: TIMEOUT
[Assignment to location after document is completely loaded]
- expected: TIMEOUT
-
+ expected: FAIL
diff --git a/tests/wpt/metadata/html/browsers/history/the-location-interface/assign_before_load.html.ini b/tests/wpt/metadata/html/browsers/history/the-location-interface/assign_before_load.html.ini
deleted file mode 100644
index 0d70e780326..00000000000
--- a/tests/wpt/metadata/html/browsers/history/the-location-interface/assign_before_load.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[assign_before_load.html]
- type: testharness
- expected: TIMEOUT
- [Assignment to location before document is completely loaded]
- expected: TIMEOUT
-
diff --git a/tests/wpt/metadata/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html.ini b/tests/wpt/metadata/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html.ini
index 3f58364cf0f..fc20af26ee0 100644
--- a/tests/wpt/metadata/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html.ini
+++ b/tests/wpt/metadata/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html.ini
@@ -17,19 +17,3 @@
[Set data URL frame location.protocol to http+x]
expected: FAIL
-
- [Set HTTP URL frame location.protocol to x]
- expected: FAIL
-
- [Set HTTP URL frame location.protocol to data]
- expected: FAIL
-
- [Set HTTP URL frame location.protocol to ftp]
- expected: FAIL
-
- [Set HTTP URL frame location.protocol to gopher]
- expected: FAIL
-
- [Set HTTP URL frame location.protocol to http+x]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini
index f93db63cd5b..f0c77110ca6 100644
--- a/tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini
+++ b/tests/wpt/metadata/html/browsers/the-window-object/window-properties.https.html.ini
@@ -32,9 +32,6 @@
[Window attribute: onmousewheel]
expected: FAIL
- [Window unforgeable attribute: location]
- expected: FAIL
-
[Window replaceable attribute: locationbar]
expected: FAIL
diff --git a/tests/wpt/metadata/html/dom/interfaces.https.html.ini b/tests/wpt/metadata/html/dom/interfaces.https.html.ini
index 4f24459327b..c6bb4b3d4bf 100644
--- a/tests/wpt/metadata/html/dom/interfaces.https.html.ini
+++ b/tests/wpt/metadata/html/dom/interfaces.https.html.ini
@@ -44,9 +44,6 @@
[Document interface: attribute onsecuritypolicyviolation]
expected: FAIL
- [Document interface: iframe.contentDocument must have own property "location"]
- expected: FAIL
-
[Document interface: iframe.contentDocument must inherit property "dir" with the proper type]
expected: FAIL
@@ -113,9 +110,6 @@
[Document interface: iframe.contentDocument must inherit property "onsecuritypolicyviolation" with the proper type]
expected: FAIL
- [Document interface: new Document() must have own property "location"]
- expected: FAIL
-
[Document interface: new Document() must inherit property "dir" with the proper type]
expected: FAIL
@@ -179,9 +173,6 @@
[Document interface: new Document() must inherit property "onsecuritypolicyviolation" with the proper type]
expected: FAIL
- [Document interface: document.implementation.createDocument(null, "", null) must have own property "location"]
- expected: FAIL
-
[Document interface: document.implementation.createDocument(null, "", null) must inherit property "dir" with the proper type]
expected: FAIL
@@ -4991,9 +4982,6 @@
[Window interface: window must inherit property "self" with the proper type]
expected: FAIL
- [Window interface: window must have own property "location"]
- expected: FAIL
-
[Window interface: window must inherit property "locationbar" with the proper type]
expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/execution-timing/079.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/execution-timing/079.html.ini
deleted file mode 100644
index 27a1d473162..00000000000
--- a/tests/wpt/metadata/html/semantics/scripting-1/the-script-element/execution-timing/079.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[079.html]
- type: testharness
- [ setting location to javascript URL from event handler ]
- expected: FAIL
-