Skip to content

Commit

Permalink
Implement dissimilar-origin window.parent and window.top.
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan Jeffrey committed Mar 17, 2017
1 parent 0b590ae commit 6bcb5f6
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 87 deletions.
13 changes: 12 additions & 1 deletion components/constellation/constellation.rs
Expand Up @@ -1092,7 +1092,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::TouchEventProcessed(result) => {
self.compositor_proxy.send(ToCompositorMsg::TouchEventProcessed(result))
}

FromScriptMsg::GetFrameId(pipeline_id, sender) => {
let result = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);
if let Err(e) = sender.send(result) {
warn!("Sending reply to get frame id failed ({:?}).", e);
}
}
FromScriptMsg::GetParentInfo(pipeline_id, sender) => {
let result = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info);
if let Err(e) = sender.send(result) {
warn!("Sending reply to get parent info failed ({:?}).", e);
}
}
FromScriptMsg::RegisterServiceWorker(scope_things, scope) => {
debug!("constellation got store registration scope message");
self.handle_register_serviceworker(scope_things, scope);
Expand Down
77 changes: 70 additions & 7 deletions components/script/dom/browsingcontext.rs
Expand Up @@ -63,25 +63,35 @@ pub struct BrowsingContext {

/// The containing iframe element, if this is a same-origin iframe
frame_element: Option<JS<Element>>,

/// The parent browsing context, if this is a nested browsing context
parent: Option<JS<BrowsingContext>>,
}

impl BrowsingContext {
pub fn new_inherited(frame_id: FrameId,
currently_active: PipelineId,
frame_element: Option<&Element>)
currently_active: Option<PipelineId>,
frame_element: Option<&Element>,
parent: Option<&BrowsingContext>)
-> BrowsingContext
{
BrowsingContext {
reflector: Reflector::new(),
frame_id: frame_id,
currently_active: Cell::new(Some(currently_active)),
currently_active: Cell::new(currently_active),
discarded: Cell::new(false),
frame_element: frame_element.map(JS::from_ref),
parent: parent.map(JS::from_ref),
}
}

#[allow(unsafe_code)]
pub fn new(window: &Window, frame_id: FrameId, frame_element: Option<&Element>) -> Root<BrowsingContext> {
pub fn new(window: &Window,
frame_id: FrameId,
frame_element: Option<&Element>,
parent: Option<&BrowsingContext>)
-> Root<BrowsingContext>
{
unsafe {
let WindowProxyHandler(handler) = window.windowproxy_handler();
assert!(!handler.is_null());
Expand All @@ -97,8 +107,48 @@ impl BrowsingContext {
assert!(!window_proxy.is_null());

// Create a new browsing context.
let currently_active = window.global().pipeline_id();
let mut browsing_context = box BrowsingContext::new_inherited(frame_id, currently_active, frame_element);
let current = Some(window.global().pipeline_id());
let mut browsing_context = box BrowsingContext::new_inherited(frame_id, current, frame_element, parent);

// The window proxy owns the browsing context.
// When we finalize the window proxy, it drops the browsing context it owns.
SetProxyExtra(window_proxy.get(), 0, &PrivateValue(&*browsing_context as *const _ as *const _));

// Notify the JS engine about the new window proxy binding.
SetWindowProxy(cx, window_jsobject, window_proxy.handle());

// Set the reflector.
debug!("Initializing reflector of {:p} to {:p}.", browsing_context, window_proxy.get());
browsing_context.reflector.set_jsobject(window_proxy.get());
Root::from_ref(&*Box::into_raw(browsing_context))
}
}

#[allow(unsafe_code)]
pub fn new_dissimilar_origin(global_to_clone_from: &GlobalScope,
frame_id: FrameId,
parent: Option<&BrowsingContext>)
-> Root<BrowsingContext>
{
unsafe {
let handler = CreateWrapperProxyHandler(&XORIGIN_PROXY_HANDLER);
assert!(!handler.is_null());

let cx = global_to_clone_from.get_cx();

// Create a new browsing context.
let mut browsing_context = box BrowsingContext::new_inherited(frame_id, None, None, parent);

// Create a new dissimilar-origin window.
let window = DissimilarOriginWindow::new(global_to_clone_from, &*browsing_context);
let window_jsobject = window.reflector().get_jsobject();
assert!(!window_jsobject.get().is_null());
assert!(((*get_object_class(window_jsobject.get())).flags & JSCLASS_IS_GLOBAL) != 0);
let _ac = JSAutoCompartment::new(cx, window_jsobject.get());

// Create a new window proxy.
rooted!(in(cx) let window_proxy = NewWindowProxy(cx, window_jsobject, handler));
assert!(!window_proxy.is_null());

// The window proxy owns the browsing context.
// When we finalize the window proxy, it drops the browsing context it owns.
Expand Down Expand Up @@ -130,6 +180,18 @@ impl BrowsingContext {
self.frame_element.r()
}

pub fn parent(&self) -> Option<&BrowsingContext> {
self.parent.r()
}

pub fn top(&self) -> &BrowsingContext {
let mut result = self;
while let Some(parent) = result.parent() {
result = parent;
}
result
}

#[allow(unsafe_code)]
/// Change the Window that this browsing context's WindowProxy resolves to.
// TODO: support setting the window proxy to a dummy value,
Expand Down Expand Up @@ -181,7 +243,8 @@ impl BrowsingContext {
}

pub fn unset_currently_active(&self) {
let window = DissimilarOriginWindow::new(self);
let globalscope = self.global();
let window = DissimilarOriginWindow::new(&*globalscope, self);
self.set_window_proxy(&*window.upcast(), &XORIGIN_PROXY_HANDLER);
self.currently_active.set(None);
}
Expand Down
36 changes: 23 additions & 13 deletions components/script/dom/dissimilaroriginwindow.rs
Expand Up @@ -7,7 +7,6 @@ use dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding::DissimilarO
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableJS, Root};
use dom::bindings::reflector::DomObject;
use dom::bindings::str::DOMString;
use dom::bindings::structuredclone::StructuredCloneData;
use dom::browsingcontext::BrowsingContext;
Expand Down Expand Up @@ -45,19 +44,18 @@ pub struct DissimilarOriginWindow {

impl DissimilarOriginWindow {
#[allow(unsafe_code)]
pub fn new(browsing_context: &BrowsingContext) -> Root<DissimilarOriginWindow> {
let globalscope = browsing_context.global();
let cx = globalscope.get_cx();
pub fn new(global_to_clone_from: &GlobalScope, browsing_context: &BrowsingContext) -> Root<DissimilarOriginWindow> {
let cx = global_to_clone_from.get_cx();
// Any timer events fired on this window are ignored.
let (timer_event_chan, _) = ipc::channel().unwrap();
let win = box DissimilarOriginWindow {
globalscope: GlobalScope::new_inherited(PipelineId::new(),
globalscope.devtools_chan().cloned(),
globalscope.mem_profiler_chan().clone(),
globalscope.time_profiler_chan().clone(),
globalscope.constellation_chan().clone(),
globalscope.scheduler_chan().clone(),
globalscope.resource_threads().clone(),
global_to_clone_from.devtools_chan().cloned(),
global_to_clone_from.mem_profiler_chan().clone(),
global_to_clone_from.time_profiler_chan().clone(),
global_to_clone_from.constellation_chan().clone(),
global_to_clone_from.scheduler_chan().clone(),
global_to_clone_from.resource_threads().clone(),
timer_event_chan),
browsing_context: JS::from_ref(browsing_context),
location: MutNullableJS::new(None),
Expand All @@ -84,14 +82,26 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {

// https://html.spec.whatwg.org/multipage/#dom-parent
fn GetParent(&self) -> Option<Root<BrowsingContext>> {
// TODO: implement window.parent correctly for x-origin windows.
// Steps 1-3.
if self.browsing_context.is_discarded() {
return None;
}
// Step 4.
if let Some(parent) = self.browsing_context.parent() {
return Some(Root::from_ref(parent));
}
// Step 5.
Some(Root::from_ref(&*self.browsing_context))
}

// https://html.spec.whatwg.org/multipage/#dom-top
fn GetTop(&self) -> Option<Root<BrowsingContext>> {
// TODO: implement window.top correctly for x-origin windows.
Some(Root::from_ref(&*self.browsing_context))
// Steps 1-3.
if self.browsing_context.is_discarded() {
return None;
}
// Steps 4-5.
Some(Root::from_ref(self.browsing_context.top()))
}

// https://html.spec.whatwg.org/multipage/#dom-length
Expand Down
50 changes: 22 additions & 28 deletions components/script/dom/window.rs
Expand Up @@ -42,7 +42,7 @@ use dom::location::Location;
use dom::mediaquerylist::{MediaQueryList, WeakMediaQueryListVec};
use dom::messageevent::MessageEvent;
use dom::navigator::Navigator;
use dom::node::{Node, NodeDamage, document_from_node, from_untrusted_node_address, window_from_node};
use dom::node::{Node, NodeDamage, document_from_node, from_untrusted_node_address};
use dom::performance::Performance;
use dom::promise::Promise;
use dom::screen::Screen;
Expand Down Expand Up @@ -631,31 +631,35 @@ impl WindowMethods for Window {

// https://html.spec.whatwg.org/multipage/#dom-parent
fn GetParent(&self) -> Option<Root<BrowsingContext>> {
// Steps 1. and 2.
if self.maybe_browsing_context().map_or(true, |c| c.is_discarded()) {
// Steps 1-3.
let context = match self.maybe_browsing_context() {
Some(context) => context,
None => return None,
};
if context.is_discarded() {
return None;
}
match self.parent() {
// Step 4.
Some(parent) => Some(parent.Window()),
// Step 5.
None => Some(self.Window())
// Step 4.
if let Some(parent) = context.parent() {
return Some(Root::from_ref(parent));
}
}
// Step 5.
Some(context)
}

// https://html.spec.whatwg.org/multipage/#dom-top
fn GetTop(&self) -> Option<Root<BrowsingContext>> {
// Steps 1. and 2.
if self.maybe_browsing_context().map_or(true, |c| c.is_discarded()) {
// Steps 1-3.
let context = match self.maybe_browsing_context() {
Some(context) => context,
None => return None,
};
if context.is_discarded() {
return None;
}
// Step 5.
let mut window = Root::from_ref(self);
while let Some(parent) = window.parent() {
window = parent;
}
Some(window.Window())
}
// Steps 4-5.
Some(Root::from_ref(context.top()))
}

// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/
// NavigationTiming/Overview.html#sec-window.performance-attribute
Expand Down Expand Up @@ -1657,16 +1661,6 @@ impl Window {
}
}

// https://html.spec.whatwg.org/multipage/#parent-browsing-context
pub fn parent(&self) -> Option<Root<Window>> {
if self.is_top_level() {
return None;
}

self.browsing_context().frame_element()
.map(|frame_element| window_from_node(frame_element))
}

/// Returns whether this window is mozbrowser.
pub fn is_mozbrowser(&self) -> bool {
PREFS.is_mozbrowser_enabled() && self.parent_info().is_none()
Expand Down

0 comments on commit 6bcb5f6

Please sign in to comment.