зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #13996 - Implement synchronous about:blank loading (from servo:about-blank); r=Ms2ger,jdm,asajeffrey,nox
Based on initial work by jdm in <https://github.com/servo/servo/pull/8600>. Source-Repo: https://github.com/servo/servo Source-Revision: 0d896a8d820e31037d536f133b5a8b8c43c2e1a2
This commit is contained in:
Родитель
4345821670
Коммит
96740ae66f
|
@ -42,7 +42,7 @@ use rand::{Rng, SeedableRng, StdRng, random};
|
|||
use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
|
||||
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg};
|
||||
use script_traits::{DocumentState, LayoutControlMsg, LoadData};
|
||||
use script_traits::{IFrameLoadInfo, IFrameSandboxState, TimerEventRequest};
|
||||
use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerEventRequest};
|
||||
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
|
||||
use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg};
|
||||
use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData};
|
||||
|
@ -914,11 +914,17 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
FromScriptMsg::ScriptLoadedURLInIFrame(load_info) => {
|
||||
debug!("constellation got iframe URL load message {:?} {:?} {:?}",
|
||||
load_info.parent_pipeline_id,
|
||||
load_info.info.parent_pipeline_id,
|
||||
load_info.old_pipeline_id,
|
||||
load_info.new_pipeline_id);
|
||||
load_info.info.new_pipeline_id);
|
||||
self.handle_script_loaded_url_in_iframe_msg(load_info);
|
||||
}
|
||||
FromScriptMsg::ScriptLoadedAboutBlankInIFrame(load_info, lc) => {
|
||||
debug!("constellation got loaded `about:blank` in iframe message {:?} {:?}",
|
||||
load_info.parent_pipeline_id,
|
||||
load_info.new_pipeline_id);
|
||||
self.handle_script_loaded_about_blank_in_iframe_msg(load_info, lc);
|
||||
}
|
||||
FromScriptMsg::ChangeRunningAnimationsState(pipeline_id, animation_state) => {
|
||||
self.handle_change_running_animations_state(pipeline_id, animation_state)
|
||||
}
|
||||
|
@ -1363,14 +1369,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
// will result in a new pipeline being spawned and a frame tree being added to
|
||||
// parent_pipeline_id's frame tree's children. This message is never the result of a
|
||||
// page navigation.
|
||||
fn handle_script_loaded_url_in_iframe_msg(&mut self, load_info: IFrameLoadInfo) {
|
||||
fn handle_script_loaded_url_in_iframe_msg(&mut self, load_info: IFrameLoadInfoWithData) {
|
||||
let (load_data, window_size, is_private) = {
|
||||
let old_pipeline = load_info.old_pipeline_id
|
||||
.and_then(|old_pipeline_id| self.pipelines.get(&old_pipeline_id));
|
||||
|
||||
let source_pipeline = match self.pipelines.get(&load_info.parent_pipeline_id) {
|
||||
let source_pipeline = match self.pipelines.get(&load_info.info.parent_pipeline_id) {
|
||||
Some(source_pipeline) => source_pipeline,
|
||||
None => return warn!("Script loaded url in closed iframe {}.", load_info.parent_pipeline_id),
|
||||
None => return warn!("Script loaded url in closed iframe {}.", load_info.info.parent_pipeline_id),
|
||||
};
|
||||
|
||||
// If no url is specified, reload.
|
||||
|
@ -1384,7 +1390,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
LoadData::new(url, None, None)
|
||||
});
|
||||
|
||||
let is_private = load_info.is_private || source_pipeline.is_private;
|
||||
let is_private = load_info.info.is_private || source_pipeline.is_private;
|
||||
|
||||
let window_size = old_pipeline.and_then(|old_pipeline| old_pipeline.size);
|
||||
|
||||
|
@ -1396,20 +1402,65 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
};
|
||||
|
||||
// Create the new pipeline, attached to the parent and push to pending frames
|
||||
self.new_pipeline(load_info.new_pipeline_id,
|
||||
load_info.frame_id,
|
||||
Some((load_info.parent_pipeline_id, load_info.frame_type)),
|
||||
self.new_pipeline(load_info.info.new_pipeline_id,
|
||||
load_info.info.frame_id,
|
||||
Some((load_info.info.parent_pipeline_id, load_info.info.frame_type)),
|
||||
window_size,
|
||||
load_data,
|
||||
load_info.sandbox,
|
||||
is_private);
|
||||
|
||||
self.pending_frames.push(FrameChange {
|
||||
frame_id: load_info.frame_id,
|
||||
frame_id: load_info.info.frame_id,
|
||||
old_pipeline_id: load_info.old_pipeline_id,
|
||||
new_pipeline_id: load_info.new_pipeline_id,
|
||||
new_pipeline_id: load_info.info.new_pipeline_id,
|
||||
document_ready: false,
|
||||
replace: load_info.replace,
|
||||
replace: load_info.info.replace,
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_script_loaded_about_blank_in_iframe_msg(&mut self,
|
||||
load_info: IFrameLoadInfo,
|
||||
layout_sender: IpcSender<LayoutControlMsg>) {
|
||||
let IFrameLoadInfo {
|
||||
parent_pipeline_id,
|
||||
new_pipeline_id,
|
||||
frame_type,
|
||||
replace,
|
||||
frame_id,
|
||||
is_private,
|
||||
} = load_info;
|
||||
|
||||
let pipeline = {
|
||||
let parent_pipeline = match self.pipelines.get(&parent_pipeline_id) {
|
||||
Some(parent_pipeline) => parent_pipeline,
|
||||
None => return warn!("Script loaded url in closed iframe {}.", parent_pipeline_id),
|
||||
};
|
||||
|
||||
let script_sender = parent_pipeline.script_chan.clone();
|
||||
|
||||
let url = ServoUrl::parse("about:blank").expect("infallible");
|
||||
Pipeline::new(new_pipeline_id,
|
||||
frame_id,
|
||||
Some((parent_pipeline_id, frame_type)),
|
||||
script_sender,
|
||||
layout_sender,
|
||||
self.compositor_proxy.clone_compositor_proxy(),
|
||||
is_private || parent_pipeline.is_private,
|
||||
url,
|
||||
None,
|
||||
parent_pipeline.visible)
|
||||
};
|
||||
|
||||
assert!(!self.pipelines.contains_key(&new_pipeline_id));
|
||||
self.pipelines.insert(new_pipeline_id, pipeline);
|
||||
|
||||
self.pending_frames.push(FrameChange {
|
||||
frame_id: frame_id,
|
||||
old_pipeline_id: None,
|
||||
new_pipeline_id: new_pipeline_id,
|
||||
document_ready: false,
|
||||
replace: replace,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -165,8 +165,7 @@ impl Pipeline {
|
|||
load_data: state.load_data.clone(),
|
||||
window_size: window_size,
|
||||
pipeline_port: pipeline_port,
|
||||
layout_to_constellation_chan: state.layout_to_constellation_chan.clone(),
|
||||
content_process_shutdown_chan: layout_content_process_shutdown_chan.clone(),
|
||||
content_process_shutdown_chan: Some(layout_content_process_shutdown_chan.clone()),
|
||||
layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize,
|
||||
};
|
||||
|
||||
|
@ -254,23 +253,23 @@ impl Pipeline {
|
|||
state.window_size,
|
||||
state.prev_visibility.unwrap_or(true));
|
||||
|
||||
pipeline.notify_visibility();
|
||||
|
||||
Ok((pipeline, child_process))
|
||||
}
|
||||
|
||||
fn new(id: PipelineId,
|
||||
frame_id: FrameId,
|
||||
parent_info: Option<(PipelineId, FrameType)>,
|
||||
script_chan: Rc<ScriptChan>,
|
||||
layout_chan: IpcSender<LayoutControlMsg>,
|
||||
compositor_proxy: Box<CompositorProxy + 'static + Send>,
|
||||
is_private: bool,
|
||||
url: ServoUrl,
|
||||
size: Option<TypedSize2D<f32, PagePx>>,
|
||||
visible: bool)
|
||||
-> Pipeline {
|
||||
Pipeline {
|
||||
/// Creates a new `Pipeline`, after the script and layout threads have been
|
||||
/// spawned.
|
||||
pub fn new(id: PipelineId,
|
||||
frame_id: FrameId,
|
||||
parent_info: Option<(PipelineId, FrameType)>,
|
||||
script_chan: Rc<ScriptChan>,
|
||||
layout_chan: IpcSender<LayoutControlMsg>,
|
||||
compositor_proxy: Box<CompositorProxy + 'static + Send>,
|
||||
is_private: bool,
|
||||
url: ServoUrl,
|
||||
size: Option<TypedSize2D<f32, PagePx>>,
|
||||
visible: bool)
|
||||
-> Pipeline {
|
||||
let pipeline = Pipeline {
|
||||
id: id,
|
||||
frame_id: frame_id,
|
||||
parent_info: parent_info,
|
||||
|
@ -284,7 +283,11 @@ impl Pipeline {
|
|||
running_animations: false,
|
||||
visible: visible,
|
||||
is_private: is_private,
|
||||
}
|
||||
};
|
||||
|
||||
pipeline.notify_visibility();
|
||||
|
||||
pipeline
|
||||
}
|
||||
|
||||
pub fn exit(&self) {
|
||||
|
@ -424,6 +427,7 @@ impl UnprivilegedPipelineContent {
|
|||
control_chan: self.script_chan.clone(),
|
||||
control_port: self.script_port,
|
||||
constellation_chan: self.constellation_chan,
|
||||
layout_to_constellation_chan: self.layout_to_constellation_chan.clone(),
|
||||
scheduler_chan: self.scheduler_chan,
|
||||
bluetooth_thread: self.bluetooth_thread,
|
||||
resource_threads: self.resource_threads,
|
||||
|
@ -448,7 +452,7 @@ impl UnprivilegedPipelineContent {
|
|||
self.font_cache_thread,
|
||||
self.time_profiler_chan,
|
||||
self.mem_profiler_chan,
|
||||
self.layout_content_process_shutdown_chan,
|
||||
Some(self.layout_content_process_shutdown_chan),
|
||||
self.webrender_api_sender,
|
||||
self.prefs.get("layout.threads").expect("exists").value()
|
||||
.as_u64().expect("count") as usize);
|
||||
|
|
|
@ -246,7 +246,7 @@ impl LayoutThreadFactory for LayoutThread {
|
|||
font_cache_thread: FontCacheThread,
|
||||
time_profiler_chan: time::ProfilerChan,
|
||||
mem_profiler_chan: mem::ProfilerChan,
|
||||
content_process_shutdown_chan: IpcSender<()>,
|
||||
content_process_shutdown_chan: Option<IpcSender<()>>,
|
||||
webrender_api_sender: webrender_traits::RenderApiSender,
|
||||
layout_threads: usize) {
|
||||
thread::spawn_named(format!("LayoutThread {:?}", id),
|
||||
|
@ -278,7 +278,9 @@ impl LayoutThreadFactory for LayoutThread {
|
|||
layout.start();
|
||||
}, reporter_name, sender, Msg::CollectReports);
|
||||
}
|
||||
let _ = content_process_shutdown_chan.send(());
|
||||
if let Some(content_process_shutdown_chan) = content_process_shutdown_chan {
|
||||
let _ = content_process_shutdown_chan.send(());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ pub trait LayoutThreadFactory {
|
|||
font_cache_thread: FontCacheThread,
|
||||
time_profiler_chan: time::ProfilerChan,
|
||||
mem_profiler_chan: mem::ProfilerChan,
|
||||
content_process_shutdown_chan: IpcSender<()>,
|
||||
content_process_shutdown_chan: Option<IpcSender<()>>,
|
||||
webrender_api_sender: webrender_traits::RenderApiSender,
|
||||
layout_threads: usize);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ use dom::bindings::conversions::ToJSValConvertible;
|
|||
use dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root};
|
||||
use dom::bindings::refcounted::Trusted;
|
||||
use dom::bindings::reflector::Reflectable;
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::browsingcontext::BrowsingContext;
|
||||
|
@ -42,14 +43,16 @@ use js::jsval::{NullValue, UndefinedValue};
|
|||
use msg::constellation_msg::{FrameType, FrameId, PipelineId, TraversalDirection};
|
||||
use net_traits::response::HttpsState;
|
||||
use script_layout_interface::message::ReflowQueryType;
|
||||
use script_thread::ScriptThread;
|
||||
use script_traits::{IFrameLoadInfo, LoadData, MozBrowserEvent, ScriptMsg as ConstellationMsg};
|
||||
use script_thread::{ScriptThread, Runnable};
|
||||
use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData};
|
||||
use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg as ConstellationMsg};
|
||||
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
|
||||
use servo_atoms::Atom;
|
||||
use servo_url::ServoUrl;
|
||||
use std::cell::Cell;
|
||||
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
|
||||
use style::context::ReflowGoal;
|
||||
use task_source::TaskSource;
|
||||
use util::prefs::PREFS;
|
||||
use util::servo_version;
|
||||
|
||||
|
@ -66,6 +69,12 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum ProcessingMode {
|
||||
FirstTime,
|
||||
NotFirstTime,
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct HTMLIFrameElement {
|
||||
htmlelement: HTMLElement,
|
||||
|
@ -131,20 +140,46 @@ impl HTMLIFrameElement {
|
|||
|
||||
let global_scope = window.upcast::<GlobalScope>();
|
||||
let load_info = IFrameLoadInfo {
|
||||
load_data: load_data,
|
||||
parent_pipeline_id: global_scope.pipeline_id(),
|
||||
frame_id: self.frame_id,
|
||||
old_pipeline_id: old_pipeline_id,
|
||||
new_pipeline_id: new_pipeline_id,
|
||||
sandbox: sandboxed,
|
||||
is_private: private_iframe,
|
||||
frame_type: frame_type,
|
||||
replace: replace,
|
||||
};
|
||||
global_scope
|
||||
.constellation_chan()
|
||||
.send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info))
|
||||
.unwrap();
|
||||
|
||||
if load_data.as_ref().map_or(false, |d| d.url.as_str() == "about:blank") {
|
||||
let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
|
||||
|
||||
global_scope
|
||||
.constellation_chan()
|
||||
.send(ConstellationMsg::ScriptLoadedAboutBlankInIFrame(load_info, pipeline_sender))
|
||||
.unwrap();
|
||||
|
||||
let new_layout_info = NewLayoutInfo {
|
||||
parent_info: Some((global_scope.pipeline_id(), frame_type)),
|
||||
new_pipeline_id: new_pipeline_id,
|
||||
frame_id: self.frame_id,
|
||||
load_data: load_data.unwrap(),
|
||||
pipeline_port: pipeline_receiver,
|
||||
content_process_shutdown_chan: None,
|
||||
window_size: None,
|
||||
layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize,
|
||||
};
|
||||
|
||||
ScriptThread::process_attach_layout(new_layout_info);
|
||||
} else {
|
||||
let load_info = IFrameLoadInfoWithData {
|
||||
info: load_info,
|
||||
load_data: load_data,
|
||||
old_pipeline_id: old_pipeline_id,
|
||||
sandbox: sandboxed,
|
||||
};
|
||||
global_scope
|
||||
.constellation_chan()
|
||||
.send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if PREFS.is_mozbrowser_enabled() {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart
|
||||
|
@ -152,9 +187,23 @@ impl HTMLIFrameElement {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn process_the_iframe_attributes(&self) {
|
||||
/// https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes
|
||||
fn process_the_iframe_attributes(&self, mode: ProcessingMode) {
|
||||
// TODO: srcdoc
|
||||
|
||||
// https://github.com/whatwg/html/issues/490
|
||||
if mode == ProcessingMode::FirstTime && !self.upcast::<Element>().has_attribute(&local_name!("src")) {
|
||||
let window = window_from_node(self);
|
||||
let event_loop = window.dom_manipulation_task_source();
|
||||
let _ = event_loop.queue(box IframeLoadEventSteps::new(self),
|
||||
window.upcast());
|
||||
return;
|
||||
}
|
||||
|
||||
let url = self.get_url();
|
||||
|
||||
// TODO: check ancestor browsing contexts for same URL
|
||||
|
||||
let document = document_from_node(self);
|
||||
self.navigate_or_reload_child_browsing_context(
|
||||
Some(LoadData::new(url, document.get_referrer_policy(), Some(document.url()))), false);
|
||||
|
@ -171,6 +220,16 @@ impl HTMLIFrameElement {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_nested_browsing_context(&self) {
|
||||
// Synchronously create a new context and navigate it to about:blank.
|
||||
let url = ServoUrl::parse("about:blank").unwrap();
|
||||
let document = document_from_node(self);
|
||||
let load_data = LoadData::new(url,
|
||||
document.get_referrer_policy(),
|
||||
Some(document.url().clone()));
|
||||
self.navigate_or_reload_child_browsing_context(Some(load_data), false);
|
||||
}
|
||||
|
||||
pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId) {
|
||||
self.pipeline_id.set(Some(new_pipeline_id));
|
||||
|
||||
|
@ -272,7 +331,11 @@ impl HTMLIFrameElement {
|
|||
self.pipeline_id.get()
|
||||
.and_then(|pipeline_id| ScriptThread::find_document(pipeline_id))
|
||||
.and_then(|document| {
|
||||
if self.global().get_url().origin() == document.global().get_url().origin() {
|
||||
// FIXME(#10964): this should use the Document's origin and the
|
||||
// origin of the incumbent settings object.
|
||||
let contained_url = document.global().get_url();
|
||||
if self.global().get_url().origin() == contained_url.origin() ||
|
||||
contained_url.as_str() == "about:blank" {
|
||||
Some(Root::from_ref(document.window()))
|
||||
} else {
|
||||
None
|
||||
|
@ -458,18 +521,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
|
|||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-iframe-contentdocument
|
||||
fn GetContentDocument(&self) -> Option<Root<Document>> {
|
||||
self.get_content_window().and_then(|window| {
|
||||
// FIXME(#10964): this should use the Document's origin and the
|
||||
// origin of the incumbent settings object.
|
||||
let self_url = self.get_url();
|
||||
let win_url = window_from_node(self).get_url();
|
||||
|
||||
if UrlHelper::SameOrigin(&self_url, &win_url) {
|
||||
Some(window.Document())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
self.get_content_window().map(|window| window.Document())
|
||||
}
|
||||
|
||||
// Experimental mozbrowser implementation is based on the webidl
|
||||
|
@ -601,19 +653,17 @@ impl VirtualMethods for HTMLIFrameElement {
|
|||
}));
|
||||
},
|
||||
&local_name!("src") => {
|
||||
if let AttributeMutation::Set(_) = mutation {
|
||||
// https://html.spec.whatwg.org/multipage/#the-iframe-element
|
||||
// "Similarly, whenever an iframe element with a non-null nested browsing context
|
||||
// but with no srcdoc attribute specified has its src attribute set, changed, or removed,
|
||||
// the user agent must process the iframe attributes,"
|
||||
// but we can't check that directly, since the child browsing context
|
||||
// may be in a different script thread. Instread, we check to see if the parent
|
||||
// is in a document tree and has a browsing context, which is what causes
|
||||
// the child browsing context to be created.
|
||||
if self.upcast::<Node>().is_in_doc_with_browsing_context() {
|
||||
debug!("iframe {} src set while in browsing context.", self.frame_id);
|
||||
self.process_the_iframe_attributes();
|
||||
}
|
||||
// https://html.spec.whatwg.org/multipage/#the-iframe-element
|
||||
// "Similarly, whenever an iframe element with a non-null nested browsing context
|
||||
// but with no srcdoc attribute specified has its src attribute set, changed, or removed,
|
||||
// the user agent must process the iframe attributes,"
|
||||
// but we can't check that directly, since the child browsing context
|
||||
// may be in a different script thread. Instread, we check to see if the parent
|
||||
// is in a document tree and has a browsing context, which is what causes
|
||||
// the child browsing context to be created.
|
||||
if self.upcast::<Node>().is_in_doc_with_browsing_context() {
|
||||
debug!("iframe {} src set while in browsing context.", self.frame_id);
|
||||
self.process_the_iframe_attributes(ProcessingMode::NotFirstTime);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
|
@ -642,7 +692,8 @@ impl VirtualMethods for HTMLIFrameElement {
|
|||
// iframe attributes for the "first time"."
|
||||
if self.upcast::<Node>().is_in_doc_with_browsing_context() {
|
||||
debug!("iframe {} bound to browsing context.", self.frame_id);
|
||||
self.process_the_iframe_attributes();
|
||||
self.create_nested_browsing_context();
|
||||
self.process_the_iframe_attributes(ProcessingMode::FirstTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -667,7 +718,7 @@ impl VirtualMethods for HTMLIFrameElement {
|
|||
// HTMLIFrameElement::contentDocument.
|
||||
let self_url = self.get_url();
|
||||
let win_url = window_from_node(self).get_url();
|
||||
UrlHelper::SameOrigin(&self_url, &win_url)
|
||||
UrlHelper::SameOrigin(&self_url, &win_url) || self_url.as_str() == "about:blank"
|
||||
};
|
||||
let (sender, receiver) = if same_origin {
|
||||
(None, None)
|
||||
|
@ -690,3 +741,24 @@ impl VirtualMethods for HTMLIFrameElement {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IframeLoadEventSteps {
|
||||
frame_element: Trusted<HTMLIFrameElement>,
|
||||
pipeline_id: PipelineId,
|
||||
}
|
||||
|
||||
impl IframeLoadEventSteps {
|
||||
fn new(frame_element: &HTMLIFrameElement) -> IframeLoadEventSteps {
|
||||
IframeLoadEventSteps {
|
||||
frame_element: Trusted::new(frame_element),
|
||||
pipeline_id: frame_element.pipeline_id().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Runnable for IframeLoadEventSteps {
|
||||
fn handler(self: Box<IframeLoadEventSteps>) {
|
||||
let this = self.frame_element.root();
|
||||
this.iframe_load_event_steps(self.pipeline_id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,8 @@ use js::rust::Runtime;
|
|||
use layout_wrapper::ServoLayoutNode;
|
||||
use mem::heap_size_of_self_and_children;
|
||||
use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace};
|
||||
use net_traits::{CoreResourceMsg, IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener};
|
||||
use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
||||
use net_traits::request::{CredentialsMode, Destination, RequestInit};
|
||||
use net_traits::storage_thread::StorageType;
|
||||
|
@ -82,7 +83,7 @@ use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryTyp
|
|||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory, EnqueuedPromiseCallback};
|
||||
use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx, PromiseJobQueue};
|
||||
use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult};
|
||||
use script_traits::{InitialScriptState, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
|
||||
use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
|
||||
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
|
||||
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
|
||||
use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData, WindowSizeType};
|
||||
|
@ -434,6 +435,9 @@ pub struct ScriptThread {
|
|||
/// For communicating load url messages to the constellation
|
||||
constellation_chan: IpcSender<ConstellationMsg>,
|
||||
|
||||
/// A sender for new layout threads to communicate to the constellation.
|
||||
layout_to_constellation_chan: IpcSender<LayoutMsg>,
|
||||
|
||||
/// The port on which we receive messages from the image cache
|
||||
image_cache_port: Receiver<ImageCacheResult>,
|
||||
|
||||
|
@ -602,6 +606,17 @@ impl ScriptThread {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn process_attach_layout(new_layout_info: NewLayoutInfo) {
|
||||
SCRIPT_THREAD_ROOT.with(|root| {
|
||||
if let Some(script_thread) = root.get() {
|
||||
let script_thread = unsafe { &*script_thread };
|
||||
script_thread.profile_event(ScriptThreadEventCategory::AttachLayout, || {
|
||||
script_thread.handle_new_layout(new_layout_info);
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn find_document(id: PipelineId) -> Option<Root<Document>> {
|
||||
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
|
||||
let script_thread = unsafe { &*script_thread };
|
||||
|
@ -681,6 +696,8 @@ impl ScriptThread {
|
|||
content_process_shutdown_chan: state.content_process_shutdown_chan,
|
||||
|
||||
promise_job_queue: PromiseJobQueue::new(),
|
||||
|
||||
layout_to_constellation_chan: state.layout_to_constellation_chan,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1179,7 +1196,6 @@ impl ScriptThread {
|
|||
load_data,
|
||||
window_size,
|
||||
pipeline_port,
|
||||
layout_to_constellation_chan,
|
||||
content_process_shutdown_chan,
|
||||
layout_threads,
|
||||
} = new_layout_info;
|
||||
|
@ -1193,7 +1209,7 @@ impl ScriptThread {
|
|||
is_parent: false,
|
||||
layout_pair: layout_pair,
|
||||
pipeline_port: pipeline_port,
|
||||
constellation_chan: layout_to_constellation_chan,
|
||||
constellation_chan: self.layout_to_constellation_chan.clone(),
|
||||
script_chan: self.control_chan.clone(),
|
||||
image_cache_thread: self.image_cache_thread.clone(),
|
||||
content_process_shutdown_chan: content_process_shutdown_chan,
|
||||
|
@ -1215,7 +1231,11 @@ impl ScriptThread {
|
|||
let new_load = InProgressLoad::new(new_pipeline_id, frame_id, parent_info,
|
||||
layout_chan, window_size,
|
||||
load_data.url.clone());
|
||||
self.start_page_load(new_load, load_data);
|
||||
if load_data.url.as_str() == "about:blank" {
|
||||
self.start_page_load_about_blank(new_load);
|
||||
} else {
|
||||
self.start_page_load(new_load, load_data);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_loads_complete(&self, pipeline: PipelineId) {
|
||||
|
@ -1641,7 +1661,8 @@ impl ScriptThread {
|
|||
|
||||
/// Notify the containing document of a child frame that has completed loading.
|
||||
fn handle_frame_load_event(&self, parent_id: PipelineId, frame_id: FrameId, child_id: PipelineId) {
|
||||
match self.documents.borrow().find_iframe(parent_id, frame_id) {
|
||||
let iframe = self.documents.borrow().find_iframe(parent_id, frame_id);
|
||||
match iframe {
|
||||
Some(iframe) => iframe.iframe_load_event_steps(child_id),
|
||||
None => warn!("Message sent to closed pipeline {}.", parent_id),
|
||||
}
|
||||
|
@ -2014,7 +2035,8 @@ impl ScriptThread {
|
|||
replace: bool) {
|
||||
match frame_id {
|
||||
Some(frame_id) => {
|
||||
if let Some(iframe) = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id) {
|
||||
let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id);
|
||||
if let Some(iframe) = iframe {
|
||||
iframe.navigate_or_reload_child_browsing_context(Some(load_data), replace);
|
||||
}
|
||||
}
|
||||
|
@ -2092,6 +2114,23 @@ impl ScriptThread {
|
|||
self.incomplete_loads.borrow_mut().push(incomplete);
|
||||
}
|
||||
|
||||
/// Synchronously fetch `about:blank`. Stores the `InProgressLoad`
|
||||
/// argument until a notification is received that the fetch is complete.
|
||||
fn start_page_load_about_blank(&self, incomplete: InProgressLoad) {
|
||||
let id = incomplete.pipeline_id;
|
||||
|
||||
self.incomplete_loads.borrow_mut().push(incomplete);
|
||||
|
||||
let url = ServoUrl::parse("about:blank").unwrap();
|
||||
let mut context = ParserContext::new(id, url.clone());
|
||||
|
||||
let mut meta = Metadata::default(url);
|
||||
meta.set_content_type(Some(&mime!(Text / Html)));
|
||||
context.process_response(Ok(FetchMetadata::Unfiltered(meta)));
|
||||
context.process_response_chunk(vec![]);
|
||||
context.process_response_eof(Ok(()));
|
||||
}
|
||||
|
||||
fn handle_parsing_complete(&self, id: PipelineId) {
|
||||
let document = match self.documents.borrow().find_document(id) {
|
||||
Some(document) => document,
|
||||
|
|
|
@ -142,6 +142,6 @@ pub struct NewLayoutThreadInfo {
|
|||
pub constellation_chan: IpcSender<ConstellationMsg>,
|
||||
pub script_chan: IpcSender<ConstellationControlMsg>,
|
||||
pub image_cache_thread: ImageCacheThread,
|
||||
pub content_process_shutdown_chan: IpcSender<()>,
|
||||
pub content_process_shutdown_chan: Option<IpcSender<()>>,
|
||||
pub layout_threads: usize,
|
||||
}
|
||||
|
|
|
@ -177,10 +177,8 @@ pub struct NewLayoutInfo {
|
|||
pub window_size: Option<WindowSizeData>,
|
||||
/// A port on which layout can receive messages from the pipeline.
|
||||
pub pipeline_port: IpcReceiver<LayoutControlMsg>,
|
||||
/// A sender for the layout thread to communicate to the constellation.
|
||||
pub layout_to_constellation_chan: IpcSender<LayoutMsg>,
|
||||
/// A shutdown channel so that layout can tell the content process to shut down when it's done.
|
||||
pub content_process_shutdown_chan: IpcSender<()>,
|
||||
pub content_process_shutdown_chan: Option<IpcSender<()>>,
|
||||
/// Number of threads to use for layout.
|
||||
pub layout_threads: usize,
|
||||
}
|
||||
|
@ -450,6 +448,8 @@ pub struct InitialScriptState {
|
|||
pub control_port: IpcReceiver<ConstellationControlMsg>,
|
||||
/// A channel on which messages can be sent to the constellation from script.
|
||||
pub constellation_chan: IpcSender<ScriptMsg>,
|
||||
/// A sender for the layout thread to communicate to the constellation.
|
||||
pub layout_to_constellation_chan: IpcSender<LayoutMsg>,
|
||||
/// A channel to schedule timer events.
|
||||
pub scheduler_chan: IpcSender<TimerEventRequest>,
|
||||
/// A channel to the resource manager thread.
|
||||
|
@ -492,21 +492,15 @@ pub enum IFrameSandboxState {
|
|||
IFrameUnsandboxed
|
||||
}
|
||||
|
||||
/// Specifies the information required to load a URL in an iframe.
|
||||
/// Specifies the information required to load an iframe.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct IFrameLoadInfo {
|
||||
/// Load data containing the url to load
|
||||
pub load_data: Option<LoadData>,
|
||||
/// Pipeline ID of the parent of this iframe
|
||||
pub parent_pipeline_id: PipelineId,
|
||||
/// The ID for this iframe.
|
||||
pub frame_id: FrameId,
|
||||
/// The old pipeline ID for this iframe, if a page was previously loaded.
|
||||
pub old_pipeline_id: Option<PipelineId>,
|
||||
/// The new pipeline ID that the iframe has generated.
|
||||
pub new_pipeline_id: PipelineId,
|
||||
/// Sandbox type of this iframe
|
||||
pub sandbox: IFrameSandboxState,
|
||||
/// Whether this iframe should be considered private
|
||||
pub is_private: bool,
|
||||
/// Whether this iframe is a mozbrowser iframe
|
||||
|
@ -516,6 +510,19 @@ pub struct IFrameLoadInfo {
|
|||
pub replace: bool,
|
||||
}
|
||||
|
||||
/// Specifies the information required to load a URL in an iframe.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct IFrameLoadInfoWithData {
|
||||
/// The information required to load an iframe.
|
||||
pub info: IFrameLoadInfo,
|
||||
/// Load data containing the url to load
|
||||
pub load_data: Option<LoadData>,
|
||||
/// The old pipeline ID for this iframe, if a page was previously loaded.
|
||||
pub old_pipeline_id: Option<PipelineId>,
|
||||
/// Sandbox type of this iframe
|
||||
pub sandbox: IFrameSandboxState,
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API#Events
|
||||
/// The events fired in a Browser API context (`<iframe mozbrowser>`)
|
||||
#[derive(Deserialize, Serialize)]
|
||||
|
|
|
@ -6,6 +6,8 @@ use AnimationState;
|
|||
use CompositorEvent;
|
||||
use DocumentState;
|
||||
use IFrameLoadInfo;
|
||||
use IFrameLoadInfoWithData;
|
||||
use LayoutControlMsg;
|
||||
use LoadData;
|
||||
use MozBrowserEvent;
|
||||
use WorkerGlobalScopeInit;
|
||||
|
@ -105,7 +107,9 @@ pub enum ScriptMsg {
|
|||
/// Notifies constellation that an iframe's visibility has been changed.
|
||||
VisibilityChangeComplete(PipelineId, bool),
|
||||
/// A load has been requested in an IFrame.
|
||||
ScriptLoadedURLInIFrame(IFrameLoadInfo),
|
||||
ScriptLoadedURLInIFrame(IFrameLoadInfoWithData),
|
||||
/// A load of `about:blank` has been completed in an IFrame.
|
||||
ScriptLoadedAboutBlankInIFrame(IFrameLoadInfo, IpcSender<LayoutControlMsg>),
|
||||
/// Requests that the constellation set the contents of the clipboard
|
||||
SetClipboardContents(String),
|
||||
/// Mark a new document as active
|
||||
|
|
Загрузка…
Ссылка в новой задаче