From d54a45a2b1e4fe5109d8292483e538252da240f1 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Fri, 9 Jan 2015 16:36:05 +0100 Subject: [PATCH] Implement most of the important WindowProxy traps --- components/script/dom/browsercontext.rs | 125 ++++++++++++++++-- components/script/dom/window.rs | 7 +- components/script/lib.rs | 2 +- tests/content/test_windowproxy.html | 23 ++++ .../window-indexed-properties.html.ini | 4 - 5 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 tests/content/test_windowproxy.html diff --git a/components/script/dom/browsercontext.rs b/components/script/dom/browsercontext.rs index 9cc2a94fdb9d..959c021b4bc9 100644 --- a/components/script/dom/browsercontext.rs +++ b/components/script/dom/browsercontext.rs @@ -2,14 +2,27 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use dom::bindings::js::{JS, JSRef, Temporary}; +use dom::bindings::conversions::unwrap_jsmanaged; +use dom::bindings::conversions::{ToJSValConvertible}; +use dom::bindings::js::{JS, JSRef, Temporary, Root}; +use dom::bindings::js::{OptionalRootable, OptionalRootedRootable, ResultRootable}; +use dom::bindings::js::{OptionalRootedReference, OptionalOptionalRootedRootable}; +use dom::bindings::proxyhandler::{getPropertyDescriptor, FillPropertyDescriptor}; use dom::bindings::utils::{Reflectable, WindowProxyHandler}; +use dom::bindings::utils::{GetArrayIndexFromId}; use dom::document::{Document, DocumentHelpers}; use dom::window::Window; - -use js::jsapi::JSObject; +use dom::window::WindowHelpers; + +use js::jsapi::{JSContext, JSObject, jsid, JSPropertyDescriptor}; +use js::jsapi::{JS_AlreadyHasOwnPropertyById, JS_ForwardGetPropertyTo}; +use js::jsapi::{JS_GetPropertyDescriptorById, JS_DefinePropertyById}; +use js::jsapi::{JS_SetPropertyById}; +use js::jsval::JSVal; +use js::glue::{GetProxyPrivate}; use js::glue::{WrapperNew, CreateWrapperProxyHandler, ProxyTraps}; use js::rust::with_compartment; +use js::{JSRESOLVE_QUALIFIED, JSRESOLVE_ASSIGNING}; use std::ptr; @@ -86,18 +99,112 @@ impl SessionHistoryEntry { } } +unsafe fn GetSubframeWindow(cx: *mut JSContext, proxy: *mut JSObject, id: jsid) -> Option> { + let index = GetArrayIndexFromId(cx, id); + if let Some(index) = index { + let target = GetProxyPrivate(proxy).to_object(); + let win: Root = unwrap_jsmanaged(target).unwrap().root(); + let mut found = false; + return win.r().IndexedGetter(index, &mut found); + } + + None +} + +unsafe extern fn getOwnPropertyDescriptor(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, set: bool, desc: *mut JSPropertyDescriptor) -> bool { + let window = GetSubframeWindow(cx, proxy, id); + if let Some(window) = window { + let window = window.root(); + (*desc).value = window.to_jsval(cx); + FillPropertyDescriptor(&mut *desc, proxy, true); + return true; + } + + let target = GetProxyPrivate(proxy).to_object(); + let flags = if set { JSRESOLVE_ASSIGNING } else { 0 } | JSRESOLVE_QUALIFIED; + // XXX This should be JS_GetOwnPropertyDescriptorById + if JS_GetPropertyDescriptorById(cx, target, id, flags, desc) == 0 { + return false; + } + + if (*desc).obj != target { + // Not an own property + (*desc).obj = ptr::null_mut(); + } else { + (*desc).obj = proxy; + } + + true +} + + +unsafe extern fn defineProperty(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, desc: *mut JSPropertyDescriptor) -> bool { + if GetArrayIndexFromId(cx, id).is_some() { + // Spec says to Reject whether this is a supported index or not, + // since we have no indexed setter or indexed creator. That means + // throwing in strict mode (FIXME: Bug 828137), doing nothing in + // non-strict mode. + return true; + } + + let target = GetProxyPrivate(proxy).to_object(); + JS_DefinePropertyById(cx, target, id, (*desc).value, (*desc).getter, + (*desc).setter, (*desc).attrs) != 0 +} + +unsafe extern fn hasOwn(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, bp: *mut bool) -> bool { + let window = GetSubframeWindow(cx, proxy, id); + if window.is_some() { + *bp = true; + return true; + } + + let target = GetProxyPrivate(proxy).to_object(); + let mut found = 0; + if JS_AlreadyHasOwnPropertyById(cx, target, id, &mut found) == 0 { + return false; + } + + *bp = found != 0; + return true; +} + +unsafe extern fn get(cx: *mut JSContext, proxy: *mut JSObject, receiver: *mut JSObject, id: jsid, vp: *mut JSVal) -> bool { + let window = GetSubframeWindow(cx, proxy, id); + if let Some(window) = window { + let window = window.root(); + *vp = window.to_jsval(cx); + return true; + } + + let target = GetProxyPrivate(proxy).to_object(); + JS_ForwardGetPropertyTo(cx, target, id, receiver, vp) != 0 +} + +unsafe extern fn set(cx: *mut JSContext, proxy: *mut JSObject, _receiver: *mut JSObject, id: jsid, _strict: bool, vp: *mut JSVal) -> bool { + if GetArrayIndexFromId(cx, id).is_some() { + // Reject (which means throw if and only if strict) the set. + // FIXME: Throw + return true; + } + + // FIXME: The receiver should be used, we need something like JS_ForwardSetPropertyTo. + let target = GetProxyPrivate(proxy).to_object(); + JS_SetPropertyById(cx, target, id, vp) != 0 +} + static PROXY_HANDLER: ProxyTraps = ProxyTraps { - getPropertyDescriptor: None, - getOwnPropertyDescriptor: None, - defineProperty: None, + getPropertyDescriptor: Some(getPropertyDescriptor), + getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor), + defineProperty: Some(defineProperty), getOwnPropertyNames: None, delete_: None, enumerate: None, has: None, - hasOwn: None, - get: None, - set: None, + hasOwn: Some(hasOwn), + get: Some(get), + set: Some(set), keys: None, iterate: None, diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 91d023eec182..91402fe6c1fd 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -311,12 +311,12 @@ impl<'a> WindowMethods for JSRef<'a, Window> { } } - pub trait WindowHelpers { fn flush_layout(self, goal: ReflowGoal, query: ReflowQueryType); fn init_browser_context(self, doc: JSRef); fn load_url(self, href: DOMString); fn handle_fire_timer(self, timer_id: TimerId); + fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option>; } pub trait ScriptHelpers { @@ -378,6 +378,11 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { self.timers.fire_timer(timer_id, self); self.flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery); } + + // https://html.spec.whatwg.org/multipage/browsers.html#accessing-other-browsing-contexts + fn IndexedGetter(self, _index: u32, _found: &mut bool) -> Option> { + None + } } impl Window { diff --git a/components/script/lib.rs b/components/script/lib.rs index 50661a60ca14..7593a3b68a3a 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -62,7 +62,7 @@ pub mod dom { pub mod callback; pub mod error; pub mod conversions; - mod proxyhandler; + pub mod proxyhandler; pub mod str; pub mod structuredclone; pub mod trace; diff --git a/tests/content/test_windowproxy.html b/tests/content/test_windowproxy.html new file mode 100644 index 000000000000..71c55211fd58 --- /dev/null +++ b/tests/content/test_windowproxy.html @@ -0,0 +1,23 @@ + + + + + +
+ + + diff --git a/tests/wpt/metadata/html/browsers/the-window-object/window-indexed-properties.html.ini b/tests/wpt/metadata/html/browsers/the-window-object/window-indexed-properties.html.ini index 93e90eb6148f..498ea7d0b6f9 100644 --- a/tests/wpt/metadata/html/browsers/the-window-object/window-indexed-properties.html.ini +++ b/tests/wpt/metadata/html/browsers/the-window-object/window-indexed-properties.html.ini @@ -2,7 +2,3 @@ type: testharness [Indexed properties of the window object (non-strict mode) 1] expected: FAIL - - [Indexed properties of the window object (non-strict mode) 2] - expected: FAIL -