mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
Compare commits
21 Commits
8ced3d1b8e
...
iframe-loa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e37cacce2d | ||
|
|
d90ca0bc53 | ||
|
|
6aad25dc25 | ||
|
|
4352b4c7ff | ||
|
|
bff5123a99 | ||
|
|
52e1b19c5c | ||
|
|
4aef4d48be | ||
|
|
8daf551654 | ||
|
|
225b581fe5 | ||
|
|
6aca6d30f7 | ||
|
|
2d2e34167e | ||
|
|
addcddf960 | ||
|
|
e22b68349b | ||
|
|
45bdc0f776 | ||
|
|
f6ba2a77c0 | ||
|
|
28c27ff835 | ||
|
|
a25beae1f1 | ||
|
|
441266a000 | ||
|
|
6a3b468623 | ||
|
|
004aa169fd | ||
|
|
9976f0e65b |
@@ -944,7 +944,6 @@ where
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new_pipeline(
|
||||
&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
browsing_context_id: BrowsingContextId,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
parent_pipeline_id: Option<PipelineId>,
|
||||
@@ -962,6 +961,7 @@ where
|
||||
if self.shutting_down {
|
||||
return;
|
||||
}
|
||||
let pipeline_id = load_data.new_pipeline_id.clone();
|
||||
debug!(
|
||||
"{}: Creating new pipeline in {}",
|
||||
pipeline_id, browsing_context_id
|
||||
@@ -1431,6 +1431,8 @@ where
|
||||
Referrer::NoReferrer,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let ctx_id = BrowsingContextId::from(top_level_browsing_context_id);
|
||||
let pipeline_id = match self.browsing_contexts.get(&ctx_id) {
|
||||
@@ -1676,8 +1678,8 @@ where
|
||||
self.handle_abort_load_url_msg(source_pipeline_id);
|
||||
},
|
||||
// A page loaded has completed all parsing, script, and reflow messages have been sent.
|
||||
FromScriptMsg::LoadComplete => {
|
||||
self.handle_load_complete_msg(source_top_ctx_id, source_pipeline_id)
|
||||
FromScriptMsg::LoadComplete(is_initial_about_blank) => {
|
||||
self.handle_load_complete_msg(source_top_ctx_id, source_pipeline_id, is_initial_about_blank)
|
||||
},
|
||||
// Handle navigating to a fragment
|
||||
FromScriptMsg::NavigatedToFragment(new_url, replacement_enabled) => {
|
||||
@@ -2867,6 +2869,7 @@ where
|
||||
|
||||
let new_pipeline_id = PipelineId::new();
|
||||
let new_load_data = LoadData {
|
||||
new_pipeline_id,
|
||||
crash: Some(
|
||||
backtrace
|
||||
.map(|b| format!("{}\n{}", reason, b))
|
||||
@@ -2878,7 +2881,6 @@ where
|
||||
let sandbox = IFrameSandboxState::IFrameSandboxed;
|
||||
let is_private = false;
|
||||
self.new_pipeline(
|
||||
new_pipeline_id,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
None,
|
||||
@@ -2988,7 +2990,6 @@ where
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
) {
|
||||
let window_size = self.window_size.initial_viewport;
|
||||
let pipeline_id = PipelineId::new();
|
||||
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
||||
let load_data = LoadData::new(
|
||||
LoadOrigin::Constellation,
|
||||
@@ -2997,7 +2998,10 @@ where
|
||||
Referrer::NoReferrer,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let pipeline_id = load_data.new_pipeline_id.clone();
|
||||
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
|
||||
let is_private = false;
|
||||
let throttled = false;
|
||||
@@ -3022,7 +3026,6 @@ where
|
||||
.insert(new_bc_group_id, new_bc_group);
|
||||
|
||||
self.new_pipeline(
|
||||
pipeline_id,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
None,
|
||||
@@ -3113,7 +3116,7 @@ where
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self), fields(servo_profiling = true))]
|
||||
fn handle_subframe_loaded(&mut self, pipeline_id: PipelineId) {
|
||||
fn handle_subframe_loaded(&mut self, pipeline_id: PipelineId, is_initial_about_blank: bool) {
|
||||
let browsing_context_id = match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => pipeline.browsing_context_id,
|
||||
None => return warn!("{}: Subframe loaded after closure", pipeline_id),
|
||||
@@ -3138,6 +3141,7 @@ where
|
||||
target: browsing_context_id,
|
||||
parent: parent_pipeline_id,
|
||||
child: pipeline_id,
|
||||
is_initial_about_blank,
|
||||
};
|
||||
let result = match self.pipelines.get(&parent_pipeline_id) {
|
||||
Some(parent) => parent.event_loop.send(msg),
|
||||
@@ -3180,7 +3184,6 @@ where
|
||||
parent_pipeline_id,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
new_pipeline_id,
|
||||
is_private,
|
||||
mut replace,
|
||||
..
|
||||
@@ -3191,6 +3194,8 @@ where
|
||||
.old_pipeline_id
|
||||
.and_then(|id| self.pipelines.get(&id));
|
||||
|
||||
let new_pipeline_id = load_info.load_data.new_pipeline_id.clone();
|
||||
|
||||
// Replacement enabled also takes into account whether the document is "completely loaded",
|
||||
// see https://html.spec.whatwg.org/multipage/#the-iframe-element:completely-loaded
|
||||
if let Some(old_pipeline) = old_pipeline {
|
||||
@@ -3259,7 +3264,6 @@ where
|
||||
|
||||
// Create the new pipeline, attached to the parent and push to pending changes
|
||||
self.new_pipeline(
|
||||
new_pipeline_id,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
Some(parent_pipeline_id),
|
||||
@@ -3285,13 +3289,14 @@ where
|
||||
fn handle_script_new_iframe(&mut self, load_info: IFrameLoadInfoWithData) {
|
||||
let IFrameLoadInfo {
|
||||
parent_pipeline_id,
|
||||
new_pipeline_id,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
is_private,
|
||||
..
|
||||
} = load_info.info;
|
||||
|
||||
let new_pipeline_id = load_info.load_data.new_pipeline_id.clone();
|
||||
|
||||
let (script_sender, parent_browsing_context_id) =
|
||||
match self.pipelines.get(&parent_pipeline_id) {
|
||||
Some(pipeline) => (pipeline.event_loop.clone(), pipeline.browsing_context_id),
|
||||
@@ -3349,10 +3354,11 @@ where
|
||||
opener_pipeline_id,
|
||||
new_top_level_browsing_context_id,
|
||||
new_browsing_context_id,
|
||||
new_pipeline_id,
|
||||
} = load_info;
|
||||
|
||||
let (script_sender, opener_browsing_context_id) =
|
||||
let new_pipeline_id = load_data.new_pipeline_id.clone();
|
||||
|
||||
let (_script_sender, opener_browsing_context_id) =
|
||||
match self.pipelines.get(&opener_pipeline_id) {
|
||||
Some(pipeline) => (pipeline.event_loop.clone(), pipeline.browsing_context_id),
|
||||
None => {
|
||||
@@ -3372,7 +3378,18 @@ where
|
||||
);
|
||||
},
|
||||
};
|
||||
let pipeline = Pipeline::new(
|
||||
self.new_pipeline(
|
||||
new_browsing_context_id,
|
||||
new_top_level_browsing_context_id,
|
||||
Some(opener_pipeline_id),
|
||||
Some(opener_browsing_context_id),
|
||||
self.window_size.initial_viewport,
|
||||
load_data,
|
||||
IFrameSandboxState::IFrameUnsandboxed, //XXXjdm
|
||||
is_opener_private,
|
||||
is_opener_throttled,
|
||||
);
|
||||
/*let pipeline = Pipeline::new(
|
||||
new_pipeline_id,
|
||||
new_browsing_context_id,
|
||||
new_top_level_browsing_context_id,
|
||||
@@ -3384,7 +3401,7 @@ where
|
||||
);
|
||||
|
||||
assert!(!self.pipelines.contains_key(&new_pipeline_id));
|
||||
self.pipelines.insert(new_pipeline_id, pipeline);
|
||||
self.pipelines.insert(new_pipeline_id, pipeline);*/
|
||||
self.webviews.add(
|
||||
new_top_level_browsing_context_id,
|
||||
WebView {
|
||||
@@ -3490,7 +3507,7 @@ where
|
||||
);
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
let _ = entry.insert((load_data.clone(), replace));
|
||||
let _ = entry.insert((load_data.clone(), if load_data.replacing_pipeline.is_some() { HistoryEntryReplacement::Enabled } else { replace }));
|
||||
},
|
||||
};
|
||||
// Allow the embedder to handle the url itself
|
||||
@@ -3531,6 +3548,7 @@ where
|
||||
return None;
|
||||
},
|
||||
};
|
||||
let new_pipeline_id = load_data.new_pipeline_id.clone();
|
||||
let (window_size, pipeline_id, parent_pipeline_id, is_private, is_throttled) =
|
||||
match self.browsing_contexts.get(&browsing_context_id) {
|
||||
Some(ctx) => (
|
||||
@@ -3602,10 +3620,8 @@ where
|
||||
HistoryEntryReplacement::Disabled => None,
|
||||
};
|
||||
|
||||
let new_pipeline_id = PipelineId::new();
|
||||
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
|
||||
self.new_pipeline(
|
||||
new_pipeline_id,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
None,
|
||||
@@ -3653,6 +3669,7 @@ where
|
||||
&mut self,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
pipeline_id: PipelineId,
|
||||
is_initial_about_blank: bool,
|
||||
) {
|
||||
let mut webdriver_reset = false;
|
||||
if let Some((expected_pipeline_id, ref reply_chan)) = self.webdriver.load_channel {
|
||||
@@ -3693,7 +3710,7 @@ where
|
||||
.send(CompositorMsg::LoadComplete(top_level_browsing_context_id));
|
||||
}
|
||||
} else {
|
||||
self.handle_subframe_loaded(pipeline_id);
|
||||
self.handle_subframe_loaded(pipeline_id, is_initial_about_blank);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3909,9 +3926,8 @@ where
|
||||
Some(pipeline) => pipeline.opener,
|
||||
None => None,
|
||||
};
|
||||
let new_pipeline_id = PipelineId::new();
|
||||
let new_pipeline_id = load_data.new_pipeline_id.clone();
|
||||
self.new_pipeline(
|
||||
new_pipeline_id,
|
||||
browsing_context_id,
|
||||
top_level_id,
|
||||
parent_pipeline_id,
|
||||
|
||||
@@ -229,10 +229,12 @@ impl Pipeline {
|
||||
window_size: state.window_size,
|
||||
};
|
||||
|
||||
if let Err(e) =
|
||||
script_chan.send(ConstellationControlMsg::AttachLayout(new_layout_info))
|
||||
{
|
||||
warn!("Sending to script during pipeline creation failed ({})", e);
|
||||
if !state.load_data.synchronously_loaded {
|
||||
if let Err(e) =
|
||||
script_chan.send(ConstellationControlMsg::AttachLayout(new_layout_info))
|
||||
{
|
||||
warn!("Sending to script during pipeline creation failed ({})", e);
|
||||
}
|
||||
}
|
||||
(script_chan, None)
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
@@ -156,7 +157,7 @@ mod from_script {
|
||||
Self::GetTopForBrowsingContext(..) => target!("GetTopForBrowsingContext"),
|
||||
Self::GetBrowsingContextInfo(..) => target!("GetBrowsingContextInfo"),
|
||||
Self::GetChildBrowsingContextId(..) => target!("GetChildBrowsingContextId"),
|
||||
Self::LoadComplete => target!("LoadComplete"),
|
||||
Self::LoadComplete(..) => target!("LoadComplete"),
|
||||
Self::LoadUrl(..) => target!("LoadUrl"),
|
||||
Self::AbortLoadUrl => target!("AbortLoadUrl"),
|
||||
Self::PostMessage { .. } => target!("PostMessage"),
|
||||
|
||||
@@ -262,7 +262,7 @@ impl CanvasState {
|
||||
CanvasImageSource::HTMLCanvasElement(canvas) => canvas.origin_is_clean(),
|
||||
CanvasImageSource::OffscreenCanvas(canvas) => canvas.origin_is_clean(),
|
||||
CanvasImageSource::HTMLImageElement(image) => {
|
||||
image.same_origin(GlobalScope::entry().origin())
|
||||
image.same_origin(&GlobalScope::entry().origin())
|
||||
},
|
||||
CanvasImageSource::CSSStyleValue(_) => true,
|
||||
}
|
||||
|
||||
@@ -3020,7 +3020,7 @@ create_global_object(
|
||||
raw.as_ptr() as *const libc::c_void,
|
||||
_trace,
|
||||
obj.handle_mut(),
|
||||
origin);
|
||||
&origin);
|
||||
assert!(!obj.is_null());
|
||||
|
||||
let root = raw.reflect_with(obj.get());
|
||||
|
||||
@@ -162,8 +162,7 @@ pub unsafe fn create_global_object(
|
||||
|
||||
// Initialize the reserved slots before doing anything that can GC, to
|
||||
// avoid getting trace hooks called on a partially initialized object.
|
||||
let private_val = PrivateValue(private);
|
||||
JS_SetReservedSlot(rval.get(), DOM_OBJECT_SLOT, &private_val);
|
||||
set_reflector_object(rval.handle(), private);
|
||||
let proto_array: Box<ProtoOrIfaceArray> =
|
||||
Box::new([ptr::null_mut::<JSObject>(); PrototypeList::PROTO_OR_IFACE_LENGTH]);
|
||||
let val = PrivateValue(Box::into_raw(proto_array) as *const libc::c_void);
|
||||
@@ -173,6 +172,11 @@ pub unsafe fn create_global_object(
|
||||
JS_FireOnNewGlobalObject(*cx, rval.handle());
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn set_reflector_object(reflector: HandleObject, private: *const libc::c_void) {
|
||||
let private_val = PrivateValue(private);
|
||||
JS_SetReservedSlot(reflector.get(), DOM_OBJECT_SLOT, &private_val);
|
||||
}
|
||||
|
||||
/// Choose the compartment to create a new global object in.
|
||||
fn select_compartment(cx: SafeJSContext, options: &mut RealmOptions) {
|
||||
type Data = *mut Compartment;
|
||||
|
||||
@@ -178,7 +178,7 @@ use crate::dom::wheelevent::WheelEvent;
|
||||
use crate::dom::window::{ReflowReason, Window};
|
||||
use crate::dom::windowproxy::WindowProxy;
|
||||
use crate::fetch::FetchCanceller;
|
||||
use crate::realms::{AlreadyInRealm, InRealm};
|
||||
use crate::realms::{AlreadyInRealm, InRealm, enter_realm};
|
||||
use crate::script_runtime::{CanGc, CommonScriptMsg, ScriptThreadEventCategory};
|
||||
use crate::script_thread::{MainThreadScriptMsg, ScriptThread};
|
||||
use crate::stylesheet_set::StylesheetSetRef;
|
||||
@@ -486,6 +486,9 @@ pub struct Document {
|
||||
visibility_state: Cell<DocumentVisibilityState>,
|
||||
/// <https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml>
|
||||
status_code: Option<u16>,
|
||||
inhibit_load_and_pageshow: Cell<bool>,
|
||||
window_replaced: Cell<bool>,
|
||||
is_initial_about_blank: Cell<bool>,
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
@@ -539,6 +542,10 @@ impl CollectionFilter for AnchorsFilter {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl Document {
|
||||
pub(crate) fn is_initial_about_blank(&self) -> bool {
|
||||
self.is_initial_about_blank.get()
|
||||
}
|
||||
|
||||
pub fn note_node_with_dirty_descendants(&self, node: &Node) {
|
||||
debug_assert!(*node.owner_doc() == *self);
|
||||
if !node.is_connected() {
|
||||
@@ -708,7 +715,9 @@ impl Document {
|
||||
ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
|
||||
|
||||
if activity != DocumentActivity::FullyActive {
|
||||
self.window().suspend();
|
||||
if self.is_window_relevant() {
|
||||
self.window().suspend();
|
||||
}
|
||||
media.suspend(&client_context_id);
|
||||
return;
|
||||
}
|
||||
@@ -2320,8 +2329,10 @@ impl Document {
|
||||
if !self.salvageable.get() {
|
||||
// Step 1 of clean-up steps.
|
||||
global_scope.close_event_sources();
|
||||
let msg = ScriptMsg::DiscardDocument;
|
||||
let _ = global_scope.script_to_constellation_chan().send(msg);
|
||||
if self.is_window_relevant() {
|
||||
let msg = ScriptMsg::DiscardDocument;
|
||||
let _ = global_scope.script_to_constellation_chan().send(msg);
|
||||
}
|
||||
}
|
||||
// https://w3c.github.io/FileAPI/#lifeTime
|
||||
global_scope.clean_up_all_file_resources();
|
||||
@@ -2358,17 +2369,20 @@ impl Document {
|
||||
// Step 7.
|
||||
debug!("Document loads are complete.");
|
||||
let document = Trusted::new(self);
|
||||
let was_initial_about_blank = self.is_initial_about_blank.get();
|
||||
self.window
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source()
|
||||
.queue(
|
||||
task!(fire_load_event: move || {
|
||||
task!(prepare_for_post_load_tasks: move || {
|
||||
let document = document.root();
|
||||
let window = document.window();
|
||||
if !window.is_alive() {
|
||||
return;
|
||||
}
|
||||
|
||||
notify_constellation_load(&window, was_initial_about_blank);
|
||||
|
||||
// Step 7.1.
|
||||
document.set_ready_state(DocumentReadyState::Complete);
|
||||
|
||||
@@ -2387,37 +2401,19 @@ impl Document {
|
||||
// http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventStart
|
||||
update_with_current_instant(&document.load_event_start);
|
||||
|
||||
debug!("About to dispatch load for {:?}", document.url());
|
||||
// FIXME(nox): Why are errors silenced here?
|
||||
let _ = window.dispatch_event_with_target_override(
|
||||
&event,
|
||||
);
|
||||
if !document.inhibit_load_and_pageshow.get() {
|
||||
debug!("About to dispatch load for {:?}", document.url());
|
||||
// FIXME(nox): Why are errors silenced here?
|
||||
let _ = window.dispatch_event_with_target_override(
|
||||
&event,
|
||||
);
|
||||
}
|
||||
|
||||
// http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventEnd
|
||||
update_with_current_instant(&document.load_event_end);
|
||||
|
||||
if let Some(fragment) = document.url().fragment() {
|
||||
document.check_and_scroll_fragment(fragment);
|
||||
}
|
||||
}),
|
||||
self.window.upcast(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Step 8.
|
||||
let document = Trusted::new(self);
|
||||
if document.root().browsing_context().is_some() {
|
||||
self.window
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source()
|
||||
.queue(
|
||||
task!(fire_pageshow_event: move || {
|
||||
let document = document.root();
|
||||
let window = document.window();
|
||||
if document.page_showing.get() || !window.is_alive() {
|
||||
return;
|
||||
}
|
||||
|
||||
//assert!(!document.page_showing.get());
|
||||
if !document.page_showing.get() {
|
||||
document.page_showing.set(true);
|
||||
|
||||
let event = PageTransitionEvent::new(
|
||||
@@ -2434,11 +2430,15 @@ impl Document {
|
||||
let _ = window.dispatch_event_with_target_override(
|
||||
event,
|
||||
);
|
||||
}),
|
||||
self.window.upcast(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fragment) = document.url().fragment() {
|
||||
document.check_and_scroll_fragment(fragment);
|
||||
}
|
||||
}),
|
||||
self.window.upcast(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Step 9.
|
||||
// TODO: pending application cache download process tasks.
|
||||
@@ -2482,10 +2482,10 @@ impl Document {
|
||||
}),
|
||||
Duration::from_secs(*time),
|
||||
);
|
||||
}
|
||||
};
|
||||
// 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();
|
||||
//document.notify_constellation_load();
|
||||
}),
|
||||
self.window.upcast(),
|
||||
)
|
||||
@@ -2641,9 +2641,10 @@ impl Document {
|
||||
.dom_manipulation_task_source()
|
||||
.queue(
|
||||
task!(fire_dom_content_loaded_event: move || {
|
||||
let document = document.root();
|
||||
document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"));
|
||||
update_with_current_instant(&document.dom_content_loaded_event_end);
|
||||
let document = document.root();
|
||||
let _realm = enter_realm(&*document);
|
||||
document.upcast::<EventTarget>().fire_bubbling_event(atom!("DOMContentLoaded"));
|
||||
update_with_current_instant(&document.dom_content_loaded_event_end);
|
||||
}),
|
||||
window.upcast(),
|
||||
)
|
||||
@@ -2701,10 +2702,6 @@ impl Document {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify_constellation_load(&self) {
|
||||
self.window().send_to_constellation(ScriptMsg::LoadComplete);
|
||||
}
|
||||
|
||||
pub fn set_current_parser(&self, script: Option<&ServoParser>) {
|
||||
self.current_parser.set(script);
|
||||
}
|
||||
@@ -3180,6 +3177,7 @@ impl Document {
|
||||
referrer_policy: Option<ReferrerPolicy>,
|
||||
status_code: Option<u16>,
|
||||
canceller: FetchCanceller,
|
||||
inhibit_load_and_pageshow: bool,
|
||||
) -> Document {
|
||||
let url = url.unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap());
|
||||
|
||||
@@ -3206,6 +3204,7 @@ impl Document {
|
||||
.and_then(|charset| Encoding::for_label(charset.as_str().as_bytes()))
|
||||
.unwrap_or(UTF_8);
|
||||
|
||||
let is_initial_about_blank = url.as_str() == "about:blank";
|
||||
let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
|
||||
Document {
|
||||
node: Node::new_document_node(),
|
||||
@@ -3327,9 +3326,20 @@ impl Document {
|
||||
fonts: Default::default(),
|
||||
visibility_state: Cell::new(DocumentVisibilityState::Hidden),
|
||||
status_code,
|
||||
inhibit_load_and_pageshow: Cell::new(inhibit_load_and_pageshow),
|
||||
window_replaced: Cell::new(false),
|
||||
is_initial_about_blank: Cell::new(is_initial_about_blank),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn disown_window(&self) {
|
||||
self.window_replaced.set(true);
|
||||
}
|
||||
|
||||
pub(crate) fn is_window_relevant(&self) -> bool {
|
||||
!self.window_replaced.get()
|
||||
}
|
||||
|
||||
/// Note a pending animation tick, to be processed at the next `update_the_rendering` task.
|
||||
pub fn note_pending_animation_tick(&self, tick_type: AnimationTickType) {
|
||||
self.pending_animation_ticks.borrow_mut().extend(tick_type);
|
||||
@@ -3475,6 +3485,7 @@ impl Document {
|
||||
None,
|
||||
Default::default(),
|
||||
can_gc,
|
||||
false,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -3495,6 +3506,7 @@ impl Document {
|
||||
status_code: Option<u16>,
|
||||
canceller: FetchCanceller,
|
||||
can_gc: CanGc,
|
||||
inhibit_load_and_pageshow: bool,
|
||||
) -> DomRoot<Document> {
|
||||
Self::new_with_proto(
|
||||
window,
|
||||
@@ -3513,6 +3525,7 @@ impl Document {
|
||||
status_code,
|
||||
canceller,
|
||||
can_gc,
|
||||
inhibit_load_and_pageshow,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3534,6 +3547,7 @@ impl Document {
|
||||
status_code: Option<u16>,
|
||||
canceller: FetchCanceller,
|
||||
can_gc: CanGc,
|
||||
inhibit_load_and_pageshow: bool,
|
||||
) -> DomRoot<Document> {
|
||||
let document = reflect_dom_object_with_proto(
|
||||
Box::new(Document::new_inherited(
|
||||
@@ -3551,6 +3565,7 @@ impl Document {
|
||||
referrer_policy,
|
||||
status_code,
|
||||
canceller,
|
||||
inhibit_load_and_pageshow,
|
||||
)),
|
||||
window,
|
||||
proto,
|
||||
@@ -3676,6 +3691,7 @@ impl Document {
|
||||
None,
|
||||
Default::default(),
|
||||
can_gc,
|
||||
false,
|
||||
);
|
||||
new_doc
|
||||
.appropriate_template_contents_owner_document
|
||||
@@ -5277,12 +5293,16 @@ impl DocumentMethods for Document {
|
||||
self.set_url(new_url);
|
||||
}
|
||||
|
||||
self.inhibit_load_and_pageshow.set(false);
|
||||
|
||||
// Step 13
|
||||
// TODO: https://github.com/servo/servo/issues/21938
|
||||
|
||||
// Step 14
|
||||
self.set_quirks_mode(QuirksMode::NoQuirks);
|
||||
|
||||
self.is_initial_about_blank.set(false);
|
||||
|
||||
// Step 15
|
||||
let resource_threads = self
|
||||
.window
|
||||
@@ -5652,3 +5672,8 @@ fn is_named_element_with_id_attribute(elem: &Element) -> bool {
|
||||
// behaviour is actually implemented
|
||||
elem.is::<HTMLImageElement>() && elem.get_name().is_some_and(|name| !name.is_empty())
|
||||
}
|
||||
|
||||
fn notify_constellation_load(window: &Window, is_initial_about_blank: bool) {
|
||||
window.send_to_constellation(ScriptMsg::LoadComplete(is_initial_about_blank));
|
||||
}
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||
None,
|
||||
Default::default(),
|
||||
can_gc,
|
||||
false,
|
||||
);
|
||||
|
||||
{
|
||||
|
||||
@@ -89,6 +89,7 @@ impl DOMParserMethods for DOMParser {
|
||||
None,
|
||||
Default::default(),
|
||||
can_gc,
|
||||
false,
|
||||
);
|
||||
ServoParser::parse_html_document(&document, Some(s), url, CanGc::note());
|
||||
document.set_ready_state(DocumentReadyState::Complete);
|
||||
@@ -111,6 +112,7 @@ impl DOMParserMethods for DOMParser {
|
||||
None,
|
||||
Default::default(),
|
||||
can_gc,
|
||||
false,
|
||||
);
|
||||
ServoParser::parse_xml_document(&document, Some(s), url, CanGc::note());
|
||||
document.set_ready_state(DocumentReadyState::Complete);
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::cell::{Cell, RefCell, Ref};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::ops::Index;
|
||||
use std::ops::{Deref, Index};
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
@@ -208,7 +208,7 @@ pub struct GlobalScope {
|
||||
|
||||
/// Pipeline id associated with this global.
|
||||
#[no_trace]
|
||||
pipeline_id: PipelineId,
|
||||
pipeline_id: Cell<PipelineId>,
|
||||
|
||||
/// A flag to indicate whether the developer tools has requested
|
||||
/// live updates from the worker.
|
||||
@@ -243,7 +243,7 @@ pub struct GlobalScope {
|
||||
/// A handle for communicating messages to the constellation thread.
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
script_to_constellation_chan: ScriptToConstellationChan,
|
||||
script_to_constellation_chan: RefCell<ScriptToConstellationChan>,
|
||||
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
@@ -266,11 +266,11 @@ pub struct GlobalScope {
|
||||
|
||||
/// The origin of the globalscope
|
||||
#[no_trace]
|
||||
origin: MutableOrigin,
|
||||
origin: RefCell<MutableOrigin>,
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#concept-environment-creation-url>
|
||||
#[no_trace]
|
||||
creation_url: Option<ServoUrl>,
|
||||
creation_url: RefCell<Option<ServoUrl>>,
|
||||
|
||||
/// A map for storing the previous permission state read results.
|
||||
permission_state_invocation_results: DomRefCell<HashMap<String, PermissionState>>,
|
||||
@@ -779,7 +779,7 @@ impl GlobalScope {
|
||||
crypto: Default::default(),
|
||||
registration_map: DomRefCell::new(HashMapTracedValues::new()),
|
||||
worker_map: DomRefCell::new(HashMapTracedValues::new()),
|
||||
pipeline_id,
|
||||
pipeline_id: Cell::new(pipeline_id),
|
||||
devtools_wants_updates: Default::default(),
|
||||
console_timers: DomRefCell::new(Default::default()),
|
||||
module_map: DomRefCell::new(Default::default()),
|
||||
@@ -787,14 +787,14 @@ impl GlobalScope {
|
||||
devtools_chan,
|
||||
mem_profiler_chan,
|
||||
time_profiler_chan,
|
||||
script_to_constellation_chan,
|
||||
script_to_constellation_chan: RefCell::new(script_to_constellation_chan),
|
||||
scheduler_chan: scheduler_chan.clone(),
|
||||
in_error_reporting_mode: Default::default(),
|
||||
resource_threads,
|
||||
timers: OneshotTimers::new(scheduler_chan),
|
||||
init_timers: Default::default(),
|
||||
origin,
|
||||
creation_url,
|
||||
origin: RefCell::new(origin),
|
||||
creation_url: RefCell::new(creation_url),
|
||||
permission_state_invocation_results: Default::default(),
|
||||
microtask_queue,
|
||||
list_auto_close_worker: Default::default(),
|
||||
@@ -2318,7 +2318,7 @@ impl GlobalScope {
|
||||
pub fn issue_page_warning(&self, warning: &str) {
|
||||
if let Some(ref chan) = self.devtools_chan {
|
||||
let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
|
||||
self.pipeline_id,
|
||||
self.pipeline_id.get(),
|
||||
PageError {
|
||||
type_: "PageError".to_string(),
|
||||
error_message: warning.to_string(),
|
||||
@@ -2352,8 +2352,8 @@ impl GlobalScope {
|
||||
}
|
||||
|
||||
/// Get a sender to the constellation thread.
|
||||
pub fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan {
|
||||
&self.script_to_constellation_chan
|
||||
pub fn script_to_constellation_chan(&self) -> Ref<ScriptToConstellationChan> {
|
||||
self.script_to_constellation_chan.borrow()
|
||||
}
|
||||
|
||||
pub fn send_to_embedder(&self, msg: EmbedderMsg) {
|
||||
@@ -2370,17 +2370,17 @@ impl GlobalScope {
|
||||
|
||||
/// Get the `PipelineId` for this global scope.
|
||||
pub fn pipeline_id(&self) -> PipelineId {
|
||||
self.pipeline_id
|
||||
self.pipeline_id.get()
|
||||
}
|
||||
|
||||
/// Get the origin for this global scope
|
||||
pub fn origin(&self) -> &MutableOrigin {
|
||||
&self.origin
|
||||
pub fn origin(&self) -> Ref<MutableOrigin> {
|
||||
self.origin.borrow()
|
||||
}
|
||||
|
||||
/// Get the creation_url for this global scope
|
||||
pub fn creation_url(&self) -> &Option<ServoUrl> {
|
||||
&self.creation_url
|
||||
pub fn creation_url(&self) -> Ref<Option<ServoUrl>> {
|
||||
self.creation_url.borrow()
|
||||
}
|
||||
|
||||
pub fn image_cache(&self) -> Arc<dyn ImageCache> {
|
||||
@@ -2513,7 +2513,7 @@ impl GlobalScope {
|
||||
} else if self.is::<Window>() {
|
||||
if let Some(ref chan) = self.devtools_chan {
|
||||
let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
|
||||
self.pipeline_id,
|
||||
self.pipeline_id.get(),
|
||||
PageError {
|
||||
type_: "PageError".to_string(),
|
||||
error_message: error_info.message.clone(),
|
||||
@@ -3129,7 +3129,7 @@ impl GlobalScope {
|
||||
if Some(false) == self.inherited_secure_context {
|
||||
return false;
|
||||
}
|
||||
if let Some(creation_url) = self.creation_url() {
|
||||
if let Some(creation_url) = self.creation_url().deref() {
|
||||
if creation_url.scheme() == "blob" && Some(true) == self.inherited_secure_context {
|
||||
return true;
|
||||
}
|
||||
@@ -3400,6 +3400,27 @@ impl GlobalScope {
|
||||
|
||||
Ok(message_clone.get())
|
||||
}
|
||||
|
||||
pub(crate) fn replace_contents(&self, data: ReplaceData) {
|
||||
let ReplaceData {
|
||||
pipeline_id,
|
||||
script_to_constellation_chan,
|
||||
creator_url,
|
||||
origin,
|
||||
} = data;
|
||||
self.pipeline_id.set(pipeline_id);
|
||||
*self.script_to_constellation_chan.borrow_mut() = script_to_constellation_chan;
|
||||
*self.creation_url.borrow_mut() = Some(creator_url);
|
||||
*self.origin.borrow_mut() = origin;
|
||||
self.timers.reset();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ReplaceData {
|
||||
pub pipeline_id: PipelineId,
|
||||
pub script_to_constellation_chan: ScriptToConstellationChan,
|
||||
pub creator_url: ServoUrl,
|
||||
pub origin: MutableOrigin,
|
||||
}
|
||||
|
||||
/// Returns the Rust global scope from a JS global object.
|
||||
|
||||
@@ -63,6 +63,7 @@ use crate::dom::htmldatalistelement::HTMLDataListElement;
|
||||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::htmlfieldsetelement::HTMLFieldSetElement;
|
||||
use crate::dom::htmlformcontrolscollection::HTMLFormControlsCollection;
|
||||
use crate::dom::htmliframeelement::HTMLIFrameElement;
|
||||
use crate::dom::htmlimageelement::HTMLImageElement;
|
||||
use crate::dom::htmlinputelement::{HTMLInputElement, InputType};
|
||||
use crate::dom::htmllabelelement::HTMLLabelElement;
|
||||
@@ -831,6 +832,8 @@ impl HTMLFormElement {
|
||||
target_window.upcast::<GlobalScope>().get_referrer(),
|
||||
target_document.get_referrer_policy(),
|
||||
Some(target_window.upcast::<GlobalScope>().is_secure_context()),
|
||||
(doc.url().as_str() == "about:blank").then(|| doc.window().pipeline_id()),
|
||||
false,
|
||||
);
|
||||
|
||||
// Step 22
|
||||
@@ -988,6 +991,14 @@ impl HTMLFormElement {
|
||||
load_data.referrer = referrer;
|
||||
load_data.referrer_policy = referrer_policy;
|
||||
|
||||
let new_pipeline_id = load_data.new_pipeline_id.clone();
|
||||
let proxy = target.window_proxy();
|
||||
if let Some(frame) = proxy.frame_element() {
|
||||
if let Some(frame) = frame.downcast::<HTMLIFrameElement>() {
|
||||
frame.update_pending_pipeline_id(new_pipeline_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4.
|
||||
let this = Trusted::new(self);
|
||||
let window = Trusted::new(target);
|
||||
|
||||
@@ -8,6 +8,7 @@ use base::id::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
|
||||
use bitflags::bitflags;
|
||||
use dom_struct::dom_struct;
|
||||
use html5ever::{local_name, namespace_url, ns, LocalName, Prefix};
|
||||
use js::jsapi::JSAutoRealm;
|
||||
use js::rust::HandleObject;
|
||||
use profile_traits::ipc as ProfiledIpc;
|
||||
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
||||
@@ -40,6 +41,8 @@ use crate::dom::node::{
|
||||
};
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::dom::windowproxy::WindowProxy;
|
||||
use crate::microtask::{Microtask, MicrotaskRunnable};
|
||||
use crate::realms::enter_realm;
|
||||
use crate::script_runtime::CanGc;
|
||||
use crate::script_thread::ScriptThread;
|
||||
|
||||
@@ -177,7 +180,7 @@ impl HTMLIFrameElement {
|
||||
|
||||
let window = window_from_node(self);
|
||||
let old_pipeline_id = self.pipeline_id();
|
||||
let new_pipeline_id = PipelineId::new();
|
||||
let new_pipeline_id = load_data.new_pipeline_id.clone();
|
||||
self.pending_pipeline_id.set(Some(new_pipeline_id));
|
||||
|
||||
let global_scope = window.upcast::<GlobalScope>();
|
||||
@@ -185,7 +188,6 @@ impl HTMLIFrameElement {
|
||||
parent_pipeline_id: global_scope.pipeline_id(),
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
new_pipeline_id,
|
||||
is_private: false, // FIXME
|
||||
inherited_secure_context: load_data.inherited_secure_context,
|
||||
replace,
|
||||
@@ -261,6 +263,8 @@ impl HTMLIFrameElement {
|
||||
window.upcast::<GlobalScope>().get_referrer(),
|
||||
document.get_referrer_policy(),
|
||||
Some(window.upcast::<GlobalScope>().is_secure_context()),
|
||||
None, //XXXjdm
|
||||
false,
|
||||
);
|
||||
let element = self.upcast::<Element>();
|
||||
load_data.srcdoc = String::from(element.get_string_attribute(&local_name!("srcdoc")));
|
||||
@@ -288,9 +292,14 @@ impl HTMLIFrameElement {
|
||||
}
|
||||
}
|
||||
|
||||
if mode == ProcessingMode::FirstTime &&
|
||||
!self.upcast::<Element>().has_attribute(&local_name!("src"))
|
||||
{
|
||||
let element = self.upcast::<Element>();
|
||||
let src = element.get_string_attribute(&local_name!("src"));
|
||||
if mode == ProcessingMode::FirstTime && (src.is_empty() || src == "about:blank") {
|
||||
let task = IframeElementMicrotask {
|
||||
elem: DomRoot::from_ref(self),
|
||||
about_blank_pipeline: self.about_blank_pipeline_id.get().unwrap(),
|
||||
};
|
||||
ScriptThread::await_stable_state(Microtask::IframeElement(task));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -332,6 +341,9 @@ impl HTMLIFrameElement {
|
||||
};
|
||||
|
||||
let document = document_from_node(self);
|
||||
let pipeline_id = self.pipeline_id();
|
||||
let is_about_blank = pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get();
|
||||
let replaced_pipeline = is_about_blank.then(|| self.about_blank_pipeline_id.get().unwrap());
|
||||
let load_data = LoadData::new(
|
||||
LoadOrigin::Script(document.origin().immutable().clone()),
|
||||
url,
|
||||
@@ -339,13 +351,12 @@ impl HTMLIFrameElement {
|
||||
window.upcast::<GlobalScope>().get_referrer(),
|
||||
document.get_referrer_policy(),
|
||||
Some(window.upcast::<GlobalScope>().is_secure_context()),
|
||||
replaced_pipeline,
|
||||
false,
|
||||
);
|
||||
|
||||
let pipeline_id = self.pipeline_id();
|
||||
// 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();
|
||||
let replace = if is_about_blank {
|
||||
HistoryEntryReplacement::Enabled
|
||||
} else {
|
||||
@@ -381,6 +392,8 @@ impl HTMLIFrameElement {
|
||||
window.upcast::<GlobalScope>().get_referrer(),
|
||||
document.get_referrer_policy(),
|
||||
Some(window.upcast::<GlobalScope>().is_secure_context()),
|
||||
None,
|
||||
true,
|
||||
);
|
||||
let browsing_context_id = BrowsingContextId::new();
|
||||
let top_level_browsing_context_id = window.window_proxy().top_level_browsing_context_id();
|
||||
@@ -405,6 +418,10 @@ impl HTMLIFrameElement {
|
||||
self.browsing_context_id.set(None);
|
||||
}
|
||||
|
||||
pub(crate) fn update_pending_pipeline_id(&self, pending: PipelineId) {
|
||||
self.pending_pipeline_id.set(Some(pending));
|
||||
}
|
||||
|
||||
pub fn update_pipeline_id(
|
||||
&self,
|
||||
new_pipeline_id: PipelineId,
|
||||
@@ -488,13 +505,24 @@ impl HTMLIFrameElement {
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#iframe-load-event-steps> steps 1-4
|
||||
pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId, can_gc: CanGc) {
|
||||
pub fn iframe_load_event_steps(
|
||||
&self,
|
||||
loaded_pipeline: PipelineId,
|
||||
can_gc: CanGc,
|
||||
dispatch_load_for_about_blank: bool,
|
||||
) {
|
||||
// TODO(#9592): assert that the load blocker is present at all times when we
|
||||
// can guarantee that it's created for the case of iframe.reload().
|
||||
if Some(loaded_pipeline) != self.pending_pipeline_id.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
if Some(loaded_pipeline) == self.about_blank_pipeline_id.get() &&
|
||||
!dispatch_load_for_about_blank
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO A cross-origin child document would not be easily accessible
|
||||
// from this script thread. It's unclear how to implement
|
||||
// steps 2, 3, and 5 efficiently in this case.
|
||||
@@ -788,3 +816,21 @@ impl VirtualMethods for HTMLIFrameElement {
|
||||
self.destroy_nested_browsing_context();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
pub struct IframeElementMicrotask {
|
||||
elem: DomRoot<HTMLIFrameElement>,
|
||||
#[no_trace]
|
||||
about_blank_pipeline: PipelineId,
|
||||
}
|
||||
|
||||
impl MicrotaskRunnable for IframeElementMicrotask {
|
||||
fn handler(&self, can_gc: CanGc) {
|
||||
self.elem
|
||||
.iframe_load_event_steps(self.about_blank_pipeline, can_gc, true);
|
||||
}
|
||||
|
||||
fn enter_realm(&self) -> JSAutoRealm {
|
||||
enter_realm(&*self.elem)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::Ref;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use net_traits::request::Referrer;
|
||||
use script_traits::{HistoryEntryReplacement, LoadData, LoadOrigin};
|
||||
@@ -123,6 +125,8 @@ impl Location {
|
||||
referrer,
|
||||
referrer_policy,
|
||||
None, // Top navigation doesn't inherit secure context
|
||||
(self.window.Document().url().as_str() == "about:blank").then(|| self.window.pipeline_id()),
|
||||
false,
|
||||
);
|
||||
self.window
|
||||
.load_url(replacement_flag, reload_triggered, load_data);
|
||||
@@ -249,7 +253,7 @@ impl Location {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn origin(&self) -> &MutableOrigin {
|
||||
pub fn origin(&self) -> Ref<MutableOrigin> {
|
||||
self.window.origin()
|
||||
}
|
||||
}
|
||||
@@ -389,11 +393,14 @@ impl LocationMethods for Location {
|
||||
if self.has_document() {
|
||||
// Note: no call to self.check_same_origin_domain()
|
||||
// Step 2: Parse the given value relative to the entry settings object.
|
||||
// If that failed, throw a TypeError exception.
|
||||
// If that failed, throw a SyntaxError exception.
|
||||
let base_url = self.entry_settings_object().api_base_url();
|
||||
let url = match base_url.join(&value.0) {
|
||||
Ok(url) => url,
|
||||
Err(e) => return Err(Error::Type(format!("Couldn't parse URL: {}", e))),
|
||||
Err(e) => {
|
||||
info!("Couldn't parse URL: {}", e);
|
||||
return Err(Error::Syntax);
|
||||
}
|
||||
};
|
||||
// Step 3: Location-object navigate to the resulting URL record.
|
||||
self.navigate(
|
||||
|
||||
@@ -2299,6 +2299,7 @@ impl Node {
|
||||
document.status_code(),
|
||||
Default::default(),
|
||||
CanGc::note(),
|
||||
false,
|
||||
);
|
||||
DomRoot::upcast::<Node>(document)
|
||||
},
|
||||
|
||||
@@ -216,6 +216,7 @@ impl ServoParser {
|
||||
None,
|
||||
Default::default(),
|
||||
can_gc,
|
||||
false,
|
||||
);
|
||||
|
||||
// Step 2.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::{Cow, ToOwned};
|
||||
use std::cell::{Cell, RefCell, RefMut};
|
||||
use std::cell::{Cell, RefCell, RefMut, Ref as StdRef};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::default::Default;
|
||||
@@ -185,7 +185,7 @@ pub struct Window {
|
||||
globalscope: GlobalScope,
|
||||
#[ignore_malloc_size_of = "trait objects are hard"]
|
||||
script_chan: MainThreadScriptChan,
|
||||
task_manager: TaskManager,
|
||||
task_manager: RefCell<TaskManager>,
|
||||
#[no_trace]
|
||||
#[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"]
|
||||
layout: RefCell<Box<dyn Layout>>,
|
||||
@@ -357,8 +357,8 @@ pub struct Window {
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn task_manager(&self) -> &TaskManager {
|
||||
&self.task_manager
|
||||
pub fn task_manager(&self) -> StdRef<TaskManager> {
|
||||
self.task_manager.borrow()
|
||||
}
|
||||
|
||||
pub fn layout(&self) -> Ref<Box<dyn Layout>> {
|
||||
@@ -405,7 +405,8 @@ impl Window {
|
||||
|
||||
/// 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();
|
||||
let task_manager = self.task_manager.borrow();
|
||||
let mut ignore_flags = task_manager.task_cancellers.borrow_mut();
|
||||
for task_source_name in TaskSourceName::all() {
|
||||
let flag = ignore_flags.entry(*task_source_name).or_default();
|
||||
flag.store(true, Ordering::SeqCst);
|
||||
@@ -417,7 +418,7 @@ impl Window {
|
||||
self.globalscope.time_profiler_chan()
|
||||
}
|
||||
|
||||
pub fn origin(&self) -> &MutableOrigin {
|
||||
pub fn origin(&self) -> Ref<MutableOrigin> {
|
||||
self.globalscope.origin()
|
||||
}
|
||||
|
||||
@@ -1635,7 +1636,8 @@ impl Window {
|
||||
/// This sets the current `task_manager.task_cancellers` sentinel value to
|
||||
/// `true` and replaces it with a brand new one for future tasks.
|
||||
pub fn cancel_all_tasks(&self) {
|
||||
let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut();
|
||||
let task_manager = self.task_manager.borrow();
|
||||
let mut ignore_flags = task_manager.task_cancellers.borrow_mut();
|
||||
for task_source_name in TaskSourceName::all() {
|
||||
let flag = ignore_flags.entry(*task_source_name).or_default();
|
||||
let cancelled = std::mem::take(&mut *flag);
|
||||
@@ -1647,7 +1649,8 @@ impl Window {
|
||||
/// This sets the current sentinel value to
|
||||
/// `true` and replaces it with a brand new one for future tasks.
|
||||
pub fn cancel_all_tasks_from_source(&self, task_source_name: TaskSourceName) {
|
||||
let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut();
|
||||
let task_manager = self.task_manager.borrow();
|
||||
let mut ignore_flags = task_manager.task_cancellers.borrow_mut();
|
||||
let flag = ignore_flags.entry(task_source_name).or_default();
|
||||
let cancelled = std::mem::take(&mut *flag);
|
||||
cancelled.store(true, Ordering::SeqCst);
|
||||
@@ -2207,13 +2210,13 @@ impl Window {
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn init_window_proxy(&self, window_proxy: &WindowProxy) {
|
||||
assert!(self.window_proxy.get().is_none());
|
||||
//assert!(self.window_proxy.get().is_none());
|
||||
self.window_proxy.set(Some(window_proxy));
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn init_document(&self, document: &Document) {
|
||||
assert!(self.document.get().is_none());
|
||||
//assert!(self.document.get().is_none());
|
||||
assert!(document.window() == self);
|
||||
self.document.set(Some(document));
|
||||
if !self.unminify_js {
|
||||
@@ -2267,6 +2270,7 @@ impl Window {
|
||||
ScriptThreadEventCategory::DomEvent,
|
||||
Box::new(
|
||||
self.task_manager
|
||||
.borrow()
|
||||
.task_canceller(TaskSourceName::DOMManipulation)
|
||||
.wrap_task(task),
|
||||
),
|
||||
@@ -2300,7 +2304,7 @@ impl Window {
|
||||
// TODO: step 11, navigationType.
|
||||
// Step 12, 13
|
||||
ScriptThread::navigate(
|
||||
window_proxy.browsing_context_id(),
|
||||
&window_proxy,
|
||||
pipeline_id,
|
||||
load_data,
|
||||
replace,
|
||||
@@ -2589,7 +2593,7 @@ impl Window {
|
||||
inherited_secure_context,
|
||||
),
|
||||
script_chan,
|
||||
task_manager,
|
||||
task_manager: RefCell::new(task_manager),
|
||||
layout: RefCell::new(layout),
|
||||
image_cache_chan,
|
||||
image_cache,
|
||||
@@ -2646,7 +2650,21 @@ impl Window {
|
||||
current_event: DomRefCell::new(None),
|
||||
});
|
||||
|
||||
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
|
||||
/*if let Some(reflector) = existing_window_reflector {
|
||||
unsafe {
|
||||
let raw = Root::new(MaybeUnreflectedDom::from_box(win));
|
||||
let jsobject = reflector.get_jsobject();
|
||||
let old_window: *const Window = crate::dom::bindings::conversions::native_from_object_static(jsobject.get()).unwrap();
|
||||
set_reflector_object(jsobject, raw.as_ptr() as *const _);
|
||||
let root = raw.reflect_with(jsobject.get());
|
||||
let old_window_box = Box::from_raw(old_window as *mut _);
|
||||
// create a new reflector for the replaced window object.
|
||||
let _ = WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), old_window_box);
|
||||
root
|
||||
}
|
||||
} else {*/
|
||||
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
|
||||
//}
|
||||
}
|
||||
|
||||
pub fn pipeline_id(&self) -> PipelineId {
|
||||
@@ -2660,6 +2678,27 @@ impl Window {
|
||||
{
|
||||
LayoutValue::new(self.layout_marker.borrow().clone(), value)
|
||||
}
|
||||
|
||||
pub(crate) fn replace_contents(&self, data: ReplaceData) {
|
||||
self.globalscope.replace_contents(crate::dom::globalscope::ReplaceData {
|
||||
pipeline_id: data.pipeline_id,
|
||||
script_to_constellation_chan: data.script_to_constellation_chan,
|
||||
creator_url: data.creator_url,
|
||||
origin: data.origin,
|
||||
});
|
||||
*self.task_manager.borrow_mut() = data.task_manager;
|
||||
*self.layout.borrow_mut() = data.layout;
|
||||
self.has_sent_idle_message.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ReplaceData {
|
||||
pub script_to_constellation_chan: ScriptToConstellationChan,
|
||||
pub task_manager: TaskManager,
|
||||
pub layout: Box<dyn Layout>,
|
||||
pub pipeline_id: PipelineId,
|
||||
pub creator_url: ServoUrl,
|
||||
pub origin: MutableOrigin,
|
||||
}
|
||||
|
||||
/// An instance of a value associated with a particular snapshot of layout. This stored
|
||||
@@ -2798,6 +2837,7 @@ impl Window {
|
||||
ScriptThreadEventCategory::DomEvent,
|
||||
Box::new(
|
||||
self.task_manager
|
||||
.borrow()
|
||||
.task_canceller(TaskSourceName::DOMManipulation)
|
||||
.wrap_task(task),
|
||||
),
|
||||
|
||||
@@ -298,7 +298,6 @@ impl WindowProxy {
|
||||
let new_top_level_browsing_context_id = TopLevelBrowsingContextId::new();
|
||||
let new_browsing_context_id =
|
||||
BrowsingContextId::from(new_top_level_browsing_context_id);
|
||||
let new_pipeline_id = PipelineId::new();
|
||||
let document = self
|
||||
.currently_active
|
||||
.get()
|
||||
@@ -313,13 +312,15 @@ impl WindowProxy {
|
||||
document.global().get_referrer(),
|
||||
document.get_referrer_policy(),
|
||||
None, // Doesn't inherit secure context
|
||||
None,
|
||||
true,
|
||||
);
|
||||
let new_pipeline_id = load_data.new_pipeline_id.clone();
|
||||
let load_info = AuxiliaryBrowsingContextLoadInfo {
|
||||
load_data: load_data.clone(),
|
||||
opener_pipeline_id: self.currently_active.get().unwrap(),
|
||||
new_browsing_context_id,
|
||||
new_top_level_browsing_context_id,
|
||||
new_pipeline_id,
|
||||
};
|
||||
|
||||
let new_layout_info = NewLayoutInfo {
|
||||
@@ -500,7 +501,7 @@ impl WindowProxy {
|
||||
.and_then(ScriptThread::find_document)
|
||||
.unwrap();
|
||||
// Step 14.1
|
||||
let url = match existing_document.url().join(&url) {
|
||||
let url = match existing_document.base_url().join(&url) {
|
||||
Ok(url) => url,
|
||||
Err(_) => return Err(Error::Syntax),
|
||||
};
|
||||
@@ -514,6 +515,7 @@ impl WindowProxy {
|
||||
let referrer_policy = target_document.get_referrer_policy();
|
||||
let pipeline_id = target_window.upcast::<GlobalScope>().pipeline_id();
|
||||
let secure = target_window.upcast::<GlobalScope>().is_secure_context();
|
||||
let is_about_blank = target_document.url().as_str() == "about:blank";
|
||||
let load_data = LoadData::new(
|
||||
LoadOrigin::Script(existing_document.origin().immutable().clone()),
|
||||
url,
|
||||
@@ -521,6 +523,8 @@ impl WindowProxy {
|
||||
referrer,
|
||||
referrer_policy,
|
||||
Some(secure),
|
||||
is_about_blank.then_some(pipeline_id),
|
||||
false,
|
||||
);
|
||||
let replacement_flag = if new {
|
||||
HistoryEntryReplacement::Enabled
|
||||
|
||||
@@ -57,6 +57,7 @@ impl XMLDocument {
|
||||
None,
|
||||
None,
|
||||
Default::default(),
|
||||
false,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1544,6 +1544,7 @@ impl XMLHttpRequest {
|
||||
None,
|
||||
Default::default(),
|
||||
can_gc,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::dom::htmlareaelement::HTMLAreaElement;
|
||||
use crate::dom::htmlformelement::HTMLFormElement;
|
||||
use crate::dom::htmllinkelement::HTMLLinkElement;
|
||||
use crate::dom::node::document_from_node;
|
||||
use crate::dom::types::{Element, GlobalScope};
|
||||
use crate::dom::types::{Element, GlobalScope, HTMLIFrameElement};
|
||||
use crate::task_source::TaskSource;
|
||||
|
||||
bitflags::bitflags! {
|
||||
@@ -428,7 +428,17 @@ pub fn follow_hyperlink(
|
||||
referrer,
|
||||
referrer_policy,
|
||||
Some(secure),
|
||||
(document.url().as_str() == "about:blank").then(|| document.window().pipeline_id()),
|
||||
false,
|
||||
);
|
||||
|
||||
let new_pipeline_id = load_data.new_pipeline_id.clone();
|
||||
if let Some(frame) = chosen.frame_element() {
|
||||
if let Some(frame) = frame.downcast::<HTMLIFrameElement>() {
|
||||
frame.update_pending_pipeline_id(new_pipeline_id);
|
||||
}
|
||||
}
|
||||
|
||||
let target = Trusted::new(target_window);
|
||||
let task = task!(navigate_follow_hyperlink: move || {
|
||||
debug!("following hyperlink to {}", load_data.url);
|
||||
|
||||
@@ -19,6 +19,7 @@ use crate::dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
|
||||
use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmliframeelement::IframeElementMicrotask;
|
||||
use crate::dom::htmlimageelement::ImageElementMicrotask;
|
||||
use crate::dom::htmlmediaelement::MediaElementMicrotask;
|
||||
use crate::dom::mutationobserver::MutationObserver;
|
||||
@@ -41,6 +42,7 @@ pub enum Microtask {
|
||||
User(UserMicrotask),
|
||||
MediaElement(MediaElementMicrotask),
|
||||
ImageElement(ImageElementMicrotask),
|
||||
IframeElement(IframeElementMicrotask),
|
||||
CustomElementReaction,
|
||||
NotifyMutationObservers,
|
||||
}
|
||||
@@ -134,6 +136,10 @@ impl MicrotaskQueue {
|
||||
let _realm = task.enter_realm();
|
||||
task.handler(can_gc);
|
||||
},
|
||||
Microtask::IframeElement(ref task) => {
|
||||
let _realm = task.enter_realm();
|
||||
task.handler(can_gc);
|
||||
},
|
||||
Microtask::CustomElementReaction => {
|
||||
ScriptThread::invoke_backup_element_queue(can_gc);
|
||||
},
|
||||
|
||||
@@ -221,6 +221,9 @@ struct InProgressLoad {
|
||||
canceller: FetchCanceller,
|
||||
/// If inheriting the security context
|
||||
inherited_secure_context: Option<bool>,
|
||||
///
|
||||
#[no_trace]
|
||||
replacing_pipeline: Option<PipelineId>,
|
||||
}
|
||||
|
||||
impl InProgressLoad {
|
||||
@@ -236,6 +239,7 @@ impl InProgressLoad {
|
||||
url: ServoUrl,
|
||||
origin: MutableOrigin,
|
||||
inherited_secure_context: Option<bool>,
|
||||
replacing_pipeline: Option<PipelineId>,
|
||||
) -> InProgressLoad {
|
||||
let navigation_start = CrossProcessInstant::now();
|
||||
InProgressLoad {
|
||||
@@ -252,6 +256,7 @@ impl InProgressLoad {
|
||||
navigation_start,
|
||||
canceller: Default::default(),
|
||||
inherited_secure_context,
|
||||
replacing_pipeline,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -834,6 +839,7 @@ impl ScriptThreadFactory for ScriptThread {
|
||||
load_data.url.clone(),
|
||||
origin,
|
||||
secure,
|
||||
None,
|
||||
);
|
||||
script_thread.pre_page_load(new_load, load_data);
|
||||
|
||||
@@ -995,7 +1001,8 @@ impl ScriptThread {
|
||||
|
||||
/// Step 13 of <https://html.spec.whatwg.org/multipage/#navigate>
|
||||
pub fn navigate(
|
||||
browsing_context: BrowsingContextId,
|
||||
//browsing_context: BrowsingContextId,
|
||||
window_proxy: &WindowProxy,
|
||||
pipeline_id: PipelineId,
|
||||
mut load_data: LoadData,
|
||||
replace: HistoryEntryReplacement,
|
||||
@@ -1007,6 +1014,7 @@ impl ScriptThread {
|
||||
};
|
||||
let script_thread = unsafe { &*script_thread };
|
||||
let is_javascript = load_data.url.scheme() == "javascript";
|
||||
let browsing_context = window_proxy.browsing_context_id();
|
||||
// If resource is a request whose url's scheme is "javascript"
|
||||
// https://html.spec.whatwg.org/multipage/#javascript-protocol
|
||||
if is_javascript {
|
||||
@@ -1040,6 +1048,14 @@ impl ScriptThread {
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(frame) = window_proxy.frame_element() {
|
||||
if let Some(frame) = frame.downcast::<HTMLIFrameElement>() {
|
||||
frame.update_pending_pipeline_id(
|
||||
load_data.new_pipeline_id.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
script_thread
|
||||
.script_sender
|
||||
.send((pipeline_id, ScriptMsg::LoadUrl(load_data, replace)))
|
||||
@@ -1843,6 +1859,11 @@ impl ScriptThread {
|
||||
ScriptThreadEventCategory::AttachLayout,
|
||||
Some(pipeline_id),
|
||||
|| {
|
||||
if new_layout_info.load_data.synchronously_loaded {
|
||||
assert_eq!(new_layout_info.load_data.url.as_str(), "about:blank");
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is an about:blank or about:srcdoc load, it must share the
|
||||
// creator's origin. This must match the logic in the constellation
|
||||
// when creating a new pipeline
|
||||
@@ -2173,9 +2194,8 @@ impl ScriptThread {
|
||||
TickAllAnimations(id, ..) => Some(id),
|
||||
WebFontLoaded(id, ..) => Some(id),
|
||||
DispatchIFrameLoadEvent {
|
||||
target: _,
|
||||
parent: id,
|
||||
child: _,
|
||||
..
|
||||
} => Some(id),
|
||||
DispatchStorageEvent(id, ..) => Some(id),
|
||||
ReportCSSError(id, ..) => Some(id),
|
||||
@@ -2380,7 +2400,8 @@ impl ScriptThread {
|
||||
target: browsing_context_id,
|
||||
parent: parent_id,
|
||||
child: child_id,
|
||||
} => self.handle_iframe_load_event(parent_id, browsing_context_id, child_id, can_gc),
|
||||
is_initial_about_blank,
|
||||
} => self.handle_iframe_load_event(parent_id, browsing_context_id, child_id, is_initial_about_blank, can_gc),
|
||||
ConstellationControlMsg::DispatchStorageEvent(
|
||||
pipeline_id,
|
||||
storage,
|
||||
@@ -2919,6 +2940,7 @@ impl ScriptThread {
|
||||
load_data.url.clone(),
|
||||
origin,
|
||||
load_data.inherited_secure_context,
|
||||
load_data.replacing_pipeline,
|
||||
);
|
||||
if load_data.url.as_str() == "about:blank" {
|
||||
self.start_page_load_about_blank(new_load, load_data.js_eval_result);
|
||||
@@ -3306,8 +3328,10 @@ impl ScriptThread {
|
||||
parser.abort(can_gc);
|
||||
}
|
||||
|
||||
debug!("{id}: Shutting down layout");
|
||||
document.window().layout_mut().exit_now();
|
||||
if document.is_window_relevant() {
|
||||
debug!("{id}: Shutting down layout");
|
||||
document.window().layout_mut().exit_now();
|
||||
}
|
||||
|
||||
debug!("{id}: Sending PipelineExited message to constellation");
|
||||
self.script_sender
|
||||
@@ -3325,15 +3349,17 @@ impl ScriptThread {
|
||||
}
|
||||
}
|
||||
|
||||
// We discard the browsing context after requesting layout shut down,
|
||||
// to avoid running layout on detached iframes.
|
||||
let window = document.window();
|
||||
if discard_bc == DiscardBrowsingContext::Yes {
|
||||
window.discard_browsing_context();
|
||||
}
|
||||
if document.is_window_relevant() {
|
||||
// We discard the browsing context after requesting layout shut down,
|
||||
// to avoid running layout on detached iframes.
|
||||
let window = document.window();
|
||||
if discard_bc == DiscardBrowsingContext::Yes {
|
||||
window.discard_browsing_context();
|
||||
}
|
||||
|
||||
debug!("{id}: Clearing JavaScript runtime");
|
||||
window.clear_js_runtime();
|
||||
debug!("{id}: Clearing JavaScript runtime");
|
||||
window.clear_js_runtime();
|
||||
}
|
||||
}
|
||||
|
||||
debug!("{id}: Finished pipeline exit");
|
||||
@@ -3441,6 +3467,7 @@ impl ScriptThread {
|
||||
parent_id: PipelineId,
|
||||
browsing_context_id: BrowsingContextId,
|
||||
child_id: PipelineId,
|
||||
is_initial_about_blank: bool,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
let iframe = self
|
||||
@@ -3448,7 +3475,7 @@ impl ScriptThread {
|
||||
.borrow()
|
||||
.find_iframe(parent_id, browsing_context_id);
|
||||
match iframe {
|
||||
Some(iframe) => iframe.iframe_load_event_steps(child_id, can_gc),
|
||||
Some(iframe) => iframe.iframe_load_event_steps(child_id, can_gc, !is_initial_about_blank),
|
||||
None => warn!("Message sent to closed pipeline {}.", parent_id),
|
||||
}
|
||||
}
|
||||
@@ -3666,44 +3693,62 @@ impl ScriptThread {
|
||||
};
|
||||
|
||||
// Create the window and document objects.
|
||||
let window = Window::new(
|
||||
self.js_runtime.clone(),
|
||||
MainThreadScriptChan(sender.clone()),
|
||||
task_manager,
|
||||
self.layout_factory.create(layout_config),
|
||||
self.image_cache_channel.clone(),
|
||||
self.image_cache.clone(),
|
||||
self.resource_threads.clone(),
|
||||
self.bluetooth_thread.clone(),
|
||||
self.mem_profiler_chan.clone(),
|
||||
self.time_profiler_chan.clone(),
|
||||
self.devtools_chan.clone(),
|
||||
script_to_constellation_chan,
|
||||
self.control_chan.clone(),
|
||||
self.scheduler_chan.clone(),
|
||||
incomplete.pipeline_id,
|
||||
incomplete.parent_info,
|
||||
incomplete.window_size,
|
||||
origin.clone(),
|
||||
final_url.clone(),
|
||||
incomplete.navigation_start,
|
||||
self.webgl_chan.as_ref().map(|chan| chan.channel()),
|
||||
self.webxr_registry.clone(),
|
||||
self.microtask_queue.clone(),
|
||||
self.webrender_document,
|
||||
self.webrender_api_sender.clone(),
|
||||
self.relayout_event,
|
||||
self.prepare_for_screenshot,
|
||||
self.unminify_js,
|
||||
self.local_script_source.clone(),
|
||||
self.userscripts_path.clone(),
|
||||
self.headless,
|
||||
self.replace_surrogates,
|
||||
self.user_agent.clone(),
|
||||
self.player_context.clone(),
|
||||
self.gpu_id_hub.clone(),
|
||||
incomplete.inherited_secure_context,
|
||||
);
|
||||
let old_document = incomplete.replacing_pipeline.and_then(ScriptThread::find_document);
|
||||
let replacement_same_origin = old_document.as_ref().map_or(false, |doc| {
|
||||
let old_origin = doc.origin();
|
||||
final_url.origin().same_origin(old_origin)
|
||||
});
|
||||
let window = if let (Some(old_document), true) = (old_document, replacement_same_origin) {
|
||||
old_document.window().replace_contents(crate::dom::window::ReplaceData {
|
||||
script_to_constellation_chan,
|
||||
task_manager,
|
||||
layout: self.layout_factory.create(layout_config),
|
||||
pipeline_id: incomplete.pipeline_id,
|
||||
creator_url: final_url.clone(),
|
||||
origin: origin.clone(),
|
||||
});
|
||||
old_document.disown_window();
|
||||
DomRoot::from_ref(old_document.window())
|
||||
} else {
|
||||
Window::new(
|
||||
self.js_runtime.clone(),
|
||||
MainThreadScriptChan(sender.clone()),
|
||||
task_manager,
|
||||
self.layout_factory.create(layout_config),
|
||||
self.image_cache_channel.clone(),
|
||||
self.image_cache.clone(),
|
||||
self.resource_threads.clone(),
|
||||
self.bluetooth_thread.clone(),
|
||||
self.mem_profiler_chan.clone(),
|
||||
self.time_profiler_chan.clone(),
|
||||
self.devtools_chan.clone(),
|
||||
script_to_constellation_chan,
|
||||
self.control_chan.clone(),
|
||||
self.scheduler_chan.clone(),
|
||||
incomplete.pipeline_id,
|
||||
incomplete.parent_info,
|
||||
incomplete.window_size,
|
||||
origin.clone(),
|
||||
final_url.clone(),
|
||||
incomplete.navigation_start,
|
||||
self.webgl_chan.as_ref().map(|chan| chan.channel()),
|
||||
self.webxr_registry.clone(),
|
||||
self.microtask_queue.clone(),
|
||||
self.webrender_document,
|
||||
self.webrender_api_sender.clone(),
|
||||
self.relayout_event,
|
||||
self.prepare_for_screenshot,
|
||||
self.unminify_js,
|
||||
self.local_script_source.clone(),
|
||||
self.userscripts_path.clone(),
|
||||
self.headless,
|
||||
self.replace_surrogates,
|
||||
self.user_agent.clone(),
|
||||
self.player_context.clone(),
|
||||
self.gpu_id_hub.clone(),
|
||||
incomplete.inherited_secure_context,
|
||||
)
|
||||
};
|
||||
|
||||
let _realm = enter_realm(&*window);
|
||||
|
||||
@@ -3715,6 +3760,7 @@ impl ScriptThread {
|
||||
incomplete.parent_info,
|
||||
incomplete.opener,
|
||||
);
|
||||
window_proxy.set_currently_active(&window);
|
||||
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
|
||||
@@ -3785,6 +3831,7 @@ impl ScriptThread {
|
||||
Some(status_code),
|
||||
incomplete.canceller,
|
||||
can_gc,
|
||||
final_url.as_str() == "about:blank",
|
||||
);
|
||||
document.set_ready_state(DocumentReadyState::Loading);
|
||||
|
||||
|
||||
@@ -136,6 +136,13 @@ impl OneshotTimers {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reset(&self) {
|
||||
self.js_timers.reset();
|
||||
self.next_timer_handle.set(OneshotTimerHandle(1));
|
||||
self.timers.borrow_mut().clear();
|
||||
self.expected_event_id.set(TimerEventId(0));
|
||||
}
|
||||
|
||||
pub fn setup_scheduling(&self, timer_event_chan: IpcSender<TimerEvent>) {
|
||||
let mut chan = self.timer_event_chan.borrow_mut();
|
||||
assert!(chan.is_none());
|
||||
@@ -415,6 +422,11 @@ impl Default for JsTimers {
|
||||
}
|
||||
|
||||
impl JsTimers {
|
||||
pub(crate) fn reset(&self) {
|
||||
self.next_timer_handle.set(JsTimerHandle(1));
|
||||
self.active_timers.borrow_mut().clear();
|
||||
}
|
||||
|
||||
// see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
|
||||
pub fn set_timeout_or_interval(
|
||||
&self,
|
||||
|
||||
@@ -128,6 +128,8 @@ pub enum LoadOrigin {
|
||||
/// parameters or headers
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct LoadData {
|
||||
///
|
||||
pub new_pipeline_id: PipelineId,
|
||||
/// The origin where the load started.
|
||||
pub load_origin: LoadOrigin,
|
||||
/// The URL.
|
||||
@@ -162,6 +164,11 @@ pub struct LoadData {
|
||||
|
||||
/// Servo internal: if crash details are present, trigger a crash error page with these details.
|
||||
pub crash: Option<String>,
|
||||
|
||||
///
|
||||
pub replacing_pipeline: Option<PipelineId>,
|
||||
///
|
||||
pub synchronously_loaded: bool,
|
||||
}
|
||||
|
||||
/// The result of evaluating a javascript scheme url.
|
||||
@@ -183,6 +190,8 @@ impl LoadData {
|
||||
referrer: Referrer,
|
||||
referrer_policy: Option<ReferrerPolicy>,
|
||||
inherited_secure_context: Option<bool>,
|
||||
replacing_pipeline: Option<PipelineId>,
|
||||
synchronously_loaded: bool,
|
||||
) -> LoadData {
|
||||
LoadData {
|
||||
load_origin,
|
||||
@@ -197,6 +206,9 @@ impl LoadData {
|
||||
srcdoc: "".to_string(),
|
||||
inherited_secure_context,
|
||||
crash: None,
|
||||
replacing_pipeline,
|
||||
synchronously_loaded,
|
||||
new_pipeline_id: PipelineId::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,6 +370,8 @@ pub enum ConstellationControlMsg {
|
||||
parent: PipelineId,
|
||||
/// The pipeline that has completed loading.
|
||||
child: PipelineId,
|
||||
///
|
||||
is_initial_about_blank: bool,
|
||||
},
|
||||
/// Cause a `storage` event to be dispatched at the appropriate window.
|
||||
/// The strings are key, old value and new value.
|
||||
@@ -692,8 +706,6 @@ pub struct AuxiliaryBrowsingContextLoadInfo {
|
||||
pub new_top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
/// The new browsing context ID.
|
||||
pub new_browsing_context_id: BrowsingContextId,
|
||||
/// The new pipeline ID for the auxiliary.
|
||||
pub new_pipeline_id: PipelineId,
|
||||
}
|
||||
|
||||
/// Specifies the information required to load an iframe.
|
||||
@@ -705,8 +717,6 @@ pub struct IFrameLoadInfo {
|
||||
pub browsing_context_id: BrowsingContextId,
|
||||
/// The ID for the top-level ancestor browsing context of this iframe's nested browsing context.
|
||||
pub top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
/// The new pipeline ID that the iframe has generated.
|
||||
pub new_pipeline_id: PipelineId,
|
||||
/// Whether this iframe should be considered private
|
||||
pub is_private: bool,
|
||||
/// Whether this iframe should be considered secure
|
||||
|
||||
@@ -181,7 +181,7 @@ pub enum ScriptMsg {
|
||||
),
|
||||
/// All pending loads are complete, and the `load` event for this pipeline
|
||||
/// has been dispatched.
|
||||
LoadComplete,
|
||||
LoadComplete(bool),
|
||||
/// A new load has been requested, with an option to replace the current entry once loaded
|
||||
/// instead of adding a new entry.
|
||||
LoadUrl(LoadData, HistoryEntryReplacement),
|
||||
@@ -293,7 +293,7 @@ impl fmt::Debug for ScriptMsg {
|
||||
GetBrowsingContextInfo(..) => "GetBrowsingContextInfo",
|
||||
GetTopForBrowsingContext(..) => "GetParentBrowsingContext",
|
||||
GetChildBrowsingContextId(..) => "GetChildBrowsingContextId",
|
||||
LoadComplete => "LoadComplete",
|
||||
LoadComplete(..) => "LoadComplete",
|
||||
LoadUrl(..) => "LoadUrl",
|
||||
AbortLoadUrl => "AbortLoadUrl",
|
||||
PostMessage { .. } => "PostMessage",
|
||||
|
||||
@@ -658,6 +658,8 @@ impl Handler {
|
||||
Referrer::NoReferrer,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let cmd_msg = WebDriverCommandMsg::LoadUrl(
|
||||
top_level_browsing_context_id,
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
[iframe-nosrc.html]
|
||||
[window.open]
|
||||
expected: FAIL
|
||||
|
||||
[link click]
|
||||
expected: FAIL
|
||||
|
||||
[form submission]
|
||||
expected: FAIL
|
||||
@@ -1,9 +0,0 @@
|
||||
[iframe-src-204.html]
|
||||
[Navigating to a different document with window.open]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with link click]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with form submission]
|
||||
expected: FAIL
|
||||
@@ -1,9 +0,0 @@
|
||||
[iframe-src-aboutblank-navigate-immediately.html]
|
||||
[Navigating to a different document with window.open]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with link click]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with form submission]
|
||||
expected: FAIL
|
||||
@@ -1,18 +0,0 @@
|
||||
[iframe-src-aboutblank-wait-for-load.html]
|
||||
[Navigating to a different document with src]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with location.href]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with location.assign]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with window.open]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with link click]
|
||||
expected: FAIL
|
||||
|
||||
[Navigating to a different document with form submission]
|
||||
expected: FAIL
|
||||
@@ -1,18 +0,0 @@
|
||||
[initial-content-replacement.html]
|
||||
[Content synchronously added to <iframe> with src='' won't get replaced]
|
||||
expected: FAIL
|
||||
|
||||
[Content synchronously added to <iframe> with src='about:blank' won't get replaced]
|
||||
expected: FAIL
|
||||
|
||||
[Content synchronously added to <iframe> with src='about:blank#foo' won't get replaced]
|
||||
expected: FAIL
|
||||
|
||||
[Content synchronously added to <iframe> with src='about:blank?foo' won't get replaced]
|
||||
expected: FAIL
|
||||
|
||||
[Content synchronously added to window.open('about:blank')-ed document won't get replaced]
|
||||
expected: FAIL
|
||||
|
||||
[Content synchronously added to window.open('about:blank?foo')-ed document won't get replaced]
|
||||
expected: FAIL
|
||||
@@ -1,21 +0,0 @@
|
||||
[load-pageshow-events-iframe-contentWindow.html]
|
||||
[load & pageshow event do not fire on contentWindow of <iframe> element created with no src]
|
||||
expected: FAIL
|
||||
|
||||
[load & pageshow events do not fire on contentWindow of <iframe> element created with src='']
|
||||
expected: FAIL
|
||||
|
||||
[load & pageshow events do not fire on contentWindow of <iframe> element created with src='about:blank?foo']
|
||||
expected: FAIL
|
||||
|
||||
[load & pageshow events do not fire on contentWindow of <iframe> element created with src='about:blank#foo']
|
||||
expected: FAIL
|
||||
|
||||
[load & pageshow events do not fire on contentWindow of <iframe> element created with src='about:blank']
|
||||
expected: FAIL
|
||||
|
||||
[load & pageshow events do not fire on contentWindow of <iframe> element created with src='']
|
||||
expected: FAIL
|
||||
|
||||
[load & pageshow events do not fire on contentWindow of <iframe> element created with src='about:blank']
|
||||
expected: FAIL
|
||||
@@ -1,18 +0,0 @@
|
||||
[load-pageshow-events-window-open.html]
|
||||
[load event does not fire on window.open()]
|
||||
expected: FAIL
|
||||
|
||||
[load event does not fire on window.open('about:blank')]
|
||||
expected: FAIL
|
||||
|
||||
[load event does not fire on window.open('')]
|
||||
expected: FAIL
|
||||
|
||||
[load event does not fire on window.open('about:blank#foo')]
|
||||
expected: FAIL
|
||||
|
||||
[load event does not fire on window.open('about:blank?foo')]
|
||||
expected: FAIL
|
||||
|
||||
[load event does not fire on window.open('about:blank')]
|
||||
expected: FAIL
|
||||
@@ -1,6 +0,0 @@
|
||||
[window-open-aboutblank.html]
|
||||
[location.href]
|
||||
expected: FAIL
|
||||
|
||||
[location.assign]
|
||||
expected: FAIL
|
||||
@@ -1,6 +0,0 @@
|
||||
[window-open-nourl.html]
|
||||
[location.href]
|
||||
expected: FAIL
|
||||
|
||||
[location.assign]
|
||||
expected: FAIL
|
||||
@@ -1,4 +0,0 @@
|
||||
[javascript-url-load-as-html.xhtml]
|
||||
expected: TIMEOUT
|
||||
[javascript: URL navigation to a string must create a HTML document using the correct properties]
|
||||
expected: TIMEOUT
|
||||
@@ -1,10 +0,0 @@
|
||||
[javascript-url-no-beforeunload.window.html]
|
||||
expected: TIMEOUT
|
||||
[Navigating an opened window with an iframe via location.href to a javascript: URL must not fire beforeunload on the iframe: string completion]
|
||||
expected: NOTRUN
|
||||
|
||||
[Navigating an opened window via location.href to a javascript: URL must not fire beforeunload: string completion]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Navigating an opened window with an iframe via location.href to a javascript: URL must not fire beforeunload on the iframe: undefined completion]
|
||||
expected: FAIL
|
||||
@@ -1,10 +0,0 @@
|
||||
[javascript-url-referrer.window.html]
|
||||
expected: TIMEOUT
|
||||
[unsafe-url referrer policy used to create the starting page]
|
||||
expected: FAIL
|
||||
|
||||
[origin referrer policy used to create the starting page]
|
||||
expected: FAIL
|
||||
|
||||
[no-referrer referrer policy used to create the starting page]
|
||||
expected: TIMEOUT
|
||||
@@ -1,6 +0,0 @@
|
||||
[navigate-to-unparseable-url.html]
|
||||
[location.href setter throws a SyntaxError DOMException for unparseable URLs]
|
||||
expected: FAIL
|
||||
|
||||
[<a> tag navigate fails for unparseable URLs]
|
||||
expected: FAIL
|
||||
@@ -1,3 +0,0 @@
|
||||
[a-click.html]
|
||||
[aElement.click() before the load event must NOT replace]
|
||||
expected: FAIL
|
||||
4
tests/wpt/mozilla/meta/MANIFEST.json
vendored
4
tests/wpt/mozilla/meta/MANIFEST.json
vendored
@@ -10414,7 +10414,7 @@
|
||||
],
|
||||
"resource": {
|
||||
"file-submission.py": [
|
||||
"5f65cebd05ce89b3a51c2382a39b6a6438133b43",
|
||||
"b03a4c9a5ddebc78af2bf8d0a35ebaca27bb4314",
|
||||
[]
|
||||
],
|
||||
"upload.txt": [
|
||||
@@ -13227,7 +13227,7 @@
|
||||
]
|
||||
],
|
||||
"form_submit_about.html": [
|
||||
"ec572ab0bc608c8cf5dd43f4159d3a67fc31a0de",
|
||||
"71342b9b6b3ae6f037829b2e472bdd2fd1e93692",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
|
||||
|
||||
def fail(msg):
|
||||
return ([("Content-Type", "text/plain")], "FAIL: " + msg)
|
||||
return ([("Content-Type", "text/plain")], b"FAIL: " + msg)
|
||||
|
||||
|
||||
def main(request, response):
|
||||
content_type = request.headers.get(b'Content-Type').split(b"; ")
|
||||
|
||||
if len(content_type) != 2:
|
||||
return fail("content type length is incorrect")
|
||||
return fail(b"content type length is incorrect")
|
||||
|
||||
if content_type[0] != b'multipart/form-data':
|
||||
return fail("content type first field is incorrect")
|
||||
return fail(b"content type first field is incorrect")
|
||||
|
||||
boundary = content_type[1].strip(b"boundary=")
|
||||
|
||||
@@ -24,6 +24,6 @@ def main(request, response):
|
||||
body += b"\r\n" + b"content-type: text/plain\r\n\r\nHello\r\n--" + boundary + b"--\r\n"
|
||||
|
||||
if body != request.body:
|
||||
return fail("request body doesn't match: " + body + "+++++++" + request.body)
|
||||
return fail(b"request body doesn't match: " + body + b"+++++++" + request.body)
|
||||
|
||||
return ([("Content-Type", "text/plain")], "OK")
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
var numOnLoads = 0
|
||||
var t = async_test("about:blank as form target")
|
||||
var iframe = document.getElementById('foo')
|
||||
iframe.onload = t.step_func(function(e) { if (++numOnLoads == 2) t.done() })
|
||||
iframe.onload = t.step_func(function(e) { t.step_timeout(() => t.done(), 100); iframe.onload = t.unreached_func(); })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user