aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2018-12-26 01:53:20 -0500
committerGitHub <noreply@github.com>2018-12-26 01:53:20 -0500
commit66223ee1054a36a093cf5ded065f6fc6d3fecd8b (patch)
tree71b445b09cad26eef9a815807d85975ed69efd7f /components
parent69e90a83bc480c13c4aa4165b9d2c432b54a4069 (diff)
parentcca354b217f4f8c7d92229ec88adde83b8300daa (diff)
downloadservo-66223ee1054a36a093cf5ded065f6fc6d3fecd8b.tar.gz
servo-66223ee1054a36a093cf5ded065f6fc6d3fecd8b.zip
Auto merge of #22121 - gterzian:remove_constellation_block_in_navigation, r=paulrouget
Remove sync constellation -> embedder communication <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #22042 (github issue number if applicable). <!-- Either: --> - [ ] 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/22121) <!-- Reviewable:end -->
Diffstat (limited to 'components')
-rw-r--r--components/compositing/windowing.rs5
-rw-r--r--components/constellation/constellation.rs115
-rw-r--r--components/embedder_traits/lib.rs8
-rw-r--r--components/script/dom/document.rs53
-rw-r--r--components/script/dom/htmliframeelement.rs9
-rw-r--r--components/script/dom/servoparser/mod.rs3
-rw-r--r--components/script/dom/window.rs12
-rw-r--r--components/script/dom/windowproxy.rs24
-rw-r--r--components/script/script_thread.rs42
-rw-r--r--components/script_traits/lib.rs8
-rw-r--r--components/servo/lib.rs10
11 files changed, 249 insertions, 40 deletions
diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs
index 7e95ca02161..c2575640975 100644
--- a/components/compositing/windowing.rs
+++ b/components/compositing/windowing.rs
@@ -9,7 +9,7 @@ use euclid::TypedScale;
#[cfg(feature = "gl")]
use gleam::gl;
use keyboard_types::KeyboardEvent;
-use msg::constellation_msg::{TopLevelBrowsingContextId, TraversalDirection};
+use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId, TraversalDirection};
use script_traits::{MouseButton, TouchEventType, TouchId};
use servo_geometry::DeviceIndependentPixel;
use servo_url::ServoUrl;
@@ -49,6 +49,8 @@ pub enum WindowEvent {
Refresh,
/// Sent when the window is resized.
Resize,
+ /// Sent when a navigation request from script is allowed/refused.
+ AllowNavigationResponse(PipelineId, bool),
/// Sent when a new URL is to be loaded.
LoadUrl(TopLevelBrowsingContextId, ServoUrl),
/// Sent when a mouse hit test is to be performed.
@@ -96,6 +98,7 @@ impl Debug for WindowEvent {
WindowEvent::Refresh => write!(f, "Refresh"),
WindowEvent::Resize => write!(f, "Resize"),
WindowEvent::Keyboard(..) => write!(f, "Keyboard"),
+ WindowEvent::AllowNavigationResponse(..) => write!(f, "AllowNavigationResponse"),
WindowEvent::LoadUrl(..) => write!(f, "LoadUrl"),
WindowEvent::MouseWindowEventClass(..) => write!(f, "Mouse"),
WindowEvent::MouseWindowMoveEventClass(..) => write!(f, "MouseMove"),
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index a54169d66db..d14e4d921db 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -156,6 +156,7 @@ use servo_rand::{random, Rng, SeedableRng, ServoRng};
use servo_remutex::ReentrantMutex;
use servo_url::{Host, ImmutableOrigin, ServoUrl};
use std::borrow::ToOwned;
+use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::marker::PhantomData;
use std::mem::replace;
@@ -168,6 +169,8 @@ use style_traits::viewport::ViewportConstraints;
use style_traits::CSSPixel;
use webvr_traits::{WebVREvent, WebVRMsg};
+type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, bool)>;
+
/// Servo supports tabs (referred to as browsers), so `Constellation` needs to
/// store browser specific data for bookkeeping.
struct Browser {
@@ -366,6 +369,9 @@ pub struct Constellation<Message, LTF, STF> {
/// A channel through which messages can be sent to the canvas paint thread.
canvas_chan: IpcSender<CanvasMsg>,
+
+ /// Navigation requests from script awaiting approval from the embedder.
+ pending_approval_navigations: PendingApprovalNavigations,
}
/// State needed to construct a constellation.
@@ -698,6 +704,7 @@ where
webgl_threads: state.webgl_threads,
webvr_chan: state.webvr_chan,
canvas_chan: CanvasPaintThread::start(),
+ pending_approval_navigations: HashMap::new(),
};
constellation.run();
@@ -1044,6 +1051,62 @@ where
FromCompositorMsg::Keyboard(key_event) => {
self.handle_key_msg(key_event);
},
+ // Perform a navigation previously requested by script, if approved by the embedder.
+ // If there is already a pending page (self.pending_changes), it will not be overridden;
+ // However, if the id is not encompassed by another change, it will be.
+ FromCompositorMsg::AllowNavigationResponse(pipeline_id, allowed) => {
+ let pending = self.pending_approval_navigations.remove(&pipeline_id);
+
+ let top_level_browsing_context_id = match self.pipelines.get(&pipeline_id) {
+ Some(pipeline) => pipeline.top_level_browsing_context_id,
+ None => return warn!("Attempted to navigate {} after closure.", pipeline_id),
+ };
+
+ match pending {
+ Some((load_data, replace)) => {
+ if allowed {
+ self.load_url(
+ top_level_browsing_context_id,
+ pipeline_id,
+ load_data,
+ replace,
+ );
+ } else {
+ let pipeline_is_top_level_pipeline = self
+ .browsing_contexts
+ .get(&BrowsingContextId::from(top_level_browsing_context_id))
+ .map(|ctx| ctx.pipeline_id == pipeline_id)
+ .unwrap_or(false);
+ // If the navigation is refused, and this concerns an iframe,
+ // we need to take it out of it's "delaying-load-events-mode".
+ // https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
+ if !pipeline_is_top_level_pipeline {
+ let msg = ConstellationControlMsg::StopDelayingLoadEventsMode(
+ pipeline_id,
+ );
+ let result = match self.pipelines.get(&pipeline_id) {
+ Some(pipeline) => pipeline.event_loop.send(msg),
+ None => {
+ return warn!(
+ "Attempted to navigate {} after closure.",
+ pipeline_id
+ )
+ },
+ };
+ if let Err(e) = result {
+ self.handle_send_error(pipeline_id, e);
+ }
+ }
+ }
+ },
+ None => {
+ return warn!(
+ "AllowNavigationReqsponse for unknow request: {:?}",
+ pipeline_id
+ )
+ },
+ };
+ },
// Load a new page from a typed url
// If there is already a pending page (self.pending_changes), it will not be overridden;
// However, if the id is not encompassed by another change, it will be.
@@ -1059,12 +1122,9 @@ where
)
},
};
- self.handle_load_url_msg(
- top_level_browsing_context_id,
- pipeline_id,
- load_data,
- false,
- );
+ // Since this is a top-level load, initiated by the embedder, go straight to load_url,
+ // bypassing schedule_navigation.
+ self.load_url(top_level_browsing_context_id, pipeline_id, load_data, false);
},
FromCompositorMsg::IsReadyToSaveImage(pipeline_states) => {
let is_ready = self.handle_is_ready_to_save_image(pipeline_states);
@@ -1176,11 +1236,9 @@ where
FromScriptMsg::ChangeRunningAnimationsState(animation_state) => {
self.handle_change_running_animations_state(source_pipeline_id, animation_state)
},
- // Load a new page from a mouse click
- // If there is already a pending page (self.pending_changes), it will not be overridden;
- // However, if the id is not encompassed by another change, it will be.
+ // Ask the embedder for permission to load a new page.
FromScriptMsg::LoadUrl(load_data, replace) => {
- self.handle_load_url_msg(source_top_ctx_id, source_pipeline_id, load_data, replace);
+ self.schedule_navigation(source_top_ctx_id, source_pipeline_id, load_data, replace);
},
FromScriptMsg::AbortLoadUrl => {
self.handle_abort_load_url_msg(source_pipeline_id);
@@ -1806,6 +1864,9 @@ where
Some(parent_pipeline_id) => parent_pipeline_id,
None => return warn!("Subframe {} has no parent.", pipeline_id),
};
+ // https://html.spec.whatwg.org/multipage/#the-iframe-element:completely-loaded
+ // When a Document in an iframe is marked as completely loaded,
+ // the user agent must run the iframe load event steps.
let msg = ConstellationControlMsg::DispatchIFrameLoadEvent {
target: browsing_context_id,
parent: parent_pipeline_id,
@@ -2115,14 +2176,33 @@ where
}
}
- fn handle_load_url_msg(
+ /// Schedule a navigation(via load_url).
+ /// 1: Ask the embedder for permission.
+ /// 2: Store the details of the navigation, pending approval from the embedder.
+ fn schedule_navigation(
&mut self,
top_level_browsing_context_id: TopLevelBrowsingContextId,
source_id: PipelineId,
load_data: LoadData,
replace: bool,
) {
- self.load_url(top_level_browsing_context_id, source_id, load_data, replace);
+ match self.pending_approval_navigations.entry(source_id) {
+ Entry::Occupied(_) => {
+ return warn!(
+ "Pipeline {:?} tried to schedule a navigation while one is already pending.",
+ source_id
+ )
+ },
+ Entry::Vacant(entry) => {
+ let _ = entry.insert((load_data.clone(), replace));
+ },
+ };
+ // Allow the embedder to handle the url itself
+ let msg = (
+ Some(top_level_browsing_context_id),
+ EmbedderMsg::AllowNavigationRequest(source_id, load_data.url.clone()),
+ );
+ self.embedder_proxy.send(msg);
}
fn load_url(
@@ -2132,17 +2212,6 @@ where
load_data: LoadData,
replace: bool,
) -> Option<PipelineId> {
- // Allow the embedder to handle the url itself
- let (chan, port) = ipc::channel().expect("Failed to create IPC channel!");
- let msg = (
- Some(top_level_browsing_context_id),
- EmbedderMsg::AllowNavigation(load_data.url.clone(), chan),
- );
- self.embedder_proxy.send(msg);
- if let Ok(false) = port.recv() {
- return None;
- }
-
debug!("Loading {} in pipeline {}.", load_data.url, source_id);
// If this load targets an iframe, its framing element may exist
// in a separate script thread than the framed document that initiated
diff --git a/components/embedder_traits/lib.rs b/components/embedder_traits/lib.rs
index 93c3275522d..e25ad11d13e 100644
--- a/components/embedder_traits/lib.rs
+++ b/components/embedder_traits/lib.rs
@@ -14,7 +14,7 @@ pub mod resources;
use crossbeam_channel::{Receiver, Sender};
use ipc_channel::ipc::IpcSender;
use keyboard_types::KeyboardEvent;
-use msg::constellation_msg::{InputMethodType, TopLevelBrowsingContextId};
+use msg::constellation_msg::{InputMethodType, PipelineId, TopLevelBrowsingContextId};
use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter};
use style_traits::cursor::CursorKind;
@@ -79,8 +79,8 @@ pub enum EmbedderMsg {
ResizeTo(DeviceIntSize),
// Show an alert message.
Alert(String, IpcSender<()>),
- /// Wether or not to follow a link
- AllowNavigation(ServoUrl, IpcSender<bool>),
+ /// Wether or not to allow a pipeline to load a url.
+ AllowNavigationRequest(PipelineId, ServoUrl),
/// Whether or not to allow script to open a new tab/browser
AllowOpeningBrowser(IpcSender<bool>),
/// A new browser was created by script
@@ -128,7 +128,7 @@ impl Debug for EmbedderMsg {
EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"),
EmbedderMsg::Alert(..) => write!(f, "Alert"),
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
- EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"),
+ EmbedderMsg::AllowNavigationRequest(..) => write!(f, "AllowNavigationRequest"),
EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"),
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 66b9e379d75..d679ff0dd3f 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -416,6 +416,8 @@ pub struct Document {
/// List of tasks to execute as soon as last script/layout blocker is removed.
#[ignore_malloc_size_of = "Measuring trait objects is hard"]
delayed_tasks: DomRefCell<Vec<Box<dyn TaskBox>>>,
+ /// https://html.spec.whatwg.org/multipage/#completely-loaded
+ completely_loaded: Cell<bool>,
}
#[derive(JSTraceable, MallocSizeOf)]
@@ -507,6 +509,10 @@ impl Document {
self.https_state.set(https_state);
}
+ pub fn is_completely_loaded(&self) -> bool {
+ self.completely_loaded.get()
+ }
+
pub fn is_fully_active(&self) -> bool {
self.activity.get() == DocumentActivity::FullyActive
}
@@ -1735,7 +1741,11 @@ impl Document {
self.process_deferred_scripts();
},
LoadType::PageSource(_) => {
- if self.has_browsing_context {
+ if self.has_browsing_context && self.is_fully_active() {
+ // Note: if the document is not fully active, the layout thread will have exited already.
+ // The underlying problem might actually be that layout exits while it should be kept alive.
+ // See https://github.com/servo/servo/issues/22507
+
// Disarm the reflow timer and trigger the initial reflow.
self.reflow_timeout.set(None);
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
@@ -1899,7 +1909,21 @@ impl Document {
// https://html.spec.whatwg.org/multipage/#the-end
pub fn maybe_queue_document_completion(&self) {
- if self.loader.borrow().is_blocked() {
+ // https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
+ let is_in_delaying_load_events_mode = match self.window.undiscarded_window_proxy() {
+ Some(window_proxy) => window_proxy.is_delaying_load_events_mode(),
+ None => false,
+ };
+
+ // Note: if the document is not fully active, the layout thread will have exited already,
+ // and this method will panic.
+ // The underlying problem might actually be that layout exits while it should be kept alive.
+ // See https://github.com/servo/servo/issues/22507
+ let not_ready_for_load = self.loader.borrow().is_blocked() ||
+ !self.is_fully_active() ||
+ is_in_delaying_load_events_mode;
+
+ if not_ready_for_load {
// Step 6.
return;
}
@@ -1952,8 +1976,6 @@ impl Document {
window.reflow(ReflowGoal::Full, ReflowReason::DocumentLoaded);
- document.notify_constellation_load();
-
if let Some(fragment) = document.url().fragment() {
document.check_and_scroll_fragment(fragment);
}
@@ -2008,8 +2030,26 @@ impl Document {
// Step 11.
// TODO: ready for post-load tasks.
- // Step 12.
- // TODO: completely loaded.
+ // Step 12: completely loaded.
+ // https://html.spec.whatwg.org/multipage/#completely-loaded
+ // TODO: fully implement "completely loaded".
+ let document = Trusted::new(self);
+ if document.root().browsing_context().is_some() {
+ self.window
+ .task_manager()
+ .dom_manipulation_task_source()
+ .queue(
+ task!(completely_loaded: move || {
+ let document = document.root();
+ document.completely_loaded.set(true);
+ // Note: this will, among others, result in the "iframe-load-event-steps" being run.
+ // https://html.spec.whatwg.org/multipage/#iframe-load-event-steps
+ document.notify_constellation_load();
+ }),
+ self.window.upcast(),
+ )
+ .unwrap();
+ }
}
// https://html.spec.whatwg.org/multipage/#pending-parsing-blocking-script
@@ -2701,6 +2741,7 @@ impl Document {
fired_unload: Cell::new(false),
responsive_images: Default::default(),
redirect_count: Cell::new(0),
+ completely_loaded: Cell::new(false),
script_and_layout_blockers: Cell::new(0),
delayed_tasks: Default::default(),
}
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index 0e23a04fc39..2bde8893a29 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -274,8 +274,13 @@ impl HTMLIFrameElement {
);
let pipeline_id = self.pipeline_id();
- // If the initial `about:blank` page is the current page, load with replacement enabled.
- let replace = pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get();
+ // If the initial `about:blank` page is the current page, load with replacement enabled,
+ // see https://html.spec.whatwg.org/multipage/#the-iframe-element:about:blank-3
+ let is_about_blank =
+ pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get();
+ // Replacement enabled also takes into account whether the document is "completely loaded",
+ // see https://html.spec.whatwg.org/multipage/#the-iframe-element:completely-loaded
+ let replace = is_about_blank || !document.is_completely_loaded();
self.navigate_or_reload_child_browsing_context(
Some(load_data),
NavigationType::Regular,
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index 913f42f7d9e..2fa92d1daa8 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -380,8 +380,7 @@ impl ServoParser {
self.document.set_current_parser(None);
// Step 4.
- self.document
- .set_ready_state(DocumentReadyState::Interactive);
+ self.document.set_ready_state(DocumentReadyState::Complete);
}
// https://html.spec.whatwg.org/multipage/#active-parser
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 29a008ce911..1dbe0fc4c3a 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1421,7 +1421,9 @@ impl Window {
dom_count: self.Document().dom_count(),
};
- self.layout_chan.send(Msg::Reflow(reflow)).unwrap();
+ self.layout_chan
+ .send(Msg::Reflow(reflow))
+ .expect("Layout thread disconnected.");
debug!("script: layout forked");
@@ -1783,8 +1785,14 @@ impl Window {
}
}
- // Step 7
+ // Step 8
if doc.prompt_to_unload(false) {
+ if self.window_proxy().parent().is_some() {
+ // Step 10
+ // If browsingContext is a nested browsing context,
+ // then put it in the delaying load events mode.
+ self.window_proxy().start_delaying_load_events_mode();
+ }
self.main_thread_script_chan()
.send(MainThreadScriptMsg::Navigate(
pipeline_id,
diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs
index 8b0af9a147e..c3d995be936 100644
--- a/components/script/dom/windowproxy.rs
+++ b/components/script/dom/windowproxy.rs
@@ -93,6 +93,9 @@ pub struct WindowProxy {
/// The parent browsing context's window proxy, if this is a nested browsing context
parent: Option<Dom<WindowProxy>>,
+
+ /// https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
+ delaying_load_events_mode: Cell<bool>,
}
impl WindowProxy {
@@ -117,6 +120,7 @@ impl WindowProxy {
disowned: Cell::new(false),
frame_element: frame_element.map(Dom::from_ref),
parent: parent.map(Dom::from_ref),
+ delaying_load_events_mode: Cell::new(false),
opener,
}
}
@@ -312,6 +316,26 @@ impl WindowProxy {
None
}
+ /// https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
+ pub fn is_delaying_load_events_mode(&self) -> bool {
+ self.delaying_load_events_mode.get()
+ }
+
+ /// https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
+ pub fn start_delaying_load_events_mode(&self) {
+ self.delaying_load_events_mode.set(true);
+ }
+
+ /// https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
+ pub fn stop_delaying_load_events_mode(&self) {
+ self.delaying_load_events_mode.set(false);
+ if let Some(document) = self.document() {
+ if !document.loader().events_inhibited() {
+ ScriptThread::mark_document_with_no_blocked_loads(&document);
+ }
+ }
+ }
+
// https://html.spec.whatwg.org/multipage/#disowned-its-opener
pub fn disown(&self) {
self.disowned.set(true);
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 8383caa9800..178e121bda9 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -1314,6 +1314,10 @@ impl ScriptThread {
// into this loop too, but for now it's only images.
debug!("Issuing batched reflows.");
for (_, document) in self.documents.borrow().iter() {
+ // Step 13
+ if !document.is_fully_active() {
+ continue;
+ }
let window = document.window();
let pending_reflows = window.get_pending_reflow_count();
if pending_reflows > 0 {
@@ -1396,6 +1400,7 @@ impl ScriptThread {
match *msg {
MixedMessage::FromConstellation(ref inner_msg) => {
match *inner_msg {
+ StopDelayingLoadEventsMode(id) => Some(id),
NavigationResponse(id, _) => Some(id),
AttachLayout(ref new_layout_info) => Some(new_layout_info.new_pipeline_id),
Resize(id, ..) => Some(id),
@@ -1533,6 +1538,9 @@ impl ScriptThread {
fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg) {
match msg {
+ ConstellationControlMsg::StopDelayingLoadEventsMode(pipeline_id) => {
+ self.handle_stop_delaying_load_events_mode(pipeline_id)
+ },
ConstellationControlMsg::NavigationResponse(id, fetch_data) => {
match fetch_data {
FetchResponseMsg::ProcessResponse(metadata) => {
@@ -2078,6 +2086,19 @@ impl ScriptThread {
}
}
+ fn handle_stop_delaying_load_events_mode(&self, pipeline_id: PipelineId) {
+ let window = self.documents.borrow().find_window(pipeline_id);
+ if let Some(window) = window {
+ match window.undiscarded_window_proxy() {
+ Some(window_proxy) => window_proxy.stop_delaying_load_events_mode(),
+ None => warn!(
+ "Attempted to take {} of 'delaying-load-events-mode' after having been discarded.",
+ pipeline_id
+ ),
+ };
+ }
+ }
+
fn handle_unload_document(&self, pipeline_id: PipelineId) {
let document = self.documents.borrow().find_document(pipeline_id);
if let Some(document) = document {
@@ -2164,6 +2185,20 @@ impl ScriptThread {
status: Some((204...205, _)),
..
}) => {
+ // If we have an existing window that is being navigated:
+ if let Some(window) = self.documents.borrow().find_window(id.clone()) {
+ let window_proxy = window.window_proxy();
+ // https://html.spec.whatwg.org/multipage/
+ // #navigating-across-documents:delaying-load-events-mode-2
+ if window_proxy.parent().is_some() {
+ // The user agent must take this nested browsing context
+ // out of the delaying load events mode
+ // when this navigation algorithm later matures,
+ // or when it terminates (whether due to having run all the steps,
+ // or being canceled, or being aborted), whichever happens first.
+ window_proxy.stop_delaying_load_events_mode();
+ }
+ }
self.script_sender
.send((id.clone(), ScriptMsg::AbortLoadUrl))
.unwrap();
@@ -2708,6 +2743,13 @@ impl ScriptThread {
incomplete.parent_info,
incomplete.opener,
);
+ if window_proxy.parent().is_some() {
+ // https://html.spec.whatwg.org/multipage/#navigating-across-documents:delaying-load-events-mode-2
+ // The user agent must take this nested browsing context
+ // out of the delaying load events mode
+ // when this navigation algorithm later matures.
+ window_proxy.stop_delaying_load_events_mode();
+ }
window.init_window_proxy(&window_proxy);
let last_modified = metadata.headers.as_ref().and_then(|headers| {
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index 45e31ca3a0a..5f450a65911 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -246,6 +246,10 @@ pub enum UpdatePipelineIdReason {
/// Messages sent from the constellation or layout to the script thread.
#[derive(Deserialize, Serialize)]
pub enum ConstellationControlMsg {
+ /// Takes the associated window proxy out of "delaying-load-events-mode",
+ /// used if a scheduled navigated was refused by the embedder.
+ /// https://html.spec.whatwg.org/multipage/#delaying-load-events-mode
+ StopDelayingLoadEventsMode(PipelineId),
/// Sends the final response to script thread for fetching after all redirections
/// have been resolved
NavigationResponse(PipelineId, FetchResponseMsg),
@@ -338,6 +342,7 @@ impl fmt::Debug for ConstellationControlMsg {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
use self::ConstellationControlMsg::*;
let variant = match *self {
+ StopDelayingLoadEventsMode(..) => "StopDelayingLoadsEventMode",
NavigationResponse(..) => "NavigationResponse",
AttachLayout(..) => "AttachLayout",
Resize(..) => "Resize",
@@ -724,6 +729,8 @@ pub enum ConstellationMsg {
IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
/// Inform the constellation of a key event.
Keyboard(KeyboardEvent),
+ /// Whether to allow script to navigate.
+ AllowNavigationResponse(PipelineId, bool),
/// Request to load a page.
LoadUrl(TopLevelBrowsingContextId, ServoUrl),
/// Request to traverse the joint session history of the provided browsing context.
@@ -768,6 +775,7 @@ impl fmt::Debug for ConstellationMsg {
GetFocusTopLevelBrowsingContext(..) => "GetFocusTopLevelBrowsingContext",
IsReadyToSaveImage(..) => "IsReadyToSaveImage",
Keyboard(..) => "Keyboard",
+ AllowNavigationResponse(..) => "AllowNavigationResponse",
LoadUrl(..) => "LoadUrl",
TraverseHistory(..) => "TraverseHistory",
WindowSize(..) => "WindowSize",
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index 1ec91142aa6..a4618c28307 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -279,6 +279,16 @@ where
self.compositor.on_resize_window_event();
},
+ WindowEvent::AllowNavigationResponse(pipeline_id, allowed) => {
+ let msg = ConstellationMsg::AllowNavigationResponse(pipeline_id, allowed);
+ if let Err(e) = self.constellation_chan.send(msg) {
+ warn!(
+ "Sending allow navigation to constellation failed ({:?}).",
+ e
+ );
+ }
+ },
+
WindowEvent::LoadUrl(top_level_browsing_context_id, url) => {
let msg = ConstellationMsg::LoadUrl(top_level_browsing_context_id, url);
if let Err(e) = self.constellation_chan.send(msg) {