mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
implement window.open, create auxiliary browsing context
This commit is contained in:
parent
3e96a322ae
commit
f408b798c4
93 changed files with 476 additions and 324 deletions
|
@ -13,10 +13,12 @@ use dom::bindings::str::DOMString;
|
|||
use dom::bindings::trace::JSTraceable;
|
||||
use dom::bindings::utils::{WindowProxyHandler, get_array_index_from_id, AsVoidPtr};
|
||||
use dom::dissimilaroriginwindow::DissimilarOriginWindow;
|
||||
use dom::document::Document;
|
||||
use dom::element::Element;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::EmbedderMsg;
|
||||
use ipc_channel::ipc;
|
||||
use js::JSCLASS_IS_GLOBAL;
|
||||
use js::glue::{CreateWrapperProxyHandler, ProxyTraps};
|
||||
|
@ -42,7 +44,9 @@ use msg::constellation_msg::BrowsingContextId;
|
|||
use msg::constellation_msg::PipelineId;
|
||||
use msg::constellation_msg::TopLevelBrowsingContextId;
|
||||
use script_thread::ScriptThread;
|
||||
use script_traits::ScriptMsg;
|
||||
use script_traits::{AuxiliaryBrowsingContextLoadInfo, LoadData, NewLayoutInfo, ScriptMsg};
|
||||
use servo_config::prefs::PREFS;
|
||||
use servo_url::ServoUrl;
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
|
||||
|
@ -200,6 +204,138 @@ impl WindowProxy {
|
|||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#auxiliary-browsing-context
|
||||
fn create_auxiliary_browsing_context(&self, name: DOMString, _noopener: bool) -> Option<DomRoot<WindowProxy>> {
|
||||
let (chan, port) = ipc::channel().unwrap();
|
||||
let window = self.currently_active.get()
|
||||
.and_then(|id| ScriptThread::find_document(id))
|
||||
.and_then(|doc| Some(DomRoot::from_ref(doc.window())))
|
||||
.unwrap();
|
||||
let msg = EmbedderMsg::AllowOpeningBrowser(chan);
|
||||
window.send_to_embedder(msg);
|
||||
if port.recv().unwrap() {
|
||||
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 load_info = AuxiliaryBrowsingContextLoadInfo {
|
||||
opener_pipeline_id: self.currently_active.get().unwrap(),
|
||||
new_browsing_context_id: new_browsing_context_id,
|
||||
new_top_level_browsing_context_id: new_top_level_browsing_context_id,
|
||||
new_pipeline_id: new_pipeline_id,
|
||||
};
|
||||
let document = self.currently_active.get()
|
||||
.and_then(|id| ScriptThread::find_document(id))
|
||||
.unwrap();
|
||||
let blank_url = ServoUrl::parse("about:blank").ok().unwrap();
|
||||
let load_data = LoadData::new(blank_url,
|
||||
None,
|
||||
document.get_referrer_policy(),
|
||||
Some(document.url().clone()));
|
||||
let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
|
||||
let new_layout_info = NewLayoutInfo {
|
||||
parent_info: None,
|
||||
new_pipeline_id: new_pipeline_id,
|
||||
browsing_context_id: new_browsing_context_id,
|
||||
top_level_browsing_context_id: new_top_level_browsing_context_id,
|
||||
load_data: load_data,
|
||||
pipeline_port: pipeline_receiver,
|
||||
content_process_shutdown_chan: None,
|
||||
window_size: None,
|
||||
layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize,
|
||||
};
|
||||
let constellation_msg = ScriptMsg::ScriptNewAuxiliary(load_info, pipeline_sender);
|
||||
window.send_to_constellation(constellation_msg);
|
||||
ScriptThread::process_attach_layout(new_layout_info, document.origin().clone());
|
||||
let msg = EmbedderMsg::BrowserCreated(new_top_level_browsing_context_id);
|
||||
window.send_to_embedder(msg);
|
||||
let auxiliary = ScriptThread::find_document(new_pipeline_id).and_then(|doc| doc.browsing_context());
|
||||
if let Some(proxy) = auxiliary {
|
||||
if name.to_lowercase() != "_blank" {
|
||||
proxy.set_name(name);
|
||||
}
|
||||
return Some(proxy)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#window-open-steps
|
||||
pub fn open(&self,
|
||||
url: DOMString,
|
||||
target: DOMString,
|
||||
features: DOMString)
|
||||
-> Option<DomRoot<WindowProxy>> {
|
||||
// Step 3.
|
||||
let non_empty_target = match target.as_ref() {
|
||||
"" => DOMString::from("_blank"),
|
||||
_ => target
|
||||
};
|
||||
// TODO Step 4, properly tokenize features.
|
||||
// Step 5
|
||||
let noopener = features.contains("noopener");
|
||||
// Step 6, 7
|
||||
let (chosen, new) = match self.choose_browsing_context(non_empty_target, noopener) {
|
||||
(Some(chosen), new) => (chosen, new),
|
||||
(None, _) => return None
|
||||
};
|
||||
// TODO Step 8, set up browsing context features.
|
||||
let target_document = match chosen.document() {
|
||||
Some(target_document) => target_document,
|
||||
None => return None
|
||||
};
|
||||
let target_window = target_document.window();
|
||||
// Step 9, and 10.2, will have happened elsewhere,
|
||||
// since we've created a new browsing context and loaded it with about:blank.
|
||||
if !url.is_empty() {
|
||||
let existing_document = self.currently_active.get()
|
||||
.and_then(|id| ScriptThread::find_document(id)).unwrap();
|
||||
// Step 10.1
|
||||
let url = match existing_document.url().join(&url) {
|
||||
Ok(url) => url,
|
||||
Err(_) => return None, // TODO: throw a "SyntaxError" DOMException.
|
||||
};
|
||||
// Step 10.3
|
||||
target_window.load_url(url, new, false, target_document.get_referrer_policy());
|
||||
}
|
||||
if noopener {
|
||||
// Step 11 (Dis-owning has been done in create_auxiliary_browsing_context).
|
||||
return None
|
||||
}
|
||||
// Step 12.
|
||||
return target_document.browsing_context()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
|
||||
pub fn choose_browsing_context(&self, name: DOMString, noopener: bool) -> (Option<DomRoot<WindowProxy>>, bool) {
|
||||
match name.to_lowercase().as_ref() {
|
||||
"" | "_self" => {
|
||||
// Step 3.
|
||||
(Some(DomRoot::from_ref(self)), false)
|
||||
},
|
||||
"_parent" => {
|
||||
// Step 4
|
||||
(Some(DomRoot::from_ref(self.parent().unwrap())), false)
|
||||
},
|
||||
"_top" => {
|
||||
// Step 5
|
||||
(Some(DomRoot::from_ref(self.top())), false)
|
||||
},
|
||||
"_blank" => {
|
||||
(self.create_auxiliary_browsing_context(name, noopener), true)
|
||||
},
|
||||
_ => {
|
||||
// Step 6.
|
||||
// TODO: expand the search to all 'familiar' bc,
|
||||
// including auxiliaries familiar by way of their opener.
|
||||
// See https://html.spec.whatwg.org/multipage/#familiar-with
|
||||
match ScriptThread::find_window_proxy_by_name(&name) {
|
||||
Some(proxy) => (Some(proxy), false),
|
||||
None => (self.create_auxiliary_browsing_context(name, noopener), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn discard_browsing_context(&self) {
|
||||
self.discarded.set(true);
|
||||
}
|
||||
|
@ -220,6 +356,11 @@ impl WindowProxy {
|
|||
self.frame_element.r()
|
||||
}
|
||||
|
||||
pub fn document(&self) -> Option<DomRoot<Document>> {
|
||||
self.currently_active.get()
|
||||
.and_then(|id| ScriptThread::find_document(id))
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<&WindowProxy> {
|
||||
self.parent.r()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue