diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 7 | ||||
-rw-r--r-- | components/script/dom/window.rs | 97 | ||||
-rw-r--r-- | components/script/dom/windowproxy.rs | 21 |
3 files changed, 98 insertions, 27 deletions
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index a3a246c4edc..f5a820458c2 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -668,15 +668,14 @@ impl VirtualMethods for HTMLIFrameElement { // so we need to discard the browsing contexts now, rather than // when the `PipelineExit` message arrives. for exited_pipeline_id in exited_pipeline_ids { + // https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded if let Some(exited_document) = ScriptThread::find_document(exited_pipeline_id) { debug!( "Discarding browsing context for pipeline {}", exited_pipeline_id ); - exited_document - .window() - .window_proxy() - .discard_browsing_context(); + let exited_window = exited_document.window(); + exited_window.discard_browsing_context(); for exited_iframe in exited_document.iter_iframes() { debug!("Discarding nested browsing context"); exited_iframe.destroy_nested_browsing_context(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index a79669d6c2e..8e139158427 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -63,7 +63,7 @@ use crate::script_runtime::{ use crate::script_thread::{ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg}; use crate::script_thread::{ScriptThread, SendableMainThreadScriptChan}; use crate::task_manager::TaskManager; -use crate::task_source::TaskSourceName; +use crate::task_source::{TaskSource, TaskSourceName}; use crate::timers::{IsInterval, TimerCallback}; use crate::webdriver_handlers::jsval_to_webdriver; use app_units::Au; @@ -82,8 +82,8 @@ use ipc_channel::router::ROUTER; use js::jsapi::JSAutoRealm; use js::jsapi::JSPROP_ENUMERATE; use js::jsapi::{GCReason, JS_GC}; -use js::jsval::JSVal; use js::jsval::UndefinedValue; +use js::jsval::{JSVal, NullValue}; use js::rust::wrappers::JS_DefineProperty; use js::rust::HandleValue; use media::WindowGLContext; @@ -352,11 +352,26 @@ impl Window { *self.js_runtime.borrow_for_script_deallocation() = None; self.window_proxy.set(None); self.current_state.set(WindowState::Zombie); - self.ignore_all_events(); + self.ignore_all_tasks(); } } - fn ignore_all_events(&self) { + /// A convenience method for + /// https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded + pub fn discard_browsing_context(&self) { + let proxy = match self.window_proxy.get() { + Some(proxy) => proxy, + None => panic!("Discarding a BC from a window that has none"), + }; + proxy.discard_browsing_context(); + // Step 4 of https://html.spec.whatwg.org/multipage/#discard-a-document + // Other steps performed when the `PipelineExit` message + // is handled by the ScriptThread. + self.ignore_all_tasks(); + } + + /// Cancel all current, and ignore all subsequently queued, tasks. + pub fn ignore_all_tasks(&self) { let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut(); for task_source_name in TaskSourceName::all() { let flag = ignore_flags @@ -623,10 +638,23 @@ impl WindowMethods for Window { self.window_proxy().open(url, target, features) } - #[allow(unsafe_code)] // https://html.spec.whatwg.org/multipage/#dom-opener fn Opener(&self, cx: JSContext) -> JSVal { - unsafe { self.window_proxy().opener(*cx) } + // Step 1, Let current be this Window object's browsing context. + let current = match self.window_proxy.get() { + Some(proxy) => proxy, + // Step 2, If current is null, then return null. + None => return NullValue(), + }; + // Still step 2, since the window's BC is the associated doc's BC, + // see https://html.spec.whatwg.org/multipage/#window-bc + // and a doc's BC is null if it has been discarded. + // see https://html.spec.whatwg.org/multipage/#concept-document-bc + if current.is_browsing_context_discarded() { + return NullValue(); + } + // Step 3 to 5. + current.opener(*cx) } #[allow(unsafe_code)] @@ -653,31 +681,60 @@ impl WindowMethods for Window { fn Closed(&self) -> bool { self.window_proxy .get() - .map(|ref proxy| proxy.is_browsing_context_discarded()) + .map(|ref proxy| proxy.is_browsing_context_discarded() || proxy.is_closing()) .unwrap_or(true) } // https://html.spec.whatwg.org/multipage/#dom-window-close fn Close(&self) { - let window_proxy = self.window_proxy(); + // Step 1, Let current be this Window object's browsing context. + // Step 2, If current is null or its is closing is true, then return. + let window_proxy = match self.window_proxy.get() { + Some(proxy) => proxy, + None => return, + }; + if window_proxy.is_closing() { + return; + } // Note: check the length of the "session history", as opposed to the joint session history? // see https://github.com/whatwg/html/issues/3734 if let Ok(history_length) = self.History().GetLength() { let is_auxiliary = window_proxy.is_auxiliary(); + // https://html.spec.whatwg.org/multipage/#script-closable let is_script_closable = (self.is_top_level() && history_length == 1) || is_auxiliary; + + // TODO: rest of Step 3: + // Is the incumbent settings object's responsible browsing context familiar with current? + // Is the incumbent settings object's responsible browsing context allowed to navigate current? if is_script_closable { - let doc = self.Document(); - // https://html.spec.whatwg.org/multipage/#closing-browsing-contexts - // Step 1, prompt to unload. - if doc.prompt_to_unload(false) { - // Step 2, unload. - doc.unload(false); - // Step 3, remove from the user interface - let _ = self.send_to_embedder(EmbedderMsg::CloseBrowser); - // Step 4, discard browsing context. - let _ = self.send_to_constellation(ScriptMsg::DiscardTopLevelBrowsingContext); - } + // Step 3.1, set current's is closing to true. + window_proxy.close(); + + // Step 3.2, queue a task on the DOM manipulation task source to close current. + let this = Trusted::new(self); + let task = task!(window_close_browsing_context: move || { + let window = this.root(); + let document = window.Document(); + // https://html.spec.whatwg.org/multipage/#closing-browsing-contexts + // Step 1, prompt to unload. + if document.prompt_to_unload(false) { + // Step 2, unload. + document.unload(false); + // Step 3, remove from the user interface + let _ = window.send_to_embedder(EmbedderMsg::CloseBrowser); + // Step 4, discard browsing context. + // https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded + // which calls into https://html.spec.whatwg.org/multipage/#discard-a-document. + window.discard_browsing_context(); + + let _ = window.send_to_constellation(ScriptMsg::DiscardTopLevelBrowsingContext); + } + }); + self.task_manager() + .dom_manipulation_task_source() + .queue(task, &self.upcast::<GlobalScope>()) + .expect("Queuing window_close_browsing_context task to work"); } } } @@ -1302,7 +1359,7 @@ impl Window { if let Some(performance) = self.performance.get() { performance.clear_and_disable_performance_entry_buffer(); } - self.ignore_all_events(); + self.ignore_all_tasks(); } /// <https://drafts.csswg.org/cssom-view/#dom-window-scroll> diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index 3ff326c683a..7fea1728c12 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -96,6 +96,9 @@ pub struct WindowProxy { /// Has the browsing context been disowned? disowned: Cell<bool>, + /// https://html.spec.whatwg.org/multipage/#is-closing + is_closing: Cell<bool>, + /// The containing iframe element, if this is a same-origin iframe frame_element: Option<Dom<Element>>, @@ -126,6 +129,7 @@ impl WindowProxy { currently_active: Cell::new(currently_active), discarded: Cell::new(false), disowned: Cell::new(false), + is_closing: Cell::new(false), frame_element: frame_element.map(Dom::from_ref), parent: parent.map(Dom::from_ref), delaying_load_events_mode: Cell::new(false), @@ -352,9 +356,20 @@ impl WindowProxy { self.disowned.set(true); } + /// https://html.spec.whatwg.org/multipage/#dom-window-close + /// Step 3.1, set BCs `is_closing` to true. + pub fn close(&self) { + self.is_closing.set(true); + } + + /// https://html.spec.whatwg.org/multipage/#is-closing + pub fn is_closing(&self) -> bool { + self.is_closing.get() + } + #[allow(unsafe_code)] // https://html.spec.whatwg.org/multipage/#dom-opener - pub unsafe fn opener(&self, cx: *mut JSContext) -> JSVal { + pub fn opener(&self, cx: *mut JSContext) -> JSVal { if self.disowned.get() { return NullValue(); } @@ -371,7 +386,7 @@ impl WindowProxy { opener_id, ) { Some(opener_top_id) => { - let global_to_clone_from = GlobalScope::from_context(cx); + let global_to_clone_from = unsafe { GlobalScope::from_context(cx) }; WindowProxy::new_dissimilar_origin( &*global_to_clone_from, opener_id, @@ -388,7 +403,7 @@ impl WindowProxy { return NullValue(); } rooted!(in(cx) let mut val = UndefinedValue()); - opener_proxy.to_jsval(cx, val.handle_mut()); + unsafe { opener_proxy.to_jsval(cx, val.handle_mut()) }; return val.get(); } |