mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
implement opener, disowning
This commit is contained in:
parent
f408b798c4
commit
21bf5a3a4b
32 changed files with 273 additions and 143 deletions
|
@ -177,6 +177,7 @@ impl HTMLIFrameElement {
|
|||
new_pipeline_id: new_pipeline_id,
|
||||
browsing_context_id: browsing_context_id,
|
||||
top_level_browsing_context_id: top_level_browsing_context_id,
|
||||
opener: None,
|
||||
load_data: load_data.unwrap(),
|
||||
pipeline_port: pipeline_receiver,
|
||||
content_process_shutdown_chan: None,
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
// Note that this can return null in the case that the browsing context has been discarded.
|
||||
// https://github.com/whatwg/html/issues/2115
|
||||
[Unforgeable] readonly attribute WindowProxy? top;
|
||||
// attribute any opener;
|
||||
attribute any opener;
|
||||
// Note that this can return null in the case that the browsing context has been discarded.
|
||||
// https://github.com/whatwg/html/issues/2115
|
||||
[Replaceable] readonly attribute WindowProxy? parent;
|
||||
|
|
|
@ -61,10 +61,12 @@ use fetch;
|
|||
use ipc_channel::ipc::IpcSender;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::jsapi::{JSAutoCompartment, JSContext};
|
||||
use js::jsapi::{JS_GC, JS_GetRuntime};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::jsapi::{JS_GC, JS_GetRuntime, JSPROP_ENUMERATE};
|
||||
use js::jsval::{JSVal, UndefinedValue};
|
||||
use js::rust::HandleValue;
|
||||
use js::rust::wrappers::JS_DefineProperty;
|
||||
use layout_image::fetch_image_for_layout;
|
||||
use libc;
|
||||
use microtask::MicrotaskQueue;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::{ResourceThreads, ReferrerPolicy};
|
||||
|
@ -574,6 +576,30 @@ impl WindowMethods for Window {
|
|||
self.window_proxy().open(url, target, features)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://html.spec.whatwg.org/multipage/#dom-opener
|
||||
unsafe fn Opener(&self, cx: *mut JSContext) -> JSVal {
|
||||
self.window_proxy().opener(cx)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://html.spec.whatwg.org/multipage/#dom-opener
|
||||
unsafe fn SetOpener(&self, cx: *mut JSContext, value: HandleValue) {
|
||||
// Step 1.
|
||||
if value.is_null() {
|
||||
return self.window_proxy().disown();
|
||||
}
|
||||
// Step 2.
|
||||
let obj = self.reflector().get_jsobject();
|
||||
assert!(JS_DefineProperty(cx,
|
||||
obj,
|
||||
"opener\0".as_ptr() as *const libc::c_char,
|
||||
value,
|
||||
JSPROP_ENUMERATE,
|
||||
None,
|
||||
None));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-window-closed
|
||||
fn Closed(&self) -> bool {
|
||||
self.window_proxy.get()
|
||||
|
|
|
@ -36,7 +36,7 @@ use js::jsapi::HandleValue as RawHandleValue;
|
|||
use js::jsapi::MutableHandle as RawMutableHandle;
|
||||
use js::jsapi::MutableHandleObject as RawMutableHandleObject;
|
||||
use js::jsapi::MutableHandleValue as RawMutableHandleValue;
|
||||
use js::jsval::{UndefinedValue, PrivateValue};
|
||||
use js::jsval::{JSVal, NullValue, UndefinedValue, PrivateValue};
|
||||
use js::rust::{Handle, MutableHandle};
|
||||
use js::rust::get_object_class;
|
||||
use js::rust::wrappers::{NewWindowProxy, SetWindowProxy, JS_TransplantObject};
|
||||
|
@ -67,6 +67,9 @@ pub struct WindowProxy {
|
|||
/// of the container.
|
||||
browsing_context_id: BrowsingContextId,
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#opener-browsing-context
|
||||
opener: Option<BrowsingContextId>,
|
||||
|
||||
/// The frame id of the top-level ancestor browsing context.
|
||||
/// In the case that this is a top-level window, this is our id.
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
|
@ -83,6 +86,9 @@ pub struct WindowProxy {
|
|||
/// Has the browsing context been discarded?
|
||||
discarded: Cell<bool>,
|
||||
|
||||
/// Has the browsing context been disowned?
|
||||
disowned: Cell<bool>,
|
||||
|
||||
/// The containing iframe element, if this is a same-origin iframe
|
||||
frame_element: Option<Dom<Element>>,
|
||||
|
||||
|
@ -95,7 +101,8 @@ impl WindowProxy {
|
|||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
currently_active: Option<PipelineId>,
|
||||
frame_element: Option<&Element>,
|
||||
parent: Option<&WindowProxy>)
|
||||
parent: Option<&WindowProxy>,
|
||||
opener: Option<BrowsingContextId>)
|
||||
-> WindowProxy
|
||||
{
|
||||
let name = frame_element.map_or(DOMString::new(), |e| e.get_string_attribute(&local_name!("name")));
|
||||
|
@ -106,8 +113,10 @@ impl WindowProxy {
|
|||
name: DomRefCell::new(name),
|
||||
currently_active: Cell::new(currently_active),
|
||||
discarded: Cell::new(false),
|
||||
disowned: Cell::new(false),
|
||||
frame_element: frame_element.map(Dom::from_ref),
|
||||
parent: parent.map(Dom::from_ref),
|
||||
opener,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,7 +125,8 @@ impl WindowProxy {
|
|||
browsing_context_id: BrowsingContextId,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
frame_element: Option<&Element>,
|
||||
parent: Option<&WindowProxy>)
|
||||
parent: Option<&WindowProxy>,
|
||||
opener: Option<BrowsingContextId>)
|
||||
-> DomRoot<WindowProxy>
|
||||
{
|
||||
unsafe {
|
||||
|
@ -140,7 +150,8 @@ impl WindowProxy {
|
|||
top_level_browsing_context_id,
|
||||
current,
|
||||
frame_element,
|
||||
parent
|
||||
parent,
|
||||
opener,
|
||||
));
|
||||
|
||||
// The window proxy owns the browsing context.
|
||||
|
@ -161,7 +172,8 @@ impl WindowProxy {
|
|||
pub fn new_dissimilar_origin(global_to_clone_from: &GlobalScope,
|
||||
browsing_context_id: BrowsingContextId,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
parent: Option<&WindowProxy>)
|
||||
parent: Option<&WindowProxy>,
|
||||
opener: Option<BrowsingContextId>)
|
||||
-> DomRoot<WindowProxy>
|
||||
{
|
||||
unsafe {
|
||||
|
@ -176,7 +188,8 @@ impl WindowProxy {
|
|||
top_level_browsing_context_id,
|
||||
None,
|
||||
None,
|
||||
parent
|
||||
parent,
|
||||
opener
|
||||
));
|
||||
|
||||
// Create a new dissimilar-origin window.
|
||||
|
@ -205,7 +218,7 @@ impl WindowProxy {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#auxiliary-browsing-context
|
||||
fn create_auxiliary_browsing_context(&self, name: DOMString, _noopener: bool) -> Option<DomRoot<WindowProxy>> {
|
||||
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))
|
||||
|
@ -237,6 +250,7 @@ impl WindowProxy {
|
|||
new_pipeline_id: new_pipeline_id,
|
||||
browsing_context_id: new_browsing_context_id,
|
||||
top_level_browsing_context_id: new_top_level_browsing_context_id,
|
||||
opener: Some(self.browsing_context_id),
|
||||
load_data: load_data,
|
||||
pipeline_port: pipeline_receiver,
|
||||
content_process_shutdown_chan: None,
|
||||
|
@ -248,17 +262,64 @@ impl WindowProxy {
|
|||
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);
|
||||
// TODO: if noopener is false, copy the sessionStorage storage area of the creator origin.
|
||||
// See step 14 of https://html.spec.whatwg.org/multipage/#creating-a-new-browsing-context
|
||||
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);
|
||||
}
|
||||
if noopener {
|
||||
proxy.disown();
|
||||
}
|
||||
return Some(proxy)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#disowned-its-opener
|
||||
pub fn disown(&self) {
|
||||
self.disowned.set(true);
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
// https://html.spec.whatwg.org/multipage/#dom-opener
|
||||
pub unsafe fn opener(&self, cx: *mut JSContext) -> JSVal {
|
||||
if self.disowned.get() {
|
||||
return NullValue()
|
||||
}
|
||||
let opener_id = match self.opener {
|
||||
Some(opener_browsing_context_id) => opener_browsing_context_id,
|
||||
None => return NullValue()
|
||||
};
|
||||
let opener_proxy = match ScriptThread::find_window_proxy(opener_id) {
|
||||
Some(window_proxy) => window_proxy,
|
||||
None => {
|
||||
let sender_pipeline_id = self.currently_active().unwrap();
|
||||
match ScriptThread::get_top_level_for_browsing_context(sender_pipeline_id, opener_id) {
|
||||
Some(opener_top_id) => {
|
||||
let global_to_clone_from = GlobalScope::from_context(cx);
|
||||
WindowProxy::new_dissimilar_origin(
|
||||
&*global_to_clone_from,
|
||||
opener_id,
|
||||
opener_top_id,
|
||||
None,
|
||||
None
|
||||
)
|
||||
},
|
||||
None => return NullValue()
|
||||
}
|
||||
}
|
||||
};
|
||||
if opener_proxy.is_browsing_context_discarded() {
|
||||
return NullValue()
|
||||
}
|
||||
rooted!(in(cx) let mut val = UndefinedValue());
|
||||
opener_proxy.to_jsval(cx, val.handle_mut());
|
||||
return val.get()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#window-open-steps
|
||||
pub fn open(&self,
|
||||
url: DOMString,
|
||||
|
@ -314,7 +375,11 @@ impl WindowProxy {
|
|||
},
|
||||
"_parent" => {
|
||||
// Step 4
|
||||
(Some(DomRoot::from_ref(self.parent().unwrap())), false)
|
||||
if let Some(parent) = self.parent() {
|
||||
return (Some(DomRoot::from_ref(parent)), false)
|
||||
}
|
||||
(None, false)
|
||||
|
||||
},
|
||||
"_top" => {
|
||||
// Step 5
|
||||
|
@ -336,6 +401,10 @@ impl WindowProxy {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_auxiliary(&self) -> bool {
|
||||
self.opener.is_some()
|
||||
}
|
||||
|
||||
pub fn discard_browsing_context(&self) {
|
||||
self.discarded.set(true);
|
||||
}
|
||||
|
|
|
@ -157,6 +157,8 @@ struct InProgressLoad {
|
|||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
/// The parent pipeline and frame type associated with this load, if any.
|
||||
parent_info: Option<PipelineId>,
|
||||
/// The opener, if this is an auxiliary.
|
||||
opener: Option<BrowsingContextId>,
|
||||
/// The current window size associated with this pipeline.
|
||||
window_size: Option<WindowSizeData>,
|
||||
/// Channel to the layout thread associated with this pipeline.
|
||||
|
@ -183,6 +185,7 @@ impl InProgressLoad {
|
|||
browsing_context_id: BrowsingContextId,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
parent_info: Option<PipelineId>,
|
||||
opener: Option<BrowsingContextId>,
|
||||
layout_chan: Sender<message::Msg>,
|
||||
window_size: Option<WindowSizeData>,
|
||||
url: ServoUrl,
|
||||
|
@ -195,6 +198,7 @@ impl InProgressLoad {
|
|||
browsing_context_id: browsing_context_id,
|
||||
top_level_browsing_context_id: top_level_browsing_context_id,
|
||||
parent_info: parent_info,
|
||||
opener: opener,
|
||||
layout_chan: layout_chan,
|
||||
window_size: window_size,
|
||||
activity: DocumentActivity::FullyActive,
|
||||
|
@ -569,6 +573,7 @@ impl ScriptThreadFactory for ScriptThread {
|
|||
let browsing_context_id = state.browsing_context_id;
|
||||
let top_level_browsing_context_id = state.top_level_browsing_context_id;
|
||||
let parent_info = state.parent_info;
|
||||
let opener = state.opener;
|
||||
let mem_profiler_chan = state.mem_profiler_chan.clone();
|
||||
let window_size = state.window_size;
|
||||
let script_thread = ScriptThread::new(state,
|
||||
|
@ -583,7 +588,7 @@ impl ScriptThreadFactory for ScriptThread {
|
|||
|
||||
let origin = MutableOrigin::new(load_data.url.origin());
|
||||
let new_load = InProgressLoad::new(id, browsing_context_id, top_level_browsing_context_id, parent_info,
|
||||
layout_chan, window_size, load_data.url.clone(), origin);
|
||||
opener, layout_chan, window_size, load_data.url.clone(), origin);
|
||||
script_thread.pre_page_load(new_load, load_data);
|
||||
|
||||
let reporter_name = format!("script-reporter-{}", id);
|
||||
|
@ -706,6 +711,15 @@ impl ScriptThread {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn get_top_level_for_browsing_context(sender_pipeline: PipelineId,
|
||||
browsing_context_id: BrowsingContextId)
|
||||
-> Option<TopLevelBrowsingContextId> {
|
||||
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
|
||||
let script_thread = unsafe { &*script_thread };
|
||||
script_thread.ask_constellation_for_top_level_info(sender_pipeline, browsing_context_id)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn find_document(id: PipelineId) -> Option<DomRoot<Document>> {
|
||||
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
|
||||
let script_thread = unsafe { &*script_thread };
|
||||
|
@ -1553,6 +1567,7 @@ impl ScriptThread {
|
|||
new_pipeline_id,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
opener,
|
||||
load_data,
|
||||
window_size,
|
||||
pipeline_port,
|
||||
|
@ -1597,6 +1612,7 @@ impl ScriptThread {
|
|||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
parent_info,
|
||||
opener,
|
||||
layout_chan,
|
||||
window_size,
|
||||
load_data.url.clone(),
|
||||
|
@ -2025,6 +2041,16 @@ impl ScriptThread {
|
|||
result_receiver.recv().expect("Failed to get frame id from constellation.")
|
||||
}
|
||||
|
||||
fn ask_constellation_for_top_level_info(&self,
|
||||
sender_pipeline: PipelineId,
|
||||
browsing_context_id: BrowsingContextId)
|
||||
-> Option<TopLevelBrowsingContextId> {
|
||||
let (result_sender, result_receiver) = ipc::channel().unwrap();
|
||||
let msg = ScriptMsg::GetTopForBrowsingContext(browsing_context_id, result_sender);
|
||||
self.script_sender.send((sender_pipeline, msg)).expect("Failed to send to constellation.");
|
||||
result_receiver.recv().expect("Failed to get top-level id from constellation.")
|
||||
}
|
||||
|
||||
// Get the browsing context for a pipeline that may exist in another
|
||||
// script thread. If the browsing context already exists in the
|
||||
// `window_proxies` map, we return it, otherwise we recursively
|
||||
|
@ -2034,7 +2060,8 @@ impl ScriptThread {
|
|||
fn remote_window_proxy(&self,
|
||||
global_to_clone: &GlobalScope,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
pipeline_id: PipelineId)
|
||||
pipeline_id: PipelineId,
|
||||
opener: Option<BrowsingContextId>)
|
||||
-> Option<DomRoot<WindowProxy>>
|
||||
{
|
||||
let browsing_context_id = self.ask_constellation_for_browsing_context_id(pipeline_id)?;
|
||||
|
@ -2042,12 +2069,13 @@ impl ScriptThread {
|
|||
return Some(DomRoot::from_ref(window_proxy));
|
||||
}
|
||||
let parent = self.ask_constellation_for_parent_info(pipeline_id).and_then(|parent_id| {
|
||||
self.remote_window_proxy(global_to_clone, top_level_browsing_context_id, parent_id)
|
||||
self.remote_window_proxy(global_to_clone, top_level_browsing_context_id, parent_id, opener)
|
||||
});
|
||||
let window_proxy = WindowProxy::new_dissimilar_origin(global_to_clone,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
parent.r());
|
||||
parent.r(),
|
||||
opener);
|
||||
self.window_proxies.borrow_mut().insert(browsing_context_id, Dom::from_ref(&*window_proxy));
|
||||
Some(window_proxy)
|
||||
}
|
||||
|
@ -2062,7 +2090,8 @@ impl ScriptThread {
|
|||
window: &Window,
|
||||
browsing_context_id: BrowsingContextId,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
parent_info: Option<PipelineId>)
|
||||
parent_info: Option<PipelineId>,
|
||||
opener: Option<BrowsingContextId>)
|
||||
-> DomRoot<WindowProxy>
|
||||
{
|
||||
if let Some(window_proxy) = self.window_proxies.borrow().get(&browsing_context_id) {
|
||||
|
@ -2075,15 +2104,17 @@ impl ScriptThread {
|
|||
let parent = match (parent_info, iframe.as_ref()) {
|
||||
(_, Some(iframe)) => Some(window_from_node(&**iframe).window_proxy()),
|
||||
(Some(parent_id), _) => self.remote_window_proxy(window.upcast(),
|
||||
top_level_browsing_context_id,
|
||||
parent_id),
|
||||
top_level_browsing_context_id,
|
||||
parent_id,
|
||||
opener),
|
||||
_ => None,
|
||||
};
|
||||
let window_proxy = WindowProxy::new(&window,
|
||||
browsing_context_id,
|
||||
top_level_browsing_context_id,
|
||||
iframe.r().map(Castable::upcast),
|
||||
parent.r());
|
||||
parent.r(),
|
||||
opener);
|
||||
self.window_proxies.borrow_mut().insert(browsing_context_id, Dom::from_ref(&*window_proxy));
|
||||
window_proxy
|
||||
}
|
||||
|
@ -2162,7 +2193,8 @@ impl ScriptThread {
|
|||
let window_proxy = self.local_window_proxy(&window,
|
||||
incomplete.browsing_context_id,
|
||||
incomplete.top_level_browsing_context_id,
|
||||
incomplete.parent_info);
|
||||
incomplete.parent_info,
|
||||
incomplete.opener);
|
||||
window.init_window_proxy(&window_proxy);
|
||||
|
||||
let last_modified = metadata.headers.as_ref().and_then(|headers| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue