mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Generate working ClientRectList and ClientRect bindings that can wrap, call methods, and access properties.
This commit is contained in:
parent
77388999ef
commit
998e3ffded
15 changed files with 830 additions and 148 deletions
|
@ -4,6 +4,8 @@ tasks.
|
|||
*/
|
||||
|
||||
use dom::bindings::utils::rust_box;
|
||||
use dom::bindings::utils::CacheableWrapper;
|
||||
use dom::bindings::utils::GlobalStaticData;
|
||||
use dom::document::Document;
|
||||
use dom::node::define_bindings;
|
||||
use dom::event::{Event, ResizeEvent, ReflowEvent};
|
||||
|
@ -21,7 +23,6 @@ use core::task::{SingleThreaded, spawn, task};
|
|||
use core::io::{println, read_whole_file};
|
||||
use core::ptr::null;
|
||||
use core::util::replace;
|
||||
use core::hashmap::linear;
|
||||
use geom::size::Size2D;
|
||||
use gfx::resource::image_cache_task::ImageCacheTask;
|
||||
use gfx::resource::resource_task::ResourceTask;
|
||||
|
@ -93,7 +94,7 @@ pub struct Content {
|
|||
|
||||
jsrt: jsrt,
|
||||
cx: @Cx,
|
||||
mut proxy_handlers: linear::LinearMap<uint, *libc::c_void>,
|
||||
dom_static: GlobalStaticData,
|
||||
|
||||
document: Option<@Document>,
|
||||
window: Option<@Window>,
|
||||
|
@ -138,7 +139,7 @@ pub fn Content(layout_task: LayoutTask,
|
|||
|
||||
jsrt : jsrt,
|
||||
cx : cx,
|
||||
proxy_handlers: linear::LinearMap::new(),
|
||||
dom_static: GlobalStaticData(),
|
||||
|
||||
document : None,
|
||||
window : None,
|
||||
|
@ -158,7 +159,7 @@ pub fn Content(layout_task: LayoutTask,
|
|||
|
||||
pub fn task_from_context(cx: *JSContext) -> *mut Content {
|
||||
unsafe {
|
||||
cast::reinterpret_cast(&JS_GetContextPrivate(cx))
|
||||
JS_GetContextPrivate(cx) as *Content
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,21 +213,19 @@ pub impl Content {
|
|||
let js_scripts = result.js_port.recv();
|
||||
debug!("js_scripts: %?", js_scripts);
|
||||
|
||||
let document = Document(root);
|
||||
let window = Window(self.control_chan.clone());
|
||||
let document = @Document(root);
|
||||
let window = @Window(self.control_chan.clone());
|
||||
|
||||
self.damage.add(MatchSelectorsDamage);
|
||||
self.relayout(&document, &url);
|
||||
self.relayout(document, &url);
|
||||
|
||||
self.document = Some(@document);
|
||||
self.window = Some(@window);
|
||||
self.document = Some(document);
|
||||
self.window = Some(window);
|
||||
self.doc_url = Some(url);
|
||||
|
||||
let compartment = option::expect(self.compartment, ~"TODO error checking");
|
||||
compartment.define_functions(debug_fns);
|
||||
define_bindings(compartment,
|
||||
option::get(self.document),
|
||||
option::get(self.window));
|
||||
define_bindings(compartment, document, window);
|
||||
|
||||
do vec::consume(js_scripts) |_i, bytes| {
|
||||
self.cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use dom::bindings::utils::{CacheableWrapper, WrapperCache};
|
||||
use content::content_task::task_from_context;
|
||||
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, OpaqueBindingReference};
|
||||
use dom::bindings::ClientRectBinding;
|
||||
use js::jsapi::{JSObject, JSContext};
|
||||
|
||||
|
@ -12,7 +13,7 @@ pub trait ClientRect {
|
|||
}
|
||||
|
||||
pub struct ClientRectImpl {
|
||||
mut wrapper: ~WrapperCache,
|
||||
wrapper: WrapperCache,
|
||||
top: f32,
|
||||
bottom: f32,
|
||||
left: f32,
|
||||
|
@ -45,17 +46,31 @@ pub impl ClientRect for ClientRectImpl {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ClientRect(top: f32, bottom: f32, left: f32, right: f32) -> ClientRectImpl {
|
||||
ClientRectImpl {
|
||||
top: top, bottom: bottom, left: left, right: right,
|
||||
wrapper: WrapperCache::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub impl CacheableWrapper for ClientRectImpl {
|
||||
fn get_wrapper(@self) -> *JSObject {
|
||||
unsafe { cast::transmute(self.wrapper.wrapper) }
|
||||
fn get_wrappercache(&self) -> &WrapperCache {
|
||||
unsafe { cast::transmute(&self.wrapper) }
|
||||
}
|
||||
|
||||
fn set_wrapper(@self, wrapper: *JSObject) {
|
||||
unsafe { self.wrapper.wrapper = cast::transmute(wrapper); }
|
||||
}
|
||||
|
||||
fn wrap_object(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
let mut unused = false;
|
||||
ClientRectBinding::Wrap(cx, scope, self, &mut unused)
|
||||
}
|
||||
|
||||
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fail!(~"nyi")
|
||||
}
|
||||
}
|
||||
|
||||
impl BindingObject for ClientRectImpl {
|
||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
|
||||
let content = task_from_context(cx);
|
||||
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
|
||||
}
|
||||
}
|
|
@ -1,46 +1,69 @@
|
|||
use content::content_task::task_from_context;
|
||||
use dom::bindings::clientrect::ClientRectImpl;
|
||||
use dom::bindings::clientrect::{ClientRect, ClientRectImpl};
|
||||
use dom::bindings::ClientRectListBinding;
|
||||
use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject};
|
||||
use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject, OpaqueBindingReference};
|
||||
use dom::window::Window;
|
||||
use dom::bindings::window::Window;
|
||||
use js::jsapi::{JSObject, JSContext};
|
||||
|
||||
pub trait ClientRectList {
|
||||
fn Length(&self) -> u32;
|
||||
fn Item(&self, index: u32) -> Option<@ClientRectImpl>;
|
||||
fn Item(&self, index: u32) -> Option<~ClientRectImpl>;
|
||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<~ClientRectImpl>;
|
||||
}
|
||||
|
||||
pub struct ClientRectListImpl {
|
||||
mut wrapper: ~WrapperCache
|
||||
wrapper: WrapperCache,
|
||||
rects: ~[(f32, f32, f32, f32)]
|
||||
}
|
||||
|
||||
impl ClientRectList for ClientRectListImpl {
|
||||
fn Length(&self) -> u32 {
|
||||
0
|
||||
self.rects.len() as u32
|
||||
}
|
||||
|
||||
fn Item(&self, index: u32) -> Option<@ClientRectImpl> {
|
||||
None
|
||||
fn Item(&self, index: u32) -> Option<~ClientRectImpl> {
|
||||
if index < self.rects.len() as u32 {
|
||||
let (top, bottom, left, right) = self.rects[index];
|
||||
Some(~ClientRect(top, bottom, left, right))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<~ClientRectImpl> {
|
||||
*found = index < self.rects.len() as u32;
|
||||
self.Item(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientRectListImpl {
|
||||
static fn new() -> ClientRectListImpl {
|
||||
ClientRectListImpl {
|
||||
wrapper: WrapperCache::new(),
|
||||
rects: ~[(5.6, 80.2, 3.7, 4.8), (800.1, 8001.1, -50.000001, -45.01)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub impl CacheableWrapper for ClientRectListImpl {
|
||||
fn get_wrapper(@self) -> *JSObject {
|
||||
unsafe { cast::transmute(self.wrapper.wrapper) }
|
||||
fn get_wrappercache(&self) -> &WrapperCache {
|
||||
unsafe { cast::transmute(&self.wrapper) }
|
||||
}
|
||||
|
||||
fn set_wrapper(@self, wrapper: *JSObject) {
|
||||
unsafe { self.wrapper.wrapper = cast::transmute(wrapper); }
|
||||
}
|
||||
|
||||
fn wrap_object(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
let mut unused = false;
|
||||
ClientRectListBinding::Wrap(cx, scope, self, &mut unused)
|
||||
}
|
||||
|
||||
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fail!(~"nyi")
|
||||
}
|
||||
}
|
||||
|
||||
pub impl BindingObject for ClientRectListImpl {
|
||||
fn GetParentObject(@self, cx: *JSContext) -> @CacheableWrapper {
|
||||
impl BindingObject for ClientRectListImpl {
|
||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
|
||||
let content = task_from_context(cx);
|
||||
unsafe { (*content).window.get() as @CacheableWrapper }
|
||||
unsafe { OpaqueBindingReference(Right((*content).window.get() as @CacheableWrapper)) }
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ class CastableObjectUnwrapper():
|
|||
def __init__(self, descriptor, source, target, codeOnFailure):
|
||||
assert descriptor.castable
|
||||
|
||||
self.substitution = { "type" : descriptor.pointerType + descriptor.nativeType,
|
||||
self.substitution = { "type" : descriptor.nativeType,
|
||||
"protoID" : "prototypes::id::" + descriptor.name + " as uint",
|
||||
"source" : source,
|
||||
"target" : target,
|
||||
|
@ -105,7 +105,7 @@ class CastableObjectUnwrapper():
|
|||
|
||||
def __str__(self):
|
||||
return string.Template(
|
||||
"""${target} = unwrap::<${type}>(${source});
|
||||
"""${target} = unwrap(${source});
|
||||
""").substitute(self.substitution)
|
||||
#"""{
|
||||
# nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
|
||||
|
@ -1346,7 +1346,7 @@ class CGArgumentConverter(CGThing):
|
|||
"holderName" : ("arg%d" % index) + "_holder"
|
||||
}
|
||||
self.replacementVariables["val"] = string.Template(
|
||||
"${argv}[${index}]"
|
||||
"(*${argv}.offset(${index}))"
|
||||
).substitute(replacer)
|
||||
self.replacementVariables["valPtr"] = (
|
||||
"&" + self.replacementVariables["val"])
|
||||
|
@ -1653,7 +1653,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
|
|||
result = CGGeneric(descriptorProvider.getDescriptor(
|
||||
returnType.unroll().inner.identifier.name).nativeType)
|
||||
if resultAlreadyAddRefed:
|
||||
result = CGWrapper(result, pre="Option<@", post=">")
|
||||
result = CGWrapper(result, pre="Option<~", post=">")
|
||||
else:
|
||||
result = CGWrapper(result, post="*")
|
||||
return result, False
|
||||
|
@ -1814,8 +1814,8 @@ class PropertyDefiner:
|
|||
#"static Prefable<%s> %s[] = [\n" +
|
||||
#',\n'.join(prefableSpecs) + "\n" +
|
||||
#"];\n\n")
|
||||
#if doIdArrays:
|
||||
# arrays += ("const %s_ids: [jsid * %i] = [" % (name, len(specs))) + ", ".join(["JSID_VOID"] * len(specs)) + "];\n\n"
|
||||
if doIdArrays:
|
||||
arrays += ("const %s_ids: [jsid * %i] = [" % (name, len(specs))) + ", ".join(["JSID_VOID"] * len(specs)) + "];\n\n"
|
||||
return arrays
|
||||
|
||||
# The length of a method is the maximum of the lengths of the
|
||||
|
@ -2011,7 +2011,7 @@ class CGNativePropertyHooks(CGThing):
|
|||
parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
|
||||
if parent else '0 as *NativePropertyHooks')
|
||||
return """
|
||||
const NativeHooks: NativePropertyHooks = NativePropertyHooks { resolve_own_property: /*%s*/ 0 as *u8, resolve_property: /*ResolveProperty*/ 0 as *u8, enumerate_own_properties: /*%s*/ 0 as *u8, enumerate_properties: /*EnumerateProperties*/ 0 as *u8, proto_hooks: %s };
|
||||
const NativeHooks: NativePropertyHooks = NativePropertyHooks { resolve_own_property: /*%s*/ 0 as *u8, resolve_property: ResolveProperty, enumerate_own_properties: /*%s*/ 0 as *u8, enumerate_properties: /*EnumerateProperties*/ 0 as *u8, proto_hooks: %s };
|
||||
""" % (resolveOwnProperty, enumerateOwnProperties, parentHooks)
|
||||
|
||||
# We'll want to insert the indent at the beginnings of lines, but we
|
||||
|
@ -2097,6 +2097,13 @@ class CGImports(CGWrapper):
|
|||
CGWrapper.__init__(self, child,
|
||||
definePre=_useString(sorted(defineImports)))
|
||||
|
||||
class CGIfWrapper(CGWrapper):
|
||||
def __init__(self, child, condition):
|
||||
pre = CGWrapper(CGGeneric(condition), pre="if ", post=" {\n",
|
||||
reindent=True)
|
||||
CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
|
||||
post="\n}")
|
||||
|
||||
class CGNamespace(CGWrapper):
|
||||
def __init__(self, namespace, child, declareOnly=False):
|
||||
pre = "mod %s {\n" % namespace
|
||||
|
@ -2377,9 +2384,13 @@ class CGAbstractMethod(CGThing):
|
|||
|
||||
def CreateBindingJSObject(descriptor, parent):
|
||||
if descriptor.proxy:
|
||||
handler = " let content = task_from_context(aCx);\n let handler = (*content).proxy_handlers.get(&(prototypes::id::%s as uint));\n" % descriptor.name
|
||||
handler = """ let cache = ptr::to_unsafe_ptr(aObject.get_wrappercache());
|
||||
|
||||
let content = task_from_context(aCx);
|
||||
let handler = (*content).dom_static.proxy_handlers.get(&(prototypes::id::%s as uint));
|
||||
""" % descriptor.name
|
||||
create = handler + """ let obj = NewProxyObject(aCx, *handler,
|
||||
ptr::addr_of(&RUST_PRIVATE_TO_JSVAL(squirrel_away(aObject) as *libc::c_void)),
|
||||
ptr::addr_of(&RUST_PRIVATE_TO_JSVAL(squirrel_away_ref(aObject) as *libc::c_void)),
|
||||
proto, %s,
|
||||
ptr::null(), ptr::null());
|
||||
if obj.is_null() {
|
||||
|
@ -2388,12 +2399,13 @@ def CreateBindingJSObject(descriptor, parent):
|
|||
|
||||
"""
|
||||
else:
|
||||
create = """ let obj = JS_NewObject(aCx, &Class.mBase, proto, %s);
|
||||
create = """ let obj = JS_NewObject(aCx, &Class.base, proto, %s);
|
||||
if obj.is_null() {
|
||||
return ptr::null();
|
||||
}
|
||||
|
||||
JS_SetReservedSlot(obj, DOM_OBJECT_SLOT, RUST_PRIVATE_TO_JSVAL(squirrel_away(aObject)));
|
||||
JS_SetReservedSlot(obj, DOM_OBJECT_SLOT as u32,
|
||||
RUST_PRIVATE_TO_JSVAL(squirrel_away_ref(aObject) as *libc::c_void));
|
||||
"""
|
||||
return create % parent
|
||||
|
||||
|
@ -2401,8 +2413,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
|
|||
def __init__(self, descriptor):
|
||||
assert descriptor.interface.hasInterfacePrototypeObject()
|
||||
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
|
||||
Argument('@' + descriptor.nativeType, 'aObject'),
|
||||
Argument('@CacheableWrapper', 'aCache'),
|
||||
Argument('BindingReference<' + descriptor.nativeType + '>', 'aObject'),
|
||||
Argument('*mut bool', 'aTriedToWrap')]
|
||||
CGAbstractMethod.__init__(self, descriptor, 'Wrap_', '*JSObject', args)
|
||||
|
||||
|
@ -2411,7 +2422,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
|
|||
return """ *aTriedToWrap = true;
|
||||
return aObject->GetJSObject();"""
|
||||
|
||||
return """/* *aTriedToWrap = true;
|
||||
return """ *aTriedToWrap = true;
|
||||
|
||||
let parent = WrapNativeParent(aCx, aScope, aObject.GetParentObject(aCx));
|
||||
if parent.is_null() {
|
||||
|
@ -2426,12 +2437,14 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
|
|||
return ptr::null();
|
||||
}
|
||||
|
||||
let cache = ptr::to_unsafe_ptr(aObject.get_wrappercache());
|
||||
|
||||
%s
|
||||
//NS_ADDREF(aObject);
|
||||
|
||||
aCache.set_wrapper(obj);
|
||||
(*cache).set_wrapper(obj);
|
||||
|
||||
return obj;*/return ptr::null();""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"),
|
||||
return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"),
|
||||
CreateBindingJSObject(self.descriptor, "parent"))
|
||||
|
||||
class CGWrapMethod(CGAbstractMethod):
|
||||
|
@ -2439,12 +2452,11 @@ class CGWrapMethod(CGAbstractMethod):
|
|||
# XXX can we wrap if we don't have an interface prototype object?
|
||||
assert descriptor.interface.hasInterfacePrototypeObject()
|
||||
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aScope'),
|
||||
Argument('@' + descriptor.nativeType, 'aObject'), Argument('*mut bool', 'aTriedToWrap')]
|
||||
#CGAbstractMethod.__init__(self, descriptor, 'Wrap', '*JSObject', args, inline=True, templateArgs=["T: &static + BindingObject + CacheableWrapper + " + descriptor.name], pub=True)
|
||||
Argument('~' + descriptor.nativeType, 'aObject'), Argument('*mut bool', 'aTriedToWrap')]
|
||||
CGAbstractMethod.__init__(self, descriptor, 'Wrap', '*JSObject', args, inline=True, pub=True)
|
||||
|
||||
def definition_body(self):
|
||||
return " return Wrap_(aCx, aScope, aObject, aObject as @CacheableWrapper, aTriedToWrap);"
|
||||
return " return Wrap_(aCx, aScope, BindingReference(Left(aObject)), aTriedToWrap);"
|
||||
|
||||
class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
|
||||
def __init__(self, descriptor):
|
||||
|
@ -2538,7 +2550,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
idsToInit = []
|
||||
# There is no need to init any IDs in workers, because worker bindings
|
||||
# don't have Xrays.
|
||||
if False and not self.descriptor.workers: #XXXjdm punt on the interned string optimization
|
||||
if not self.descriptor.workers:
|
||||
for var in self.properties.xrayRelevantArrayNames():
|
||||
props = getattr(self.properties, var)
|
||||
# We only have non-chrome ids to init if we have no chrome ids.
|
||||
|
@ -2548,17 +2560,19 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
idsToInit.append(props.variableName(False))
|
||||
if len(idsToInit) > 0:
|
||||
initIds = CGList(
|
||||
[CGGeneric("!InitIds(aCx, %s, %s_ids)" % (varname, varname)) for
|
||||
[CGGeneric("!InitIds(aCx, %s, *%s_ids_mut)" % (varname, varname)) for
|
||||
varname in idsToInit], ' ||\n')
|
||||
if len(idsToInit) > 1:
|
||||
initIds = CGWrapper(initIds, pre="(", post=")", reindent=True)
|
||||
initIds = CGList(
|
||||
[CGGeneric("%s_ids[0] == JSID_VOID &&" % idsToInit[0]), initIds],
|
||||
[CGGeneric("%s_ids_mut[0] == JSID_VOID &&" % idsToInit[0]), initIds],
|
||||
"\n")
|
||||
initIds = CGWrapper(initIds, pre="if ", post=" {", reindent=True)
|
||||
initIds = CGList(
|
||||
[initIds,
|
||||
CGGeneric((" %s_ids[0] = JSID_VOID;\n"
|
||||
[CGGeneric("let content = task_from_context(aCx);\n" +
|
||||
"let sAttributes_ids_mut = (*content).dom_static.attribute_ids.get(&(prototypes::id::%s as uint));" % self.descriptor.name),
|
||||
initIds,
|
||||
CGGeneric((" %s_ids_mut[0] = JSID_VOID;\n"
|
||||
" return ptr::null();") % idsToInit[0]),
|
||||
CGGeneric("}")],
|
||||
"\n")
|
||||
|
@ -2762,11 +2776,11 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
|||
else:
|
||||
getter = "GetConstructorObject"
|
||||
|
||||
body = ""
|
||||
body = " let content = task_from_context(aCx);\n"
|
||||
if self.descriptor.proxy:
|
||||
body = """ let traps = ProxyTraps {
|
||||
getPropertyDescriptor: ptr::null(),
|
||||
getOwnPropertyDescriptor: ptr::null(),
|
||||
body += """ let traps = ProxyTraps {
|
||||
getPropertyDescriptor: getPropertyDescriptor,
|
||||
getOwnPropertyDescriptor: getOwnPropertyDescriptor,
|
||||
defineProperty: ptr::null(),
|
||||
getOwnPropertyNames: ptr::null(),
|
||||
delete_: ptr::null(),
|
||||
|
@ -2774,7 +2788,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
|||
|
||||
has: ptr::null(),
|
||||
hasOwn: ptr::null(),
|
||||
get: ptr::null(),
|
||||
get: get,
|
||||
set: ptr::null(),
|
||||
keys: ptr::null(),
|
||||
iterate: ptr::null(),
|
||||
|
@ -2785,7 +2799,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
|||
hasInstance: ptr::null(),
|
||||
typeOf: ptr::null(),
|
||||
objectClassIs: ptr::null(),
|
||||
obj_toString: ptr::null(),
|
||||
obj_toString: obj_toString,
|
||||
fun_toString: ptr::null(),
|
||||
//regexp_toShared: ptr::null(),
|
||||
defaultValue: ptr::null(),
|
||||
|
@ -2794,10 +2808,13 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
|||
getElementIfPresent: ptr::null(),
|
||||
getPrototypeOf: ptr::null()
|
||||
};
|
||||
let content = task_from_context(aCx);
|
||||
(*content).proxy_handlers.insert(prototypes::id::%s as uint,
|
||||
CreateProxyHandler(ptr::addr_of(&traps)));
|
||||
(*content).dom_static.proxy_handlers.insert(prototypes::id::%s as uint,
|
||||
CreateProxyHandler(ptr::addr_of(&traps)));
|
||||
|
||||
""" % self.descriptor.name
|
||||
else:
|
||||
body += """ (*content).dom_static.attribute_ids.insert(prototypes::id::%s as uint,
|
||||
vec::cast_to_mut(vec::from_slice(sAttributes_ids)));
|
||||
""" % self.descriptor.name
|
||||
|
||||
return (body + " let global: *JSObject = JS_GetGlobalForObject(aCx, aReceiver);\n" +
|
||||
|
@ -2938,7 +2955,7 @@ class CGPerSignatureCall(CGThing):
|
|||
def getArgv(self):
|
||||
return "argv" if self.argCount > 0 else ""
|
||||
def getArgvDecl(self):
|
||||
return "\nlet argv = JS_ARGV(cx, vp);\n"
|
||||
return "\nlet argv = JS_ARGV(cx, cast::transmute(vp));\n"
|
||||
def getArgc(self):
|
||||
return "argc"
|
||||
def getArguments(self):
|
||||
|
@ -2989,6 +3006,21 @@ class CGGetterCall(CGPerSignatureCall):
|
|||
nativeMethodName, False, descriptor,
|
||||
attr, getter=True)
|
||||
|
||||
class FakeArgument():
|
||||
"""
|
||||
A class that quacks like an IDLArgument. This is used to make
|
||||
setters look like method calls or for special operations.
|
||||
"""
|
||||
def __init__(self, type, interfaceMember):
|
||||
self.type = type
|
||||
self.optional = False
|
||||
self.variadic = False
|
||||
self.defaultValue = None
|
||||
self.treatNullAs = interfaceMember.treatNullAs
|
||||
self.treatUndefinedAs = interfaceMember.treatUndefinedAs
|
||||
self.enforceRange = False
|
||||
self.clamp = False
|
||||
|
||||
class CGAbstractBindingMethod(CGAbstractExternMethod):
|
||||
"""
|
||||
Common class to generate the JSNatives for all our methods, getters, and
|
||||
|
@ -3025,7 +3057,7 @@ class CGAbstractBindingMethod(CGAbstractExternMethod):
|
|||
" return false as JSBool;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"let self: %s;" % (self.descriptor.pointerType + self.descriptor.nativeType)))
|
||||
"let self: *rust_box<%s>;" % self.descriptor.nativeType))
|
||||
|
||||
def generate_code(self):
|
||||
assert(False) # Override me
|
||||
|
@ -3042,8 +3074,7 @@ class CGGenericMethod(CGAbstractBindingMethod):
|
|||
def generate_code(self):
|
||||
return CGIndenter(CGGeneric(
|
||||
"let _info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
|
||||
"let tmp: *rust_box<%s> = cast::reinterpret_cast(&self);\n"
|
||||
"return CallJitMethodOp(_info, cx, obj, ptr::addr_of(&(*tmp).payload) as *libc::c_void, argc, vp);" % self.descriptor.nativeType))
|
||||
"return CallJitMethodOp(_info, cx, obj, ptr::to_unsafe_ptr(&(*self).payload) as *libc::c_void, argc, vp);"))
|
||||
|
||||
class CGAbstractStaticMethod(CGAbstractMethod):
|
||||
"""
|
||||
|
@ -3065,16 +3096,17 @@ class CGSpecializedMethod(CGAbstractExternMethod):
|
|||
def __init__(self, descriptor, method):
|
||||
self.method = method
|
||||
name = method.identifier.name
|
||||
args = [Argument('*JSContext', 'cx'), Argument('*JSHandleObject', 'obj'),
|
||||
args = [Argument('*JSContext', 'cx'), Argument('JSHandleObject', '++obj'),
|
||||
Argument('*%s' % descriptor.nativeType, 'self'),
|
||||
Argument('libc::c_uint', 'argc'), Argument('*JSVal', 'vp')]
|
||||
Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')]
|
||||
CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args)
|
||||
|
||||
def definition_body(self):
|
||||
name = self.method.identifier.name
|
||||
nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
|
||||
return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
|
||||
self.descriptor, self.method), pre="/*", post="*/return 1;").define()
|
||||
self.descriptor, self.method),
|
||||
pre=" let obj = (*obj.unnamed);\n").define()
|
||||
|
||||
class CGGenericGetter(CGAbstractBindingMethod):
|
||||
"""
|
||||
|
@ -3098,8 +3130,7 @@ class CGGenericGetter(CGAbstractBindingMethod):
|
|||
def generate_code(self):
|
||||
return CGIndenter(CGGeneric(
|
||||
"let _info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
|
||||
"let tmp: *rust_box<%s> = cast::reinterpret_cast(&self);\n"
|
||||
"return CallJitPropertyOp(_info, cx, obj, ptr::addr_of(&(*tmp).payload) as *libc::c_void, vp);" % self.descriptor.nativeType))
|
||||
"return CallJitPropertyOp(_info, cx, obj, ptr::to_unsafe_ptr(&(*self).payload) as *libc::c_void, vp);"))
|
||||
|
||||
class CGSpecializedGetter(CGAbstractExternMethod):
|
||||
"""
|
||||
|
@ -3110,7 +3141,7 @@ class CGSpecializedGetter(CGAbstractExternMethod):
|
|||
self.attr = attr
|
||||
name = 'get_' + attr.identifier.name
|
||||
args = [ Argument('*JSContext', 'cx'),
|
||||
Argument('*JSObject', 'obj'),
|
||||
Argument('JSHandleObject', '++obj'),
|
||||
Argument('*%s' % descriptor.nativeType, 'self'),
|
||||
Argument('*mut JSVal', 'vp') ]
|
||||
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
|
||||
|
@ -3204,6 +3235,252 @@ class CGMemberJITInfo(CGThing):
|
|||
return result
|
||||
raise TypeError("Illegal member type to CGPropertyJITInfo")
|
||||
|
||||
class CGXrayHelper(CGAbstractExternMethod):
|
||||
def __init__(self, descriptor, name, args, properties):
|
||||
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
|
||||
self.properties = properties
|
||||
|
||||
def definition_body(self):
|
||||
varNames = self.properties.variableNames(True)
|
||||
|
||||
setup = "let content = task_from_context(cx);\n"
|
||||
|
||||
methods = self.properties.methods
|
||||
if methods.hasNonChromeOnly() or methods.hasChromeOnly():
|
||||
methodArgs = """// %(methods)s has an end-of-list marker at the end that we ignore
|
||||
%(methods)s, %(methods)s_ids, %(methods)s_specs, ArrayLength(%(methods)s) - 1""" % varNames
|
||||
else:
|
||||
methodArgs = "None"
|
||||
methodArgs = CGGeneric(methodArgs)
|
||||
|
||||
attrs = self.properties.attrs
|
||||
if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
|
||||
attrArgs = "Some(vec::zip_slice(%(attrs)s, *attr_ids))" % varNames
|
||||
setup += "let attr_ids = (*content).dom_static.attribute_ids.get(&(prototypes::id::ClientRect as uint));\n"
|
||||
else:
|
||||
attrArgs = "None"
|
||||
attrArgs = CGGeneric(attrArgs)
|
||||
|
||||
consts = self.properties.consts
|
||||
if consts.hasNonChromeOnly() or consts.hasChromeOnly():
|
||||
constArgs = """// %(consts)s has an end-of-list marker at the end that we ignore
|
||||
%(consts)s, %(consts)s_ids, %(consts)s_specs, ArrayLength(%(consts)s) - 1""" % varNames
|
||||
else:
|
||||
constArgs = "None"
|
||||
constArgs = CGGeneric(constArgs)
|
||||
|
||||
prefixArgs = CGGeneric(self.getPrefixArgs())
|
||||
|
||||
return CGIndenter(
|
||||
CGWrapper(CGList([prefixArgs, methodArgs, attrArgs, constArgs], ", "),
|
||||
pre=(setup + "return Xray%s(" % self.name),
|
||||
post=");",
|
||||
reindent=True)).define()
|
||||
|
||||
class CGResolveProperty(CGXrayHelper):
|
||||
def __init__(self, descriptor, properties):
|
||||
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'wrapper'),
|
||||
Argument('jsid', 'id'), Argument('bool', 'set'),
|
||||
Argument('*mut JSPropertyDescriptor', 'desc')]
|
||||
CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args,
|
||||
properties)
|
||||
|
||||
def getPrefixArgs(self):
|
||||
return "cx, wrapper, id, desc"
|
||||
|
||||
|
||||
class CGEnumerateProperties(CGXrayHelper):
|
||||
def __init__(self, descriptor, properties):
|
||||
args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
|
||||
Argument('JS::AutoIdVector&', 'props')]
|
||||
CGXrayHelper.__init__(self, descriptor, "EnumerateProperties", args,
|
||||
properties)
|
||||
|
||||
def getPrefixArgs(self):
|
||||
return "props"
|
||||
|
||||
class CGProxySpecialOperation(CGPerSignatureCall):
|
||||
"""
|
||||
Base class for classes for calling an indexed or named special operation
|
||||
(don't use this directly, use the derived classes below).
|
||||
"""
|
||||
def __init__(self, descriptor, operation):
|
||||
nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
|
||||
operation = descriptor.operations[operation]
|
||||
assert len(operation.signatures()) == 1
|
||||
signature = operation.signatures()[0]
|
||||
extendedAttributes = descriptor.getExtendedAttributes(operation)
|
||||
|
||||
(returnType, arguments) = signature
|
||||
|
||||
# We pass len(arguments) as the final argument so that the
|
||||
# CGPerSignatureCall won't do any argument conversion of its own.
|
||||
CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
|
||||
False, descriptor, operation,
|
||||
len(arguments))
|
||||
|
||||
if operation.isSetter() or operation.isCreator():
|
||||
# arguments[0] is the index or name of the item that we're setting.
|
||||
argument = arguments[1]
|
||||
template = getJSToNativeConversionTemplate(argument.type, descriptor,
|
||||
treatNullAs=argument.treatNullAs,
|
||||
treatUndefinedAs=argument.treatUndefinedAs)
|
||||
templateValues = {
|
||||
"declName": argument.identifier.name,
|
||||
"holderName": argument.identifier.name + "_holder",
|
||||
"val": "desc->value",
|
||||
"valPtr": "&desc->value"
|
||||
}
|
||||
self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(template, templateValues))
|
||||
elif operation.isGetter():
|
||||
self.cgRoot.prepend(CGGeneric("let mut found = false;"))
|
||||
|
||||
def getArguments(self):
|
||||
args = [(a, a.identifier.name) for a in self.arguments]
|
||||
if self.idlNode.isGetter():
|
||||
args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
|
||||
self.idlNode),
|
||||
"&mut found"))
|
||||
return args
|
||||
|
||||
def wrap_return_value(self):
|
||||
if not self.idlNode.isGetter() or self.templateValues is None:
|
||||
return ""
|
||||
|
||||
wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
|
||||
wrap = CGIfWrapper(wrap, "found")
|
||||
return "\n" + wrap.define()
|
||||
|
||||
class CGProxyIndexedGetter(CGProxySpecialOperation):
|
||||
"""
|
||||
Class to generate a call to an indexed getter. If templateValues is not None
|
||||
the returned value will be wrapped with wrapForType using templateValues.
|
||||
"""
|
||||
def __init__(self, descriptor, templateValues=None):
|
||||
self.templateValues = templateValues
|
||||
CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
|
||||
|
||||
class CGProxyUnwrap(CGAbstractMethod):
|
||||
def __init__(self, descriptor):
|
||||
args = [Argument('*JSObject', 'obj')]
|
||||
CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*' + descriptor.nativeType, args, alwaysInline=True)
|
||||
def declare(self):
|
||||
return ""
|
||||
def definition_body(self):
|
||||
return """ /*if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
|
||||
obj = js::UnwrapObject(obj);
|
||||
}*/
|
||||
//MOZ_ASSERT(IsProxy(obj));
|
||||
let box: *rust_box<%s> = cast::transmute(RUST_JSVAL_TO_PRIVATE(GetProxyPrivate(obj)));
|
||||
return ptr::to_unsafe_ptr(&(*box).payload);""" % (self.descriptor.nativeType)
|
||||
|
||||
class CGDOMJSProxyHandler_get(CGAbstractExternMethod):
|
||||
def __init__(self, descriptor):
|
||||
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy'),
|
||||
Argument('*JSObject', 'receiver'), Argument('jsid', 'id'),
|
||||
Argument('*mut JSVal', 'vp')]
|
||||
CGAbstractExternMethod.__init__(self, descriptor, "get", "JSBool", args)
|
||||
self.descriptor = descriptor
|
||||
def getBody(self):
|
||||
getFromExpando = """let expando = GetExpandoObject(proxy);
|
||||
if expando.is_not_null() {
|
||||
let hasProp = 0;
|
||||
if JS_HasPropertyById(cx, expando, id, ptr::to_unsafe_ptr(&hasProp)) == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if hasProp != 0 {
|
||||
return JS_GetPropertyById(cx, expando, id, cast::transmute(vp));
|
||||
}
|
||||
}"""
|
||||
|
||||
templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'}
|
||||
|
||||
indexedGetter = self.descriptor.operations['IndexedGetter']
|
||||
if indexedGetter:
|
||||
getIndexedOrExpando = ("let index = GetArrayIndexFromId(cx, id);\n" +
|
||||
"if index.is_some() {\n" +
|
||||
" let index = index.get();\n" +
|
||||
" let self = UnwrapProxy(proxy);\n" +
|
||||
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define())
|
||||
getIndexedOrExpando += """
|
||||
// Even if we don't have this index, we don't forward the
|
||||
// get on to our expando object.
|
||||
} else {
|
||||
%s
|
||||
}
|
||||
""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n ')))
|
||||
else:
|
||||
getIndexedOrExpando = getFromExpando + "\n"
|
||||
|
||||
namedGetter = self.descriptor.operations['NamedGetter']
|
||||
if namedGetter:
|
||||
getNamed = ("if (JSID_IS_STRING(id)) {\n" +
|
||||
" JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
|
||||
" FakeDependentString name;\n"
|
||||
" if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
|
||||
" eStringify, eStringify, name)) {\n" +
|
||||
" return false;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" let self = UnwrapProxy(proxy);\n" +
|
||||
CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
|
||||
"}\n") % (self.descriptor.nativeType)
|
||||
else:
|
||||
getNamed = ""
|
||||
|
||||
return """//MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
|
||||
//"Should not have a XrayWrapper here");
|
||||
|
||||
%s
|
||||
let mut found = false;
|
||||
if !GetPropertyOnPrototype(cx, proxy, id, &mut found, cast::transmute(vp)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
return 1;
|
||||
}
|
||||
%s
|
||||
*vp = JSVAL_VOID;
|
||||
return 1;""" % (getIndexedOrExpando, getNamed)
|
||||
|
||||
def definition_body(self):
|
||||
return self.getBody()
|
||||
|
||||
class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
|
||||
def __init__(self, descriptor):
|
||||
args = [Argument('*JSContext', 'cx'), Argument('*JSObject', 'proxy')]
|
||||
CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*JSString", args)
|
||||
self.descriptor = descriptor
|
||||
def getBody(self):
|
||||
stringifier = self.descriptor.operations['Stringifier']
|
||||
if stringifier:
|
||||
name = stringifier.identifier.name
|
||||
nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
|
||||
signature = stringifier.signatures()[0]
|
||||
returnType = signature[0]
|
||||
extendedAttributes = self.descriptor.getExtendedAttributes(stringifier)
|
||||
infallible = 'infallible' in extendedAttributes
|
||||
if not infallible:
|
||||
error = CGGeneric(
|
||||
('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString");\n' +
|
||||
"return NULL;") % self.descriptor.interface.identifier.name)
|
||||
else:
|
||||
error = None
|
||||
call = CGCallGenerator(error, [], "", returnType, extendedAttributes, self.descriptor, nativeName, False, object="UnwrapProxy(proxy)")
|
||||
return call.define() + """
|
||||
|
||||
JSString* jsresult;
|
||||
return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;"""
|
||||
|
||||
return """ do str::as_c_str("%s") |s| {
|
||||
_obj_toString(cx, s)
|
||||
}""" % self.descriptor.name
|
||||
|
||||
def definition_body(self):
|
||||
return self.getBody()
|
||||
|
||||
class CGAbstractClassHook(CGAbstractExternMethod):
|
||||
"""
|
||||
Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
|
||||
|
@ -3442,7 +3719,7 @@ class CGDescriptor(CGThing):
|
|||
#cgThings.append(CGResolveOwnProperty(descriptor))
|
||||
#cgThings.append(CGEnumerateOwnProperties(descriptor))
|
||||
pass
|
||||
#cgThings.append(CGResolveProperty(descriptor, properties))
|
||||
cgThings.append(CGResolveProperty(descriptor, properties))
|
||||
#cgThings.append(CGEnumerateProperties(descriptor, properties))
|
||||
|
||||
if descriptor.interface.hasInterfaceObject():
|
||||
|
@ -3461,8 +3738,10 @@ class CGDescriptor(CGThing):
|
|||
if descriptor.concrete:
|
||||
if descriptor.proxy:
|
||||
#cgThings.append(CGProxyIsProxy(descriptor))
|
||||
#cgThings.append(CGProxyUnwrap(descriptor))
|
||||
cgThings.append(CGProxyUnwrap(descriptor))
|
||||
cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
|
||||
cgThings.append(CGDOMJSProxyHandler_obj_toString(descriptor))
|
||||
cgThings.append(CGDOMJSProxyHandler_get(descriptor))
|
||||
#cgThings.append(CGDOMJSProxyHandler(descriptor))
|
||||
#cgThings.append(CGIsMethod(descriptor))
|
||||
pass
|
||||
|
@ -3525,7 +3804,8 @@ class CGBindingRoot(CGThing):
|
|||
'dom::bindings::utils::*',
|
||||
'dom::bindings::conversions::*',
|
||||
'dom::bindings::clientrect::*', #XXXjdm
|
||||
'dom::bindings::clientrectlist::*' #XXXjdm
|
||||
'dom::bindings::clientrectlist::*', #XXXjdm
|
||||
'dom::bindings::proxyhandler::*',
|
||||
],
|
||||
curr)
|
||||
|
||||
|
|
|
@ -72,8 +72,8 @@ extern fn getDocumentElement(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> J
|
|||
|
||||
let doc = &(*unwrap(obj)).payload;
|
||||
*vp = RUST_OBJECT_TO_JSVAL(node::create(cx, doc.root).ptr);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Document> {
|
||||
|
|
|
@ -2,7 +2,9 @@ use content::content_task::{Content, task_from_context};
|
|||
use dom::bindings::node::unwrap;
|
||||
use dom::bindings::utils::{rust_box, squirrel_away_unique, get_compartment};
|
||||
use dom::bindings::utils::{domstring_to_jsval, WrapNewBindingObject};
|
||||
use dom::bindings::utils::{str};
|
||||
use dom::bindings::utils::{str, CacheableWrapper, DOM_OBJECT_SLOT};
|
||||
use dom::bindings::utils;
|
||||
use dom::bindings::clientrectlist::ClientRectListImpl;
|
||||
use dom::element::*;
|
||||
use dom::node::{AbstractNode, Node, Element, ElementNodeTypeId};
|
||||
use layout::layout_task;
|
||||
|
@ -14,7 +16,8 @@ use js::crust::{JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_Con
|
|||
use js::glue::bindgen::*;
|
||||
use js::jsapi::bindgen::*;
|
||||
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSFreeOp, JSPropertySpec};
|
||||
use js::jsapi::{JSPropertyOpWrapper, JSStrictPropertyOpWrapper};
|
||||
use js::jsapi::{JSPropertyOpWrapper, JSStrictPropertyOpWrapper, JSFunctionSpec};
|
||||
use js::jsapi::JSNativeWrapper;
|
||||
use js::rust::{Compartment, jsobj};
|
||||
use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL};
|
||||
use js::{JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
|
||||
|
@ -22,7 +25,7 @@ use js::{JS_THIS_OBJECT, JS_SET_RVAL, JSPROP_NATIVE_ACCESSORS};
|
|||
extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
|
||||
debug!("element finalize!");
|
||||
unsafe {
|
||||
let val = JS_GetReservedSlot(obj, 0);
|
||||
let val = JS_GetReservedSlot(obj, DOM_OBJECT_SLOT as u32);
|
||||
let _node: ~AbstractNode = cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val));
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +54,11 @@ pub fn init(compartment: @mut Compartment) {
|
|||
call: JSNativeWrapper {op: getClientRects, info: null()},
|
||||
nargs: 0,
|
||||
flags: 0,
|
||||
selfHostedName: null()},
|
||||
JSFunctionSpec {name: null(),
|
||||
call: JSNativeWrapper {op: null(), info: null()},
|
||||
nargs: 0,
|
||||
flags: 0,
|
||||
selfHostedName: null()}];
|
||||
vec::as_imm_buf(*methods, |fns, _len| {
|
||||
JS_DefineFunctions(compartment.cx.ptr, obj.ptr, fns);
|
||||
|
@ -82,24 +90,25 @@ pub fn init(compartment: @mut Compartment) {
|
|||
});
|
||||
}
|
||||
|
||||
/*trait Element: utils::CacheableWrapper {
|
||||
fn getClientRects() -> Option<@ClientRectListImpl>;
|
||||
}*/
|
||||
|
||||
/*extern fn getClientRects(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
|
||||
extern fn getClientRects(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
|
||||
unsafe {
|
||||
let self: @Element =
|
||||
cast::reinterpret_cast(&utils::unwrap::<ElementData>(JS_THIS_OBJECT(cx, vp)));
|
||||
let rval = self.getClientRects();
|
||||
if rval.is_none() {
|
||||
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||
} else {
|
||||
assert WrapNewBindingObject(cx, (self as utils::CacheableWrapper).get_wrapper(), rval.get(), cast::transmute(vp));
|
||||
}
|
||||
cast::forget(self);
|
||||
return 1;
|
||||
let obj = JS_THIS_OBJECT(cx, vp);
|
||||
let box = utils::unwrap::<*rust_box<AbstractNode>>(obj);
|
||||
let node = &(*box).payload;
|
||||
let rval = do node.with_imm_element |elem| {
|
||||
elem.getClientRects()
|
||||
};
|
||||
if rval.is_none() {
|
||||
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||
} else {
|
||||
let cache = node.get_wrappercache();
|
||||
assert WrapNewBindingObject(cx, cache.get_wrapper(),
|
||||
rval.get(),
|
||||
cast::transmute(vp));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
#[allow(non_implicitly_copyable_typarams)]
|
||||
extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
||||
|
@ -149,6 +158,7 @@ extern fn HTMLImageElement_setWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa
|
|||
ElementNodeTypeId(_) => fail!(~"why is this not an image element?"),
|
||||
_ => fail!(~"why is this not an element?")
|
||||
};
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -187,12 +197,13 @@ pub fn create(cx: *JSContext, node: AbstractNode) -> jsobj {
|
|||
let obj = result::unwrap(compartment.new_object_with_proto(~"GenericElementInstance",
|
||||
proto,
|
||||
compartment.global_obj.ptr));
|
||||
|
||||
|
||||
node.get_wrappercache().set_wrapper(obj.ptr);
|
||||
|
||||
unsafe {
|
||||
let raw_ptr: *libc::c_void =
|
||||
cast::reinterpret_cast(&squirrel_away_unique(~node));
|
||||
JS_SetReservedSlot(obj.ptr, 0, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||
let raw_ptr = squirrel_away_unique(~node) as *libc::c_void;
|
||||
JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT as u32, RUST_PRIVATE_TO_JSVAL(raw_ptr));
|
||||
}
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use dom::bindings::utils::{rust_box, squirrel_away_unique, get_compartment};
|
||||
use dom::bindings::utils::{str, domstring_to_jsval};
|
||||
use dom::bindings::utils::{str, domstring_to_jsval, CacheableWrapper, WrapperCache};
|
||||
use dom::bindings::utils::{DOM_OBJECT_SLOT};
|
||||
use dom::node::{AbstractNode, Node, ElementNodeTypeId, TextNodeTypeId, CommentNodeTypeId};
|
||||
use dom::node::{DoctypeNodeTypeId};
|
||||
use super::element;
|
||||
|
@ -69,8 +70,8 @@ pub fn create(cx: *JSContext, node: AbstractNode) -> jsobj {
|
|||
}
|
||||
|
||||
pub unsafe fn unwrap(obj: *JSObject) -> *rust_box<AbstractNode> {
|
||||
let val = js::GetReservedSlot(obj, 0);
|
||||
cast::reinterpret_cast(&JSVAL_TO_PRIVATE(val))
|
||||
let val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT as u64);
|
||||
cast::transmute(JSVAL_TO_PRIVATE(val))
|
||||
}
|
||||
|
||||
#[allow(non_implicitly_copyable_typarams)]
|
||||
|
@ -107,6 +108,7 @@ extern fn getNextSibling(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBoo
|
|||
let node = &(*unwrap(obj)).payload;
|
||||
let rval = do node.with_imm_node |node| {
|
||||
node.getNextSibling()
|
||||
<<<<<<< HEAD
|
||||
};
|
||||
match rval {
|
||||
Some(n) => {
|
||||
|
@ -115,6 +117,16 @@ extern fn getNextSibling(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBoo
|
|||
}
|
||||
None => *vp = JSVAL_NULL
|
||||
}
|
||||
=======
|
||||
};
|
||||
match rval {
|
||||
Some(n) => {
|
||||
let obj = create(cx, n).ptr;
|
||||
*vp = RUST_OBJECT_TO_JSVAL(obj)
|
||||
}
|
||||
None => *vp = JSVAL_NULL
|
||||
};
|
||||
>>>>>>> Generate working ClientRectList and ClientRect bindings that can wrap, call methods, and access properties.
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -131,6 +143,13 @@ impl Node {
|
|||
|
||||
fn getNextSibling(&self) -> Option<AbstractNode> {
|
||||
self.next_sibling
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
}
|
||||
|
||||
fn getFirstChild(&self) -> Option<AbstractNode> {
|
||||
self.first_child
|
||||
>>>>>>> Generate working ClientRectList and ClientRect bindings that can wrap, call methods, and access properties.
|
||||
}
|
||||
|
||||
fn getFirstChild(&self) -> Option<AbstractNode> {
|
||||
|
@ -153,3 +172,19 @@ extern fn getNodeType(cx: *JSContext, _argc: c_uint, vp: *mut JSVal) -> JSBool {
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
impl CacheableWrapper for AbstractNode {
|
||||
fn get_wrappercache(&self) -> &WrapperCache {
|
||||
do self.with_imm_node |n| {
|
||||
unsafe { cast::transmute(&n.wrapper) }
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fail!(~"need to implement wrapping");
|
||||
}
|
||||
|
||||
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fail!(~"need to implement wrapping");
|
||||
}
|
||||
}
|
||||
|
|
82
src/servo/dom/bindings/proxyhandler.rs
Normal file
82
src/servo/dom/bindings/proxyhandler.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString, jschar};
|
||||
use js::jsapi::bindgen::{JS_GetPropertyDescriptorById, JS_GetPrototype};
|
||||
use js::jsapi::bindgen::{JS_NewUCString, JS_malloc, JS_free};
|
||||
use js::glue::bindgen::{RUST_JSVAL_IS_VOID, RUST_JSVAL_TO_OBJECT, GetProxyExtra};
|
||||
use js::glue::bindgen::{GetObjectProto};
|
||||
|
||||
use core::sys::size_of;
|
||||
|
||||
type c_bool = libc::c_int;
|
||||
|
||||
extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
|
||||
set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
|
||||
unsafe {
|
||||
if _getOwnPropertyDescriptor(cx, proxy, id, set, desc) == 0 {
|
||||
return 0;
|
||||
}
|
||||
if (*desc).obj.is_not_null() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
//let proto = JS_GetPrototype(proxy);
|
||||
let proto = GetObjectProto(proxy);
|
||||
if proto.is_null() {
|
||||
(*desc).obj = ptr::null();
|
||||
return 1;
|
||||
}
|
||||
|
||||
JS_GetPropertyDescriptorById(cx, proto, id, 0x01 /*JSRESOLVE_QUALIFIED*/,
|
||||
cast::transmute(desc))
|
||||
}
|
||||
}
|
||||
|
||||
fn _getOwnPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
|
||||
set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
|
||||
unsafe {
|
||||
let v = GetProxyExtra(proxy, 0 /*JSPROXYSLOT_EXPANDO*/);
|
||||
if RUST_JSVAL_IS_VOID(v) == 0 {
|
||||
let expando = RUST_JSVAL_TO_OBJECT(v);
|
||||
if JS_GetPropertyDescriptorById(cx, expando, id, 0x01 /*JSRESOLVE_QUALIFIED*/,
|
||||
cast::transmute(desc)) == 0 {
|
||||
return 0;
|
||||
}
|
||||
if (*desc).obj.is_not_null() {
|
||||
(*desc).obj = proxy;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
(*desc).obj = ptr::null();
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
extern fn getOwnPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
|
||||
set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
|
||||
_getOwnPropertyDescriptor(cx, proxy, id, set, desc)
|
||||
}
|
||||
|
||||
fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
||||
unsafe {
|
||||
let name = str::raw::from_buf(className as *u8);
|
||||
let nchars = "[object ]".len() + name.len();
|
||||
let chars: *mut jschar = cast::transmute(JS_malloc(cx, nchars as u64 * (size_of::<jschar>() as u64)));
|
||||
if chars.is_null() {
|
||||
return ptr::null();
|
||||
}
|
||||
|
||||
let result = ~"[object " + name + ~"]";
|
||||
for result.each_chari |i, c| {
|
||||
*chars.offset(i) = c as jschar;
|
||||
}
|
||||
*chars.offset(nchars) = 0;
|
||||
let jsstr = JS_NewUCString(cx, cast::transmute(chars), nchars as u64);
|
||||
if jsstr.is_null() {
|
||||
JS_free(cx, cast::transmute(chars));
|
||||
}
|
||||
jsstr
|
||||
}
|
||||
}
|
||||
|
||||
pub fn GetExpandoObject(proxy: *JSObject) -> *JSObject {
|
||||
ptr::null()
|
||||
}
|
|
@ -2,9 +2,9 @@ use js;
|
|||
use js::rust::Compartment;
|
||||
use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL,
|
||||
JS_THIS_OBJECT, JS_SET_RVAL, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY,
|
||||
JSPROP_PERMANENT};
|
||||
JSPROP_PERMANENT, JSID_VOID, JSPROP_NATIVE_ACCESSORS, JSPROP_GETTER, JSPROP_SETTER};
|
||||
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSFreeOp, JSNative,
|
||||
JSFunctionSpec, JSPropertySpec, JSVal, JSString};
|
||||
JSFunctionSpec, JSPropertySpec, JSVal, JSString, JSPropertyDescriptor};
|
||||
use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
|
||||
JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
|
||||
JS_DefineFunctions, JS_DefineProperty, JS_GetContextPrivate,
|
||||
|
@ -12,7 +12,8 @@ use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_Repor
|
|||
JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction,
|
||||
JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject,
|
||||
JS_GetInternedStringCharsAndLength, JS_DefineProperties,
|
||||
JS_WrapValue};
|
||||
JS_WrapValue, JS_GetObjectPrototype, JS_ForwardGetPropertyTo,
|
||||
JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
|
||||
use js::jsfriendapi::bindgen::{DefineFunctionWithReserved, GetObjectJSClass,
|
||||
JS_NewObjectWithUniqueType};
|
||||
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB,
|
||||
|
@ -22,9 +23,23 @@ use core::ptr::null;
|
|||
use core::cast;
|
||||
use content::content_task::{Content, task_from_context};
|
||||
|
||||
use core::hashmap::linear;
|
||||
|
||||
const TOSTRING_CLASS_RESERVED_SLOT: u64 = 0;
|
||||
const TOSTRING_NAME_RESERVED_SLOT: u64 = 1;
|
||||
|
||||
struct GlobalStaticData {
|
||||
mut proxy_handlers: linear::LinearMap<uint, *libc::c_void>,
|
||||
mut attribute_ids: linear::LinearMap<uint, ~[mut jsid]>
|
||||
}
|
||||
|
||||
pub fn GlobalStaticData() -> GlobalStaticData {
|
||||
GlobalStaticData {
|
||||
proxy_handlers: linear::LinearMap::new(),
|
||||
attribute_ids: linear::LinearMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
extern fn InterfaceObjectToString(cx: *JSContext, argc: uint, vp: *mut JSVal) -> JSBool {
|
||||
unsafe {
|
||||
let callee = RUST_JSVAL_TO_OBJECT(*JS_CALLEE(cx, cast::transmute(&vp)));
|
||||
|
@ -72,9 +87,20 @@ pub struct rust_box<T> {
|
|||
payload: T
|
||||
}
|
||||
|
||||
fn is_dom_class(clasp: *JSClass) -> bool {
|
||||
unsafe {
|
||||
((*clasp).flags & js::JSCLASS_IS_DOMJSCLASS) != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn unwrap<T>(obj: *JSObject) -> T {
|
||||
let val = JS_GetReservedSlot(obj, 0);
|
||||
cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val))
|
||||
let slot = if is_dom_class(JS_GetClass(obj)) {
|
||||
DOM_OBJECT_SLOT
|
||||
} else {
|
||||
DOM_PROXY_OBJECT_SLOT
|
||||
} as u32;
|
||||
let val = JS_GetReservedSlot(obj, slot);
|
||||
cast::transmute(RUST_JSVAL_TO_PRIVATE(val))
|
||||
}
|
||||
|
||||
pub unsafe fn squirrel_away<T>(x: @T) -> *rust_box<T> {
|
||||
|
@ -189,7 +215,7 @@ pub fn instance_jsclass(name: ~str, finalize: *u8)
|
|||
let f: @fn(@mut Compartment) -> JSClass = |compartment: @mut Compartment| {
|
||||
JSClass {
|
||||
name: compartment.add_name(copy name),
|
||||
flags: JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||
flags: JSCLASS_HAS_RESERVED_SLOTS(1) | js::JSCLASS_IS_DOMJSCLASS,
|
||||
addProperty: GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
||||
delProperty: GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
||||
getProperty: GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
||||
|
@ -240,7 +266,8 @@ pub fn define_empty_prototype(name: ~str, proto: Option<~str>, compartment: @mut
|
|||
|
||||
// We use slot 0 for holding the raw object. This is safe for both
|
||||
// globals and non-globals.
|
||||
const DOM_OBJECT_SLOT: uint = 0;
|
||||
pub const DOM_OBJECT_SLOT: uint = 0;
|
||||
const DOM_PROXY_OBJECT_SLOT: uint = js::JSSLOT_PROXY_PRIVATE as uint;
|
||||
|
||||
// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
|
||||
// LSetDOMProperty. Those constants need to be changed accordingly if this value
|
||||
|
@ -511,27 +538,45 @@ pub extern fn ThrowingConstructor(cx: *JSContext, argc: uint, vp: *JSVal) -> JSB
|
|||
pub fn initialize_global(global: *JSObject) {
|
||||
let protoArray = @[0 as *JSObject, ..2]; //XXXjdm number of constructors
|
||||
unsafe {
|
||||
//XXXjdm we should be storing the box pointer instead of the inner
|
||||
let box = squirrel_away(protoArray);
|
||||
let inner = ptr::to_unsafe_ptr(&(*box).payload);
|
||||
JS_SetReservedSlot(global, DOM_PROTOTYPE_SLOT,
|
||||
JS_SetReservedSlot(global,
|
||||
DOM_PROTOTYPE_SLOT,
|
||||
RUST_PRIVATE_TO_JSVAL(inner as *libc::c_void));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CacheableWrapper {
|
||||
fn get_wrapper(@self) -> *JSObject;
|
||||
fn set_wrapper(@self, wrapper: *JSObject);
|
||||
fn wrap_object(@self, cx: *JSContext, scope: *JSObject) -> *JSObject;
|
||||
fn get_wrappercache(&self) -> &WrapperCache;
|
||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject;
|
||||
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject;
|
||||
}
|
||||
|
||||
pub struct WrapperCache {
|
||||
wrapper: *mut JSObject
|
||||
mut wrapper: *JSObject
|
||||
}
|
||||
|
||||
impl WrapperCache {
|
||||
fn get_wrapper(&self) -> *JSObject {
|
||||
unsafe { cast::transmute(self.wrapper) }
|
||||
}
|
||||
|
||||
fn set_wrapper(&self, wrapper: *JSObject) {
|
||||
unsafe { self.wrapper = wrapper; }
|
||||
}
|
||||
|
||||
static fn new() -> WrapperCache {
|
||||
WrapperCache {
|
||||
wrapper: ptr::null()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn WrapNewBindingObject<T: CacheableWrapper>(cx: *JSContext, scope: *JSObject,
|
||||
value: @T, vp: *mut JSVal) -> bool {
|
||||
value: ~T, vp: *mut JSVal) -> bool {
|
||||
unsafe {
|
||||
let obj = value.get_wrapper();
|
||||
let obj = value.get_wrappercache().get_wrapper();
|
||||
if obj.is_not_null() /*&& js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)*/ {
|
||||
*vp = RUST_OBJECT_TO_JSVAL(obj);
|
||||
return true;
|
||||
|
@ -540,7 +585,7 @@ pub fn WrapNewBindingObject<T: CacheableWrapper>(cx: *JSContext, scope: *JSObjec
|
|||
let obj = if obj.is_not_null() {
|
||||
obj
|
||||
} else {
|
||||
value.wrap_object(cx, scope)
|
||||
value.wrap_object_unique(cx, scope)
|
||||
};
|
||||
|
||||
if obj.is_null() {
|
||||
|
@ -553,16 +598,173 @@ pub fn WrapNewBindingObject<T: CacheableWrapper>(cx: *JSContext, scope: *JSObjec
|
|||
}
|
||||
}
|
||||
|
||||
pub fn WrapNativeParent(cx: *JSContext, scope: *JSObject, p: @CacheableWrapper)
|
||||
-> *JSObject {
|
||||
let obj = p.get_wrapper();
|
||||
if obj.is_not_null() {
|
||||
return obj;
|
||||
}
|
||||
pub struct OpaqueBindingReference(Either<~CacheableWrapper, @CacheableWrapper>);
|
||||
|
||||
return ptr::null();
|
||||
pub fn WrapNativeParent(cx: *JSContext, scope: *JSObject, p: OpaqueBindingReference) -> *JSObject {
|
||||
match p {
|
||||
OpaqueBindingReference(Left(p)) => {
|
||||
let obj = p.get_wrappercache().get_wrapper();
|
||||
if obj.is_not_null() {
|
||||
return obj;
|
||||
}
|
||||
p.wrap_object_unique(cx, scope)
|
||||
}
|
||||
OpaqueBindingReference(Right(p)) => {
|
||||
let obj = p.get_wrappercache().get_wrapper();
|
||||
if obj.is_not_null() {
|
||||
return obj;
|
||||
}
|
||||
p.wrap_object_shared(cx, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BindingReference<T>(Either<~T, @T>);
|
||||
|
||||
pub trait BindingObject {
|
||||
fn GetParentObject(@self, cx: *JSContext) -> @CacheableWrapper;
|
||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference;
|
||||
}
|
||||
|
||||
pub impl<T: BindingObject + CacheableWrapper> BindingReference<T> {
|
||||
fn GetParentObject(&self, cx: *JSContext) -> OpaqueBindingReference {
|
||||
match **self {
|
||||
Left(ref obj) => obj.GetParentObject(cx),
|
||||
Right(ref obj) => obj.GetParentObject(cx)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_wrappercache(&self) -> &self/WrapperCache {
|
||||
match **self {
|
||||
Left(ref obj) => obj.get_wrappercache(),
|
||||
Right(ref obj) => obj.get_wrappercache()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn squirrel_away_ref<R>(obj: BindingReference<R>) -> *rust_box<R> {
|
||||
unsafe {
|
||||
match obj {
|
||||
BindingReference(Left(obj)) => squirrel_away_unique(obj),
|
||||
BindingReference(Right(obj)) => squirrel_away(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn GetPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid, found: *mut bool,
|
||||
vp: *JSVal) -> bool {
|
||||
unsafe {
|
||||
//let proto = GetObjectProto(proxy);
|
||||
let proto = JS_GetPrototype(proxy);
|
||||
if proto.is_null() {
|
||||
*found = false;
|
||||
return true;
|
||||
}
|
||||
let hasProp = 0;
|
||||
if JS_HasPropertyById(cx, proto, id, ptr::to_unsafe_ptr(&hasProp)) == 0 {
|
||||
return false;
|
||||
}
|
||||
*found = hasProp != 0;
|
||||
let no_output = vp.is_null();
|
||||
if hasProp == 0 || no_output {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp) != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn GetArrayIndexFromId(cx: *JSContext, id: jsid) -> Option<u32> {
|
||||
if RUST_JSID_IS_INT(id) != 0 {
|
||||
return Some(RUST_JSID_TO_INT(id) as u32);
|
||||
}
|
||||
return None;
|
||||
// if id is length atom, -1, otherwise
|
||||
/*return if JSID_IS_ATOM(id) {
|
||||
let atom = JSID_TO_ATOM(id);
|
||||
//let s = *GetAtomChars(id);
|
||||
if s > 'a' && s < 'z' {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
let str = AtomToLinearString(JSID_TO_ATOM(id));
|
||||
return if StringIsArray(str, &mut i) != 0 { i } else { -1 }
|
||||
} else {
|
||||
IdToInt32(cx, id);
|
||||
}*/
|
||||
}
|
||||
|
||||
pub fn XrayResolveProperty(cx: *JSContext,
|
||||
wrapper: *JSObject,
|
||||
id: jsid,
|
||||
desc: *mut JSPropertyDescriptor,
|
||||
methods: Option<~[(JSFunctionSpec, jsid)]>,
|
||||
attributes: Option<~[(JSPropertySpec, jsid)]>,
|
||||
constants: Option<~[(ConstantSpec, jsid)]>) -> bool
|
||||
{
|
||||
unsafe {
|
||||
match attributes {
|
||||
Some(attrs) => {
|
||||
for attrs.each |&elem| {
|
||||
let (attr, attr_id) = elem;
|
||||
if attr_id == JSID_VOID || attr_id != id {
|
||||
loop;
|
||||
}
|
||||
|
||||
(*desc).attrs = (attr.flags & !(JSPROP_NATIVE_ACCESSORS as u8)) as u32;
|
||||
let global = JS_GetGlobalForObject(cx, wrapper);
|
||||
let fun = JS_NewFunction(cx, attr.getter.op, 0, 0, global, ptr::null());
|
||||
if fun.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
RUST_SET_JITINFO(fun, attr.getter.info);
|
||||
let funobj = JS_GetFunctionObject(fun);
|
||||
(*desc).getter = funobj as *u8;
|
||||
(*desc).attrs |= JSPROP_GETTER;
|
||||
if attr.setter.op.is_not_null() {
|
||||
let fun = JS_NewFunction(cx, attr.setter.op, 1, 0, global, ptr::null());
|
||||
if fun.is_null() {
|
||||
return false
|
||||
}
|
||||
|
||||
RUST_SET_JITINFO(fun, attr.setter.info);
|
||||
let funobj = JS_GetFunctionObject(fun);
|
||||
(*desc).setter = funobj as *u8;
|
||||
(*desc).attrs |= JSPROP_SETTER;
|
||||
} else {
|
||||
(*desc).setter = ptr::null();
|
||||
}
|
||||
}
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn InternJSString(cx: *JSContext, chars: *libc::c_char) -> Option<jsid> {
|
||||
let s = JS_InternString(cx, chars);
|
||||
if s.is_not_null() {
|
||||
Some(RUST_INTERNED_STRING_TO_JSID(cx, s))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn InitIds(cx: *JSContext, specs: &[JSPropertySpec], ids: &[mut jsid]) -> bool {
|
||||
let mut rval = true;
|
||||
for specs.eachi |i, spec| {
|
||||
if spec.name.is_null() == true {
|
||||
break;
|
||||
}
|
||||
match InternJSString(cx, spec.name) {
|
||||
Some(id) => ids[i] = id,
|
||||
None => {
|
||||
rval = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
rval
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use dom::bindings::node::create;
|
||||
use dom::bindings::utils::{rust_box, squirrel_away, jsval_to_str, CacheableWrapper};
|
||||
use dom::bindings::utils::{WrapperCache};
|
||||
use dom::node::Node;
|
||||
use dom::window::{Window, TimerMessage_Fire};
|
||||
use super::utils;
|
||||
|
@ -115,6 +116,8 @@ pub fn init(compartment: @mut Compartment, win: @Window) {
|
|||
}
|
||||
];
|
||||
|
||||
win.get_wrappercache().set_wrapper(obj.ptr);
|
||||
|
||||
unsafe {
|
||||
JS_DefineFunctions(compartment.cx.ptr, proto.ptr, &methods[0]);
|
||||
|
||||
|
@ -127,20 +130,18 @@ pub fn init(compartment: @mut Compartment, win: @Window) {
|
|||
compartment.define_property(~"window", RUST_OBJECT_TO_JSVAL(obj.ptr),
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE);
|
||||
|
||||
win.set_wrapper(obj.ptr);
|
||||
}
|
||||
|
||||
pub impl CacheableWrapper for Window {
|
||||
fn get_wrapper(@self) -> *JSObject {
|
||||
self.wrapper
|
||||
fn get_wrappercache(&self) -> &WrapperCache {
|
||||
unsafe { cast::transmute(&self.wrapper) }
|
||||
}
|
||||
|
||||
fn set_wrapper(@self, wrapper: *JSObject) {
|
||||
self.wrapper = wrapper;
|
||||
fn wrap_object_unique(~self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fail!(~"should this be called?");
|
||||
}
|
||||
|
||||
fn wrap_object(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fn wrap_object_shared(@self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||
fail!(~"should this be called?");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
|
||||
use dom::node::{ElementNodeTypeId, Node};
|
||||
use dom::bindings::clientrectlist::ClientRectListImpl;
|
||||
|
||||
use core::str::eq_slice;
|
||||
use core::cell::Cell;
|
||||
|
@ -138,6 +139,10 @@ pub impl Element {
|
|||
}
|
||||
self.attrs.push(Attr::new(name.to_str(), value_cell.take()));
|
||||
}
|
||||
|
||||
fn getClientRects(&self) -> Option<~ClientRectListImpl> {
|
||||
Some(~ClientRectListImpl::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Attr {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
|
||||
use dom::bindings;
|
||||
use dom::bindings::utils::WrapperCache;
|
||||
use dom::document::Document;
|
||||
use dom::element::{Element, ElementTypeId, HTMLImageElement, HTMLImageElementTypeId};
|
||||
use dom::element::{HTMLStyleElementTypeId};
|
||||
|
@ -30,7 +31,8 @@ use std::arc::ARC;
|
|||
///
|
||||
/// FIXME: This should be replaced with a trait once they can inherit from structs.
|
||||
pub struct AbstractNode {
|
||||
priv obj: *mut Node
|
||||
priv obj: *mut Node,
|
||||
//wrapper: WrapperCache
|
||||
}
|
||||
|
||||
impl Eq for AbstractNode {
|
||||
|
@ -39,6 +41,7 @@ impl Eq for AbstractNode {
|
|||
}
|
||||
|
||||
pub struct Node {
|
||||
wrapper: WrapperCache,
|
||||
type_id: NodeTypeId,
|
||||
|
||||
parent_node: Option<AbstractNode>,
|
||||
|
@ -350,12 +353,14 @@ impl Node {
|
|||
static pub unsafe fn as_abstract_node<N>(node: ~N) -> AbstractNode {
|
||||
// This surrenders memory management of the node!
|
||||
AbstractNode {
|
||||
obj: transmute(node)
|
||||
obj: transmute(node),
|
||||
//wrapper: WrapperCache::new()
|
||||
}
|
||||
}
|
||||
|
||||
static pub fn new(type_id: NodeTypeId) -> Node {
|
||||
Node {
|
||||
wrapper: WrapperCache::new(),
|
||||
type_id: type_id,
|
||||
|
||||
parent_node: None,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use content::content_task::{ControlMsg, Timer, ExitMsg};
|
||||
use dom::bindings::utils::WrapperCache;
|
||||
use js::jsapi::{JSVal, JSObject};
|
||||
use util::task::spawn_listener;
|
||||
|
||||
|
@ -14,7 +15,7 @@ pub enum TimerControlMsg {
|
|||
|
||||
pub struct Window {
|
||||
timer_chan: Chan<TimerControlMsg>,
|
||||
mut wrapper: *JSObject
|
||||
wrapper: WrapperCache
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
|
@ -75,7 +76,7 @@ pub impl Window {
|
|||
pub fn Window(content_chan: comm::SharedChan<ControlMsg>) -> Window {
|
||||
|
||||
Window {
|
||||
wrapper: ptr::null(),
|
||||
wrapper: WrapperCache::new(),
|
||||
timer_chan: do spawn_listener |timer_port: Port<TimerControlMsg>| {
|
||||
loop {
|
||||
match timer_port.recv() {
|
||||
|
|
|
@ -46,6 +46,7 @@ pub mod dom {
|
|||
pub mod utils;
|
||||
pub mod conversions;
|
||||
pub mod window;
|
||||
pub mod proxyhandler;
|
||||
pub mod clientrect;
|
||||
pub mod clientrectlist;
|
||||
pub mod ClientRectBinding;
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
window.alert(ClientRect);
|
||||
window.alert(ClientRectList);
|
||||
//window.alert(ClientRect);
|
||||
//window.alert(ClientRectList);
|
||||
|
||||
window.alert("1");
|
||||
let elem = document.documentElement;
|
||||
window.alert(elem);
|
||||
window.alert("2");
|
||||
var rects = elem.getClientRects();
|
||||
window.alert("3");
|
||||
window.alert(rects);
|
||||
window.alert(rects.length);
|
||||
window.alert("4");
|
||||
let rect = rects[0];
|
||||
window.alert(rect);
|
||||
/*window.alert(Object.prototype.toString.call(rect.__proto__));
|
||||
window.alert(rect.__proto__ === Object.getPrototypeOf(rect));
|
||||
window.alert(rect.__proto__.top);
|
||||
window.alert(Object.getPrototypeOf(rect).top);*/
|
||||
window.alert(rect.top);
|
||||
window.alert(rect.bottom);
|
||||
window.alert(rect.left);
|
||||
window.alert(rect.right);
|
||||
window.alert(rect.width);
|
||||
window.alert(rect.height);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue