mirror of
https://github.com/servo/servo.git
synced 2025-08-01 03:30:33 +01:00
234 lines
6.9 KiB
Rust
234 lines
6.9 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* 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 crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
|
use crate::dom::bindings::proxyhandler::set_property_descriptor;
|
|
use crate::dom::bindings::root::Root;
|
|
use crate::dom::bindings::utils::has_property_on_prototype;
|
|
use crate::dom::globalscope::GlobalScope;
|
|
use crate::dom::window::Window;
|
|
use crate::js::conversions::ToJSValConvertible;
|
|
use crate::script_runtime::JSContext as SafeJSContext;
|
|
use js::conversions::jsstr_to_string;
|
|
use js::error::throw_type_error;
|
|
use js::glue::RUST_JSID_TO_STRING;
|
|
use js::glue::{CreateProxyHandler, NewProxyObject, ProxyTraps, RUST_JSID_IS_STRING};
|
|
use js::jsapi::JS_SetImmutablePrototype;
|
|
use js::jsapi::{
|
|
Handle, HandleObject, JSClass, JSContext, JSErrNum, MutableHandleObject, UndefinedHandleValue,
|
|
};
|
|
use js::jsapi::{
|
|
HandleId, JSClass_NON_NATIVE, MutableHandle, MutableHandleIdVector, ObjectOpResult,
|
|
PropertyDescriptor, ProxyClassExtension, ProxyClassOps, ProxyObjectOps,
|
|
JSCLASS_DELAY_METADATA_BUILDER, JSCLASS_IS_PROXY, JSCLASS_RESERVED_SLOTS_MASK,
|
|
JSCLASS_RESERVED_SLOTS_SHIFT,
|
|
};
|
|
use js::jsval::UndefinedValue;
|
|
use js::rust::IntoHandle;
|
|
use js::rust::{Handle as RustHandle, MutableHandle as RustMutableHandle};
|
|
use js::rust::{HandleObject as RustHandleObject, MutableHandleObject as RustMutableHandleObject};
|
|
use libc;
|
|
use std::ptr;
|
|
|
|
struct SyncWrapper(*const libc::c_void);
|
|
#[allow(unsafe_code)]
|
|
unsafe impl Sync for SyncWrapper {}
|
|
|
|
lazy_static! {
|
|
static ref HANDLER: SyncWrapper = {
|
|
let traps = ProxyTraps {
|
|
enter: None,
|
|
getOwnPropertyDescriptor: Some(get_own_property_descriptor),
|
|
defineProperty: Some(define_property),
|
|
ownPropertyKeys: Some(own_property_keys),
|
|
delete_: Some(delete),
|
|
enumerate: None,
|
|
getPrototypeIfOrdinary: Some(get_prototype_if_ordinary),
|
|
getPrototype: None,
|
|
setPrototype: None,
|
|
setImmutablePrototype: None,
|
|
preventExtensions: Some(prevent_extensions),
|
|
isExtensible: Some(is_extensible),
|
|
has: None,
|
|
get: None,
|
|
set: None,
|
|
call: None,
|
|
construct: None,
|
|
hasOwn: None,
|
|
getOwnEnumerablePropertyKeys: None,
|
|
nativeCall: None,
|
|
objectClassIs: None,
|
|
className: Some(class_name),
|
|
fun_toString: None,
|
|
boxedValue_unbox: None,
|
|
defaultValue: None,
|
|
trace: None,
|
|
finalize: None,
|
|
objectMoved: None,
|
|
isCallable: None,
|
|
isConstructor: None,
|
|
};
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe {
|
|
SyncWrapper(CreateProxyHandler(&traps, ptr::null()))
|
|
}
|
|
};
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe extern "C" fn get_own_property_descriptor(
|
|
cx: *mut JSContext,
|
|
proxy: HandleObject,
|
|
id: HandleId,
|
|
desc: MutableHandle<PropertyDescriptor>,
|
|
is_none: *mut bool,
|
|
) -> bool {
|
|
let cx = SafeJSContext::from_ptr(cx);
|
|
if !RUST_JSID_IS_STRING(id) {
|
|
// Nothing to do if we're resolving a non-string property.
|
|
return true;
|
|
}
|
|
|
|
let mut found = false;
|
|
if !has_property_on_prototype(
|
|
*cx,
|
|
RustHandle::from_raw(proxy),
|
|
RustHandle::from_raw(id),
|
|
&mut found,
|
|
) {
|
|
return false;
|
|
}
|
|
if found {
|
|
return true;
|
|
}
|
|
|
|
let s = jsstr_to_string(*cx, RUST_JSID_TO_STRING(id));
|
|
if s.is_empty() {
|
|
return true;
|
|
}
|
|
|
|
let window = Root::downcast::<Window>(GlobalScope::from_object(proxy.get()))
|
|
.expect("global is not a window");
|
|
if let Some(obj) = window.NamedGetter(cx, s.into()) {
|
|
rooted!(in(*cx) let mut rval = UndefinedValue());
|
|
obj.to_jsval(*cx, rval.handle_mut());
|
|
set_property_descriptor(RustMutableHandle::from_raw(desc), rval.handle(), 0, &mut *is_none);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe extern "C" fn own_property_keys(
|
|
_cx: *mut JSContext,
|
|
_proxy: HandleObject,
|
|
_props: MutableHandleIdVector,
|
|
) -> bool {
|
|
// FIXME(pylbrecht): dummy implementation
|
|
true
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe extern "C" fn define_property(
|
|
cx: *mut JSContext,
|
|
_proxy: HandleObject,
|
|
_id: HandleId,
|
|
_desc: Handle<PropertyDescriptor>,
|
|
_result: *mut ObjectOpResult,
|
|
) -> bool {
|
|
throw_type_error(
|
|
cx,
|
|
"Not allowed to define a property on the named properties object.",
|
|
);
|
|
false
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe extern "C" fn delete(
|
|
_cx: *mut JSContext,
|
|
_proxy: HandleObject,
|
|
_id: HandleId,
|
|
result: *mut ObjectOpResult,
|
|
) -> bool {
|
|
(*result).code_ = JSErrNum::JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY as usize;
|
|
true
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe extern "C" fn get_prototype_if_ordinary(
|
|
_cx: *mut JSContext,
|
|
proxy: HandleObject,
|
|
is_ordinary: *mut bool,
|
|
proto: MutableHandleObject,
|
|
) -> bool {
|
|
*is_ordinary = true;
|
|
proto.set(js::jsapi::GetStaticPrototype(proxy.get()));
|
|
true
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe extern "C" fn prevent_extensions(
|
|
_cx: *mut JSContext,
|
|
_proxy: HandleObject,
|
|
result: *mut ObjectOpResult,
|
|
) -> bool {
|
|
(*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as usize;
|
|
true
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe extern "C" fn is_extensible(
|
|
_cx: *mut JSContext,
|
|
_proxy: HandleObject,
|
|
extensible: *mut bool,
|
|
) -> bool {
|
|
*extensible = true;
|
|
true
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
unsafe extern "C" fn class_name(_cx: *mut JSContext, _proxy: HandleObject) -> *const i8 {
|
|
&b"WindowProperties\0" as *const _ as *const i8
|
|
}
|
|
|
|
// Maybe this should be a DOMJSClass. See https://bugzilla.mozilla.org/show_bug.cgi?id=787070
|
|
#[allow(unsafe_code)]
|
|
static CLASS: JSClass = JSClass {
|
|
name: b"WindowProperties\0" as *const u8 as *const libc::c_char,
|
|
flags: JSClass_NON_NATIVE |
|
|
JSCLASS_IS_PROXY |
|
|
JSCLASS_DELAY_METADATA_BUILDER |
|
|
((1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), /* JSCLASS_HAS_RESERVED_SLOTS(1) */
|
|
cOps: unsafe { &ProxyClassOps },
|
|
spec: ptr::null(),
|
|
ext: unsafe { &ProxyClassExtension },
|
|
oOps: unsafe { &ProxyObjectOps },
|
|
};
|
|
|
|
#[allow(unsafe_code)]
|
|
pub fn create(
|
|
cx: SafeJSContext,
|
|
proto: RustHandleObject,
|
|
mut properties_obj: RustMutableHandleObject,
|
|
) {
|
|
unsafe {
|
|
properties_obj.set(NewProxyObject(
|
|
*cx,
|
|
HANDLER.0,
|
|
UndefinedHandleValue,
|
|
proto.get(),
|
|
// TODO: pass proper clasp
|
|
&CLASS,
|
|
false,
|
|
));
|
|
assert!(!properties_obj.get().is_null());
|
|
let mut succeeded = false;
|
|
assert!(JS_SetImmutablePrototype(
|
|
*cx,
|
|
properties_obj.handle().into_handle(),
|
|
&mut succeeded
|
|
));
|
|
assert!(succeeded);
|
|
}
|
|
}
|