Generate working ClientRectList and ClientRect bindings that can wrap, call methods, and access properties.

This commit is contained in:
Josh Matthews 2013-02-28 19:18:08 -05:00
parent 77388999ef
commit 998e3ffded
15 changed files with 830 additions and 148 deletions

View file

@ -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);

View file

@ -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)) }
}
}

View file

@ -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)) }
}
}

View file

@ -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)

View file

@ -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> {

View file

@ -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;
}

View file

@ -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");
}
}

View 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()
}

View file

@ -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
}

View file

@ -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?");
}
}

View file

@ -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 {

View file

@ -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,

View file

@ -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() {

View file

@ -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;

View file

@ -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);