auto merge of #573 : jdm/servo/domevent, r=metajack

This commit is contained in:
bors-servo 2013-07-12 08:45:33 -07:00
commit 0c4119b496
16 changed files with 895 additions and 146 deletions

View file

@ -256,6 +256,9 @@ DOMInterfaces = {
'workers': True,
}],
'MouseEvent': {
},
'NodeList': [
{
'nativeType': 'nsINodeList',
@ -333,6 +336,9 @@ DOMInterfaces = {
'resultNotAddRefed': [ 'getItem' ]
}],
'UIEvent': {
},
'WebGLRenderingContext': {
'nativeType': 'mozilla::WebGLContext',
'headerFile': 'WebGLContext.h',
@ -499,7 +505,7 @@ def addExternalIface(iface, nativeType=None, headerFile=None, pointerType=None):
# If you add one of these, you need to make sure nsDOMQS.h has the relevant
# macros added for it
def addExternalHTMLElement(element):
nativeElement = 'ns' + element
nativeElement = element
addExternalIface(element, nativeType=nativeElement,
headerFile=nativeElement + '.h')
@ -520,7 +526,7 @@ addExternalIface('File')
addExternalIface('HitRegionOptions', nativeType='nsISupports')
addExternalIface('HTMLElement')
addExternalIface('ImageData', nativeType='mozilla::dom::ImageData')
addExternalIface('Node', nativeType='nsINode')
addExternalIface('Node', nativeType='AbstractNode<ScriptView>', pointerType='')
addExternalIface('PaintRequest')
addExternalIface('SVGLength')
addExternalIface('SVGMatrix')
@ -552,4 +558,5 @@ addExternalIface('WebGLShaderPrecisionFormat',
addExternalIface('WebGLTexture', nativeType='mozilla::WebGLTexture',
headerFile='WebGLContext.h')
addExternalIface('Window')
addExternalIface('WindowProxy', nativeType='WindowProxy')
addExternalIface('XULElement')

View file

@ -24,16 +24,21 @@ def replaceFileIfChanged(filename, newContents):
Read a copy of the old file, so that we don't touch it if it hasn't changed.
Returns True if the file was updated, false otherwise.
"""
oldFileContents = ""
try:
oldFile = open(filename, 'rb')
oldFileContents = ''.join(oldFile.readlines())
oldFile.close()
except:
pass
#XXXjdm This doesn't play well with make right now.
# Force the file to always be updated, or else changing CodegenRust.py
# will cause many autogenerated bindings to be regenerated perpetually
# until the result is actually different.
if newContents == oldFileContents:
return False
#oldFileContents = ""
#try:
# oldFile = open(filename, 'rb')
# oldFileContents = ''.join(oldFile.readlines())
# oldFile.close()
#except:
# pass
#if newContents == oldFileContents:
# return False
f = open(filename, 'wb')
f.write(newContents)
@ -91,6 +96,8 @@ class CastableObjectUnwrapper():
assert descriptor.castable
self.substitution = { "type" : descriptor.nativeType,
"depth": descriptor.interface.inheritanceDepth(),
"prototype": "prototypes::id::" + descriptor.name,
"protoID" : "prototypes::id::" + descriptor.name + " as uint",
"source" : source,
"target" : target,
@ -115,8 +122,14 @@ class CastableObjectUnwrapper():
def __str__(self):
return string.Template(
"""${target} = unwrap(${source});
"""match unwrap_object(${source}, ${prototype}, ${depth}) {
Ok(val) => ${target} = val,
Err(()) => {
${codeOnFailure}
}
}
""").substitute(self.substitution)
#"""{
# nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
# if (NS_FAILED(rv)) {
@ -130,7 +143,7 @@ class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
"""
def __init__(self, descriptor, source, target):
CastableObjectUnwrapper.__init__(self, descriptor, source, target,
"return Throw<%s>(cx, rv);" %
"return 0; //XXXjdm return Throw<%s>(cx, rv);" %
toStringBool(not descriptor.workers))
class CGThing():
@ -394,6 +407,10 @@ class FakeCastableDescriptor():
self.pointerType = descriptor.pointerType
self.name = descriptor.name
self.hasXPConnectImpls = descriptor.hasXPConnectImpls
class FakeInterface:
def inheritanceDepth(self):
return descriptor.interface.inheritanceDepth()
self.interface = FakeInterface()
def dictionaryHasSequenceMember(dictionary):
return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
@ -543,7 +560,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
CGIndenter(CGGeneric(templateBody)).define() + "\n")
if type.nullable():
templateBody += (
"} else if (${val}.isNullOrUndefined()) {\n"
"} else if RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0 {\n"
" %s;\n" % codeToSetNull)
templateBody += (
"} else {\n" +
@ -878,7 +895,7 @@ for (uint32_t i = 0; i < length; ++i) {
not descriptor.workers) or isMember
typeName = descriptor.nativeType
typePtr = typeName + "*"
typePtr = descriptor.pointerType + typeName
# Compute a few things:
# - declType is the type we want to return as the first element of our
@ -889,15 +906,9 @@ for (uint32_t i = 0; i < length; ++i) {
# Set up some sensible defaults for these things insofar as we can.
holderType = None
if argIsPointer:
if forceOwningType:
declType = "nsRefPtr<" + typeName + ">"
declType = "Option<" + typePtr + ">"
else:
declType = typePtr
else:
if forceOwningType:
declType = "OwningNonNull<" + typeName + ">"
else:
declType = descriptor.pointerType + typeName
templateBody = ""
if descriptor.castable:
@ -931,41 +942,19 @@ for (uint32_t i = 0; i < length; ++i) {
elif descriptor.workers:
templateBody += "${declName} = &${val}.toObject();"
else:
# Either external, or new-binding non-castable. We always have a
# holder for these, because we don't actually know whether we have
# to addref when unwrapping or not. So we just pass an
# getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
# it'll put a non-null pointer in there.
if forceOwningType:
# Don't return a holderType in this case; our declName
# will just own stuff.
templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
else:
holderType = "nsRefPtr<" + typeName + ">"
templateBody += (
"jsval tmpVal = ${val};\n" +
typePtr + " tmp;\n"
"if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
"match unwrap_value::<" + typePtr + ">(&${val} as *JSVal, "
"prototypes::id::%s, %d) {\n" % (descriptor.name, descriptor.interface.inheritanceDepth() if descriptor.concrete else 0) +
" Err(()) => {")
templateBody += CGIndenter(onFailureBadType(failureCode,
descriptor.interface.identifier.name)).define()
templateBody += ("}\n"
"MOZ_ASSERT(tmp);\n")
if not isDefinitelyObject:
# Our tmpVal will go out of scope, so we can't rely on it
# for rooting
templateBody += (
"if (tmpVal != ${val} && !${holderName}) {\n"
" // We have to have a strong ref, because we got this off\n"
" // some random object that might get GCed\n"
" ${holderName} = tmp;\n"
" }\n"
" Ok(unwrapped) => ${declName} = Some(unwrapped)\n"
"}\n")
# And store our tmp, before it goes out of scope.
templateBody += "${declName} = tmp;"
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
type, "${declName} = NULL",
type, "${declName} = None",
failureCode)
declType = CGGeneric(declType)
@ -1305,10 +1294,15 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
(holderType.define(), originalHolderName))
mutableHolderType = CGWrapper(holderType, pre="Optional< ", post=" >")
holderType = CGWrapper(mutableHolderType, pre="const ")
result.append(
CGList([holderType, CGGeneric(" "),
tmpresult = [CGGeneric("let "),
CGGeneric(originalHolderName),
CGGeneric(";")]))
CGGeneric(": "),
holderType]
if initialValue:
tmpresult += [CGGeneric(" = "),
initialValue]
tmpresult += [CGGeneric(";")]
result.append(CGList(tmpresult))
originalDeclName = replacements["declName"]
if declType is not None:
@ -2073,7 +2067,7 @@ class CGNativePropertyHooks(CGThing):
parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
if parent else '0 as *NativePropertyHooks')
return """
static 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 };
static 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*/ 0 as *NativePropertyHooks };
""" % (resolveOwnProperty, enumerateOwnProperties, parentHooks)
# We'll want to insert the indent at the beginnings of lines, but we
@ -2729,11 +2723,11 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
A method for getting a per-interface object (a prototype object or interface
constructor object).
"""
def __init__(self, descriptor, name, idPrefix=""):
def __init__(self, descriptor, name, idPrefix="", pub=False):
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aGlobal'),
Argument('*JSObject', 'aReceiver')]
CGAbstractMethod.__init__(self, descriptor, name,
'*JSObject', args, inline=True)
'*JSObject', args, inline=True, pub=pub)
self.id = idPrefix + "id::" + self.descriptor.name
def definition_body(self):
return """
@ -2765,7 +2759,7 @@ class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
"""
def __init__(self, descriptor):
CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
"prototypes::")
"prototypes::", pub=True)
def definition_body(self):
return """
/* Get the interface prototype object for this class. This will create the
@ -2846,7 +2840,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
getPrototypeOf: ptr::null()
};
(*script_context).dom_static.proxy_handlers.insert(prototypes::id::%s as uint,
CreateProxyHandler(ptr::to_unsafe_ptr(&traps)));
CreateProxyHandler(ptr::to_unsafe_ptr(&traps), ptr::to_unsafe_ptr(&Class) as *libc::c_void));
""" % self.descriptor.name
else:
@ -3107,6 +3101,25 @@ class FakeArgument():
self.enforceRange = False
self.clamp = False
class CGSetterCall(CGPerSignatureCall):
"""
A class to generate a native object setter call for a particular IDL
setter.
"""
def __init__(self, argType, nativeMethodName, descriptor, attr):
CGPerSignatureCall.__init__(self, None, [],
[FakeArgument(argType, attr)],
nativeMethodName, False, descriptor, attr,
setter=True)
def wrap_return_value(self):
# We have no return value
return "\nreturn 1;"
def getArgc(self):
return "1"
def getArgvDecl(self):
# We just get our stuff from our last arg no matter what
return ""
class CGAbstractBindingMethod(CGAbstractExternMethod):
"""
Common class to generate the JSNatives for all our methods, getters, and
@ -3119,7 +3132,7 @@ class CGAbstractBindingMethod(CGAbstractExternMethod):
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
if unwrapFailureCode is None:
self.unwrapFailureCode = ("return Throw<%s>(cx, rv);" %
self.unwrapFailureCode = ("return 0; //XXXjdm return Throw<%s>(cx, rv);" %
toStringBool(not descriptor.workers))
else:
self.unwrapFailureCode = unwrapFailureCode
@ -3138,7 +3151,7 @@ class CGAbstractBindingMethod(CGAbstractExternMethod):
def getThis(self):
return CGIndenter(
CGGeneric("let obj: *JSObject = JS_THIS_OBJECT(cx, vp);\n"
CGGeneric("let obj: *JSObject = JS_THIS_OBJECT(cx, cast::transmute(vp));\n"
"if obj.is_null() {\n"
" return false as JSBool;\n"
"}\n"
@ -3248,6 +3261,56 @@ class CGSpecializedGetter(CGAbstractExternMethod):
self.descriptor, self.attr)),
pre=" let obj = (*obj.unnamed);\n").define()
class CGGenericSetter(CGAbstractBindingMethod):
"""
A class for generating the Rust code for an IDL attribute setter.
"""
def __init__(self, descriptor, lenientThis=False):
args = [Argument('*JSContext', 'cx'), Argument('uint', 'argc'),
Argument('*mut JSVal', 'vp')]
if lenientThis:
name = "genericLenientSetter"
unwrapFailureCode = (
"MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"
"return true;")
else:
name = "genericSetter"
unwrapFailureCode = None
CGAbstractBindingMethod.__init__(self, descriptor, name, args,
unwrapFailureCode)
def generate_code(self):
return CGIndenter(CGGeneric(
"let undef = JSVAL_VOID;\n"
"let argv: *JSVal = if argc != 0 { JS_ARGV(cx, cast::transmute(vp)) } else { &undef as *JSVal };\n"
"let info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, cast::transmute(vp)));\n"
"if CallJitPropertyOp(info, cx, obj, ptr::to_unsafe_ptr(&(*this).payload) as *libc::c_void, cast::transmute(vp)) == 0 {"
" return 0;\n"
"}\n"
"*vp = JSVAL_VOID;\n"
"return 1;"))
class CGSpecializedSetter(CGAbstractExternMethod):
"""
A class for generating the code for a specialized attribute setter
that the JIT can call with lower overhead.
"""
def __init__(self, descriptor, attr):
self.attr = attr
name = 'set_' + attr.identifier.name
args = [ Argument('*JSContext', 'cx'),
Argument('JSHandleObject', 'obj'),
Argument('*mut %s' % descriptor.nativeType, 'this'),
Argument('*mut JSVal', 'argv')]
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
def definition_body(self):
name = self.attr.identifier.name
nativeName = "Set" + MakeNativeName(self.descriptor.binaryNames.get(name, name))
return CGWrapper(CGIndenter(CGSetterCall(self.attr.type, nativeName,
self.descriptor, self.attr)),
pre=" let obj = (*obj.unnamed);\n").define()
def infallibleForMember(member, type, descriptorProvider):
"""
Determine the fallibility of changing a C++ value of IDL type "type" into
@ -3786,7 +3849,7 @@ class CGDescriptor(CGThing):
else:
hasGetter = True
if not m.readonly:
#cgThings.append(CGSpecializedSetter(descriptor, m))
cgThings.append(CGSpecializedSetter(descriptor, m))
if m.hasLenientThis():
hasLenientSetter = True
else:
@ -3796,7 +3859,7 @@ class CGDescriptor(CGThing):
if hasGetter: cgThings.append(CGGenericGetter(descriptor))
#if hasLenientGetter: cgThings.append(CGGenericGetter(descriptor,
# lenientThis=True))
#if hasSetter: cgThings.append(CGGenericSetter(descriptor))
if hasSetter: cgThings.append(CGGenericSetter(descriptor))
#if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor,
# lenientThis=True))
@ -3926,7 +3989,8 @@ class CGDictionary(CGThing):
return ""
d = self.dictionary
if d.parent:
inheritance = ": public %s " % self.makeClassName(d.parent) #XXXjdm
inheritance = " parent: %s::%s,\n" % (self.makeModuleName(d.parent),
self.makeClassName(d.parent))
else:
inheritance = ""
memberDecls = [" %s: %s," %
@ -3934,7 +3998,8 @@ class CGDictionary(CGThing):
for m in self.memberInfo]
return (string.Template(
"pub struct ${selfName} {\n" + #XXXjdm deal with inheritance
"pub struct ${selfName} {\n" +
"${inheritance}" +
"\n".join(memberDecls) + "\n" +
# NOTE: jsids are per-runtime, so don't use them in workers
"\n".join(" //static jsid " +
@ -3949,13 +4014,13 @@ class CGDictionary(CGThing):
d = self.dictionary
if d.parent:
initParent = ("// Per spec, we init the parent's members first\n"
"if (!%s::Init(cx, val)) {\n"
" return false;\n"
"}\n" % self.makeClassName(d.parent))
"if self.parent.Init(cx, val) == 0 {\n"
" return 0;\n"
"}\n")
else:
initParent = ""
memberInits = [CGIndenter(self.getMemberConversion(m)).define()
memberInits = [CGIndenter(self.getMemberConversion(m), indentLevel=6).define()
for m in self.memberInfo]
idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' %
(m.identifier.name + "_id", m.identifier.name))
@ -3970,11 +4035,11 @@ class CGDictionary(CGThing):
def defaultValue(ty):
if ty is "bool":
return "false"
elif ty in ["i32", "u32"]:
elif ty in ["i32", "u32", "i16", "u16"]:
return "0"
elif ty is "nsString":
return "\"\""
elif ty.startswith("Optional"):
elif ty.startswith("Option"):
return "None"
else:
return "/* uh oh: %s */" % ty
@ -3987,24 +4052,25 @@ class CGDictionary(CGThing):
for m in d.members) + "\n"
"\n"
"impl ${selfName} {\n"
"fn new() -> ${selfName} {\n"
" pub fn new() -> ${selfName} {\n"
" ${selfName} {\n" +
((" parent: %s::%s::new(),\n" % (self.makeModuleName(d.parent),
self.makeClassName(d.parent))) if d.parent else "") +
"\n".join(" %s: %s," % (m[0].identifier.name, defaultValue(self.getMemberType(m))) for m in self.memberInfo) + "\n"
" }\n"
"}\n"
" }\n"
"\n"
"fn InitIds(cx: *JSContext) -> bool {\n"
" pub fn InitIds(&mut self, cx: *JSContext) -> bool {\n"
" //MOZ_ASSERT(!initedIds);\n"
"/*${idInit}\n"
" /*${idInit}\n"
" initedIds = true;*/ //XXXjdm\n"
" return true;\n"
"}\n"
" }\n"
"\n" if not self.workers else "") +
"fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool\n"
"{\n"
" pub fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool {\n"
" unsafe {\n" +
# NOTE: jsids are per-runtime, so don't use them in workers
(" if (!initedIds && !${selfName}::InitIds(cx)) {\n"
(" if (!initedIds && !self.InitIds(cx)) {\n"
" return 0;\n"
" }\n" if not self.workers else "") +
"${initParent}"
@ -4019,10 +4085,10 @@ class CGDictionary(CGThing):
"${initMembers}\n"
" return 1;\n"
" }\n"
"}\n"
" }\n"
"}").substitute({
"selfName": self.makeClassName(d),
"initParent": CGIndenter(CGGeneric(initParent)).define(),
"initParent": CGIndenter(CGGeneric(initParent), indentLevel=6).define(),
"initMembers": "\n\n".join(memberInits),
"idInit": CGIndenter(idinit).define(),
"isMainThread": toStringBool(not self.workers)
@ -4036,6 +4102,15 @@ class CGDictionary(CGThing):
def makeClassName(self, dictionary):
return self.makeDictionaryName(dictionary, self.workers)
@staticmethod
def makeModuleName(dictionary):
name = dictionary.identifier.name
if name.endswith('Init'):
return toBindingNamespace(name.replace('Init', ''))
#XXXjdm This breaks on the test webidl files, sigh.
#raise TypeError("No idea how to find this dictionary's definition: " + name)
return "/* uh oh */ %s" % name
def getMemberType(self, memberInfo):
(member, (templateBody, declType,
holderType, dealWithOptional, initialValue)) = memberInfo
@ -4209,6 +4284,10 @@ class CGBindingRoot(CGThing):
'dom::event::*', #XXXjdm
'dom::eventtarget::*', #XXXjdm
'dom::formdata::*', #XXXjdm
'dom::mouseevent::*', #XXXjdm
'dom::uievent::*', #XXXjdm
'dom::windowproxy::*', #XXXjdm
'dom::bindings::codegen::*', #XXXjdm
'script_task::task_from_context',
'dom::bindings::utils::EnumEntry',
'dom::node::ScriptView',

View file

@ -1,3 +1,15 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* For more information on this interface please see
* http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[Constructor(DOMString type, optional EventInit eventInitDict)]
interface Event {
readonly attribute DOMString type;

View file

@ -0,0 +1,76 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* For more information on this interface please see
* http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface MouseEvent : UIEvent {
readonly attribute long screenX;
readonly attribute long screenY;
readonly attribute long clientX;
readonly attribute long clientY;
readonly attribute boolean ctrlKey;
readonly attribute boolean shiftKey;
readonly attribute boolean altKey;
readonly attribute boolean metaKey;
readonly attribute unsigned short button;
readonly attribute unsigned short buttons;
readonly attribute EventTarget? relatedTarget;
// Deprecated in DOM Level 3:
[Throws]
void initMouseEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg,
WindowProxy? viewArg,
long detailArg,
long screenXArg,
long screenYArg,
long clientXArg,
long clientYArg,
boolean ctrlKeyArg,
boolean altKeyArg,
boolean shiftKeyArg,
boolean metaKeyArg,
unsigned short buttonArg,
EventTarget? relatedTargetArg);
// Introduced in DOM Level 3:
boolean getModifierState(DOMString keyArg);
};
// Event Constructor Syntax:
[Constructor(DOMString typeArg, optional MouseEventInit mouseEventInitDict)]
partial interface MouseEvent
{
};
// Suggested initMouseEvent replacement initializer:
dictionary MouseEventInit {
// Attributes from Event:
boolean bubbles = false;
boolean cancelable = false;
// Attributes from UIEvent:
WindowProxy? view = null;
long detail = 0;
// Attributes for MouseEvent:
long screenX = 0;
long screenY = 0;
long clientX = 0;
long clientY = 0;
boolean ctrlKey = false;
boolean shiftKey = false;
boolean altKey = false;
boolean metaKey = false;
unsigned short button = 0;
// Note: "buttons" was not previously initializable through initMouseEvent!
unsigned short buttons = 0;
EventTarget? relatedTarget = null;
};

View file

@ -1,34 +0,0 @@
#include "BlobBinding.h"
#include "ClientRectBinding.h"
#include "ClientRectListBinding.h"
#include "DOMParserBinding.h"
#include "EventBinding.h"
#include "EventTargetBinding.h"
#include "FormDataBinding.h"
#include "HTMLCollectionBinding.h"
#include "nsScriptNameSpaceManager.h"
namespace mozilla {
namespace dom {
void
Register(nsScriptNameSpaceManager* aNameSpaceManager)
{
#define REGISTER_PROTO(_dom_class, _pref_check) \
aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), _dom_class##Binding::DefineDOMInterface, _pref_check);
REGISTER_PROTO(Blob, nullptr);
REGISTER_PROTO(ClientRect, nullptr);
REGISTER_PROTO(ClientRectList, nullptr);
REGISTER_PROTO(DOMParser, nullptr);
REGISTER_PROTO(Event, nullptr);
REGISTER_PROTO(EventTarget, nullptr);
REGISTER_PROTO(FormData, nullptr);
REGISTER_PROTO(HTMLCollection, nullptr);
#undef REGISTER_PROTO
}
} // namespace dom
} // namespace mozilla

View file

@ -0,0 +1,48 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* For more information on this interface please see
* http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface WindowProxy;
interface Node;
[Constructor(DOMString type, optional UIEventInit eventInitDict)]
interface UIEvent : Event
{
readonly attribute WindowProxy? view;
readonly attribute long detail;
void initUIEvent(DOMString aType,
boolean aCanBubble,
boolean aCancelable,
WindowProxy? aView,
long aDetail);
};
// Additional DOM0 properties.
partial interface UIEvent {
const long SCROLL_PAGE_UP = -32768;
const long SCROLL_PAGE_DOWN = 32768;
readonly attribute long layerX;
readonly attribute long layerY;
readonly attribute long pageX;
readonly attribute long pageY;
readonly attribute unsigned long which;
readonly attribute Node? rangeParent;
readonly attribute long rangeOffset;
attribute boolean cancelBubble;
readonly attribute boolean isChar;
};
dictionary UIEventInit : EventInit
{
WindowProxy? view = null;
long detail = 0;
};

View file

@ -429,17 +429,19 @@ class IDLExternalInterface(IDLObjectWithIdentifier):
pass
class IDLInterface(IDLObjectWithScope):
def __init__(self, location, parentScope, name, parent, members):
def __init__(self, location, parentScope, name, parent, members,
isPartial):
assert isinstance(parentScope, IDLScope)
assert isinstance(name, IDLUnresolvedIdentifier)
assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
assert not isPartial or not parent
self.parent = parent
self.parent = None
self._callback = False
self._finished = False
self.members = list(members) # clone the list
self.members = []
self.implementedInterfaces = set()
self._consequential = False
self._isPartial = True
# self.interfacesBasedOnSelf is the set of interfaces that inherit from
# self or have self as a consequential interface, including self itself.
# Used for distinguishability checking.
@ -447,6 +449,12 @@ class IDLInterface(IDLObjectWithScope):
IDLObjectWithScope.__init__(self, location, parentScope, name)
if not isPartial:
self.setNonPartial(location, parent, members)
else:
# Just remember our members for now
self.members = list(members) # clone the list
def __str__(self):
return "Interface '%s'" % self.identifier.name
@ -482,6 +490,11 @@ class IDLInterface(IDLObjectWithScope):
self._finished = True
if self._isPartial:
raise WebIDLError("Interface %s does not have a non-partial "
"declaration" % self.identifier.name,
[self.location])
assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder)
parent = self.parent.finish(scope) if self.parent else None
if parent and isinstance(parent, IDLExternalInterface):
@ -749,6 +762,21 @@ class IDLInterface(IDLObjectWithScope):
def getExtendedAttribute(self, name):
return self._extendedAttrDict.get(name, None)
def setNonPartial(self, location, parent, members):
assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
if not self._isPartial:
raise WebIDLError("Two non-partial definitions for the "
"same interface",
[location, self.location])
self._isPartial = False
# Now make it look like we were parsed at this new location, since
# that's the place where the interface is "really" defined
self.location = location
assert not self.parent
self.parent = parent
# Put the new members at the beginning
self.members = members + self.members
class IDLDictionary(IDLObjectWithScope):
def __init__(self, location, parentScope, name, parent, members):
assert isinstance(parentScope, IDLScope)
@ -2742,9 +2770,25 @@ class Parser(Tokenizer):
"""
location = self.getLocation(p, 1)
identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
members = p[5]
p[0] = IDLInterface(location, self.globalScope(), identifier, p[3], members)
parent = p[3]
try:
if self.globalScope()._lookupIdentifier(identifier):
p[0] = self.globalScope()._lookupIdentifier(identifier)
if not isinstance(p[0], IDLInterface):
raise WebIDLError("Partial interface has the same name as "
"non-interface object",
[location, p[0].location])
p[0].setNonPartial(location, parent, members)
return
except Exception, ex:
if isinstance(ex, WebIDLError):
raise ex
pass
p[0] = IDLInterface(location, self.globalScope(), identifier, parent,
members, isPartial=False)
def p_InterfaceForwardDecl(self, p):
"""
@ -2766,6 +2810,29 @@ class Parser(Tokenizer):
"""
PartialInterface : PARTIAL INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
"""
location = self.getLocation(p, 2)
identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
members = p[5]
try:
if self.globalScope()._lookupIdentifier(identifier):
p[0] = self.globalScope()._lookupIdentifier(identifier)
if not isinstance(p[0], IDLInterface):
raise WebIDLError("Partial interface has the same name as "
"non-interface object",
[location, p[0].location])
# Just throw our members into the existing IDLInterface. If we
# have extended attributes, those will get added to it
# automatically.
p[0].members.extend(members)
return
except Exception, ex:
if isinstance(ex, WebIDLError):
raise ex
pass
p[0] = IDLInterface(location, self.globalScope(), identifier, None,
members, isPartial=True)
pass
def p_Inheritance(self, p):

View file

@ -25,6 +25,34 @@ impl JSValConvertible for u32 {
}
}
impl JSValConvertible for i32 {
fn to_jsval(&self) -> JSVal {
unsafe {
RUST_UINT_TO_JSVAL(*self as u32)
}
}
fn from_jsval(val: JSVal) -> Option<i32> {
unsafe {
Some(RUST_JSVAL_TO_INT(val) as i32)
}
}
}
impl JSValConvertible for u16 {
fn to_jsval(&self) -> JSVal {
unsafe {
RUST_UINT_TO_JSVAL(*self as u32)
}
}
fn from_jsval(val: JSVal) -> Option<u16> {
unsafe {
Some(RUST_JSVAL_TO_INT(val) as u16)
}
}
}
impl JSValConvertible for bool {
fn to_jsval(&self) -> JSVal {
if *self {

View file

@ -17,6 +17,7 @@ use std::uint;
use std::unstable::intrinsics;
use js::glue::*;
use js::glue::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL};
use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily};
use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB, RESOLVE_STUB};
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction};
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
@ -117,16 +118,62 @@ fn is_dom_class(clasp: *JSClass) -> bool {
}
}
fn is_dom_proxy(obj: *JSObject) -> bool {
unsafe {
(js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) &&
IsProxyHandlerFamily(obj)
}
}
pub unsafe fn unwrap<T>(obj: *JSObject) -> T {
let slot = if is_dom_class(JS_GetClass(obj)) {
let clasp = JS_GetClass(obj);
let slot = if is_dom_class(clasp) {
DOM_OBJECT_SLOT
} else {
assert!(is_dom_proxy(obj));
DOM_PROXY_OBJECT_SLOT
} as u32;
let val = JS_GetReservedSlot(obj, slot);
cast::transmute(RUST_JSVAL_TO_PRIVATE(val))
}
pub unsafe fn get_dom_class(obj: *JSObject) -> Result<DOMClass, ()> {
let clasp = JS_GetClass(obj);
if is_dom_class(clasp) {
debug!("plain old dom object");
let domjsclass: *DOMJSClass = cast::transmute(clasp);
return Ok((*domjsclass).dom_class);
}
if is_dom_proxy(obj) {
debug!("proxy dom object");
let dom_class: *DOMClass = cast::transmute(GetProxyHandlerExtra(obj));
return Ok(*dom_class);
}
debug!("not a dom object");
return Err(());
}
pub fn unwrap_object<T>(obj: *JSObject, proto_id: prototypes::id::Prototype, proto_depth: uint) -> Result<T, ()> {
unsafe {
do get_dom_class(obj).chain |dom_class| {
if dom_class.interface_chain[proto_depth] == proto_id {
debug!("good prototype");
Ok(unwrap(obj))
} else {
debug!("bad prototype");
Err(())
}
}
}
}
pub fn unwrap_value<T>(val: *JSVal, proto_id: prototypes::id::Prototype, proto_depth: uint) -> Result<T, ()> {
unsafe {
let obj = RUST_JSVAL_TO_OBJECT(*val);
unwrap_object(obj, proto_id, proto_depth)
}
}
pub unsafe fn squirrel_away<T>(x: @mut T) -> *rust_box<T> {
let y: *rust_box<T> = cast::transmute(x);
cast::forget(x);
@ -353,7 +400,7 @@ pub struct ConstantSpec {
pub struct DOMClass {
// A list of interfaces that this object implements, in order of decreasing
// derivedness.
interface_chain: [prototypes::id::Prototype, ..2 /*max prototype chain length*/],
interface_chain: [prototypes::id::Prototype, ..3 /*max prototype chain length*/],
unused: bool, // DOMObjectIsISupports (always false)
native_hooks: *NativePropertyHooks
@ -373,7 +420,9 @@ pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
pub mod prototypes {
pub mod id {
#[deriving(Eq)]
pub enum Prototype {
Blob,
ClientRect,
ClientRectList,
DOMParser,
@ -381,6 +430,9 @@ pub mod prototypes {
Event,
EventTarget,
FormData,
UIEvent,
MouseEvent,
WindowProxy,
_ID_Count
}
}
@ -583,7 +635,7 @@ pub extern fn ThrowingConstructor(_cx: *JSContext, _argc: uint, _vp: *JSVal) ->
}
pub fn initialize_global(global: *JSObject) {
let protoArray = @mut ([0 as *JSObject, ..7]); //XXXjdm prototypes::_ID_COUNT
let protoArray = @mut ([0 as *JSObject, ..10]); //XXXjdm prototypes::_ID_COUNT
unsafe {
//XXXjdm we should be storing the box pointer instead of the inner
let box = squirrel_away(protoArray);

View file

@ -0,0 +1,184 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::MouseEventBinding;
use dom::bindings::utils::{ErrorResult, DOMString};
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
use dom::eventtarget::EventTarget;
use dom::uievent::UIEvent;
use dom::window::Window;
use dom::windowproxy::WindowProxy;
use script_task::{global_script_context};
use js::glue::RUST_OBJECT_TO_JSVAL;
use js::jsapi::{JSObject, JSContext, JSVal};
pub struct MouseEvent {
parent: UIEvent,
screen_x: i32,
screen_y: i32,
client_x: i32,
client_y: i32,
ctrl_key: bool,
shift_key: bool,
alt_key: bool,
meta_key: bool,
button: u16,
related_target: Option<@mut EventTarget>
}
impl MouseEvent {
pub fn new(type_: DOMString, can_bubble: bool, cancelable: bool,
view: Option<@mut WindowProxy>, detail: i32, screen_x: i32,
screen_y: i32, client_x: i32, client_y: i32, ctrl_key: bool,
shift_key: bool, alt_key: bool, meta_key: bool, button: u16,
_buttons: u16, related_target: Option<@mut EventTarget>) -> MouseEvent {
MouseEvent {
parent: UIEvent::new(type_, can_bubble, cancelable, view, detail),
screen_x: screen_x,
screen_y: screen_y,
client_x: client_x,
client_y: client_y,
ctrl_key: ctrl_key,
shift_key: shift_key,
alt_key: alt_key,
meta_key: meta_key,
button: button,
related_target: related_target
}
}
pub fn init_wrapper(@mut self) {
let script_context = global_script_context();
let cx = script_context.js_compartment.cx.ptr;
let owner = script_context.root_frame.get_ref().window;
let cache = owner.get_wrappercache();
let scope = cache.get_wrapper();
self.wrap_object_shared(cx, scope);
}
pub fn Constructor(_owner: @mut Window,
type_: DOMString,
init: &MouseEventBinding::MouseEventInit,
_rv: &mut ErrorResult) -> @mut MouseEvent {
@mut MouseEvent::new(type_, init.bubbles, init.cancelable, init.view, init.detail,
init.screenX, init.screenY, init.clientX, init.clientY,
init.ctrlKey, init.shiftKey, init.altKey, init.metaKey,
init.button, init.buttons, init.relatedTarget)
}
pub fn ScreenX(&self) -> i32 {
self.screen_x
}
pub fn ScreenY(&self) -> i32 {
self.screen_y
}
pub fn ClientX(&self) -> i32 {
self.client_x
}
pub fn ClientY(&self) -> i32 {
self.client_y
}
pub fn CtrlKey(&self) -> bool {
self.ctrl_key
}
pub fn ShiftKey(&self) -> bool {
self.shift_key
}
pub fn AltKey(&self) -> bool {
self.alt_key
}
pub fn MetaKey(&self) -> bool {
self.meta_key
}
pub fn Button(&self) -> u16 {
self.button
}
pub fn Buttons(&self)-> u16 {
//TODO
0
}
pub fn GetRelatedTarget(&self) -> Option<@mut EventTarget> {
self.related_target
}
pub fn GetModifierState(&self, _keyArg: DOMString) -> bool {
//TODO
false
}
pub fn InitMouseEvent(&mut self,
typeArg: DOMString,
canBubbleArg: bool,
cancelableArg: bool,
viewArg: Option<@mut WindowProxy>,
detailArg: i32,
screenXArg: i32,
screenYArg: i32,
clientXArg: i32,
clientYArg: i32,
ctrlKeyArg: bool,
altKeyArg: bool,
shiftKeyArg: bool,
metaKeyArg: bool,
buttonArg: u16,
relatedTargetArg: Option<@mut EventTarget>,
_rv: &mut ErrorResult) {
self.parent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
self.screen_x = screenXArg;
self.screen_y = screenYArg;
self.client_x = clientXArg;
self.client_y = clientYArg;
self.ctrl_key = ctrlKeyArg;
self.alt_key = altKeyArg;
self.shift_key = shiftKeyArg;
self.meta_key = metaKeyArg;
self.button = buttonArg;
self.related_target = relatedTargetArg;
}
}
impl CacheableWrapper for MouseEvent {
fn get_wrappercache(&mut self) -> &mut WrapperCache {
return self.parent.get_wrappercache()
}
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
MouseEventBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for MouseEvent {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
self.parent.GetParentObject(cx)
}
}
impl DerivedWrapper for MouseEvent {
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
fail!(~"nyi")
}
fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
let obj = self.wrap_object_shared(cx, scope);
if obj.is_null() {
return 0;
} else {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(obj) };
return 1;
}
}
}

View file

@ -514,4 +514,13 @@ pub fn define_bindings(compartment: @mut Compartment) {
assert!(codegen::EventTargetBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
assert!(codegen::FormDataBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
assert!(codegen::MouseEventBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
assert!(codegen::UIEventBinding::DefineDOMInterface(compartment.cx.ptr,
compartment.global_obj.ptr,
&mut unused));
}

View file

@ -0,0 +1,158 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::codegen::UIEventBinding;
use dom::bindings::utils::{ErrorResult, DOMString};
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
use dom::node::{AbstractNode, ScriptView};
use dom::event::Event_;
use dom::window::Window;
use dom::windowproxy::WindowProxy;
use script_task::global_script_context;
use js::glue::RUST_OBJECT_TO_JSVAL;
use js::jsapi::{JSObject, JSContext, JSVal};
pub struct UIEvent {
parent: Event_,
can_bubble: bool,
cancelable: bool,
view: Option<@mut WindowProxy>,
detail: i32
}
impl UIEvent {
pub fn new(type_: DOMString, can_bubble: bool, cancelable: bool,
view: Option<@mut WindowProxy>, detail: i32) -> UIEvent {
UIEvent {
parent: Event_::new(type_),
can_bubble: can_bubble,
cancelable: cancelable,
view: view,
detail: detail
}
}
pub fn init_wrapper(@mut self) {
let script_context = global_script_context();
let cx = script_context.js_compartment.cx.ptr;
let owner = script_context.root_frame.get_ref().window;
let cache = owner.get_wrappercache();
let scope = cache.get_wrapper();
self.wrap_object_shared(cx, scope);
}
pub fn Constructor(_owner: @mut Window,
type_: DOMString,
init: &UIEventBinding::UIEventInit,
_rv: &mut ErrorResult) -> @mut UIEvent {
@mut UIEvent::new(type_, init.parent.bubbles, init.parent.cancelable,
init.view, init.detail)
}
pub fn GetView(&self) -> Option<@mut WindowProxy> {
self.view
}
pub fn Detail(&self) -> i32 {
self.detail
}
pub fn InitUIEvent(&mut self,
type_: DOMString,
can_bubble: bool,
cancelable: bool,
view: Option<@mut WindowProxy>,
detail: i32) {
let mut rv = Ok(());
self.parent.InitEvent(type_, can_bubble, cancelable, &mut rv);
self.can_bubble = can_bubble;
self.cancelable = cancelable;
self.view = view;
self.detail = detail;
}
pub fn LayerX(&self) -> i32 {
//TODO
0
}
pub fn LayerY(&self) -> i32 {
//TODO
0
}
pub fn PageX(&self) -> i32 {
//TODO
0
}
pub fn PageY(&self) -> i32 {
//TODO
0
}
pub fn Which(&self) -> u32 {
//TODO
0
}
pub fn GetRangeParent(&self) -> Option<AbstractNode<ScriptView>> {
//TODO
None
}
pub fn RangeOffset(&self) -> i32 {
//TODO
0
}
pub fn CancelBubble(&self) -> bool {
//TODO
false
}
pub fn SetCancelBubble(&mut self, _val: bool) {
//TODO
}
pub fn IsChar(&self) -> bool {
//TODO
false
}
}
impl CacheableWrapper for UIEvent {
fn get_wrappercache(&mut self) -> &mut WrapperCache {
return self.parent.get_wrappercache()
}
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
let mut unused = false;
UIEventBinding::Wrap(cx, scope, self, &mut unused)
}
}
impl BindingObject for UIEvent {
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
self.parent.GetParentObject(cx)
}
}
impl DerivedWrapper for UIEvent {
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
fail!(~"nyi")
}
fn wrap_shared(@mut self, cx: *JSContext, scope: *JSObject, vp: *mut JSVal) -> i32 {
let obj = self.wrap_object_shared(cx, scope);
if obj.is_null() {
return 0;
} else {
unsafe { *vp = RUST_OBJECT_TO_JSVAL(obj) };
return 1;
}
}
}

View file

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::utils::{CacheableWrapper, WrapperCache};
use script_task::global_script_context;
use js::jsapi::{JSContext, JSObject};
pub struct WindowProxy {
wrapper: WrapperCache
}
impl WindowProxy {
pub fn new() -> @mut WindowProxy {
@mut WindowProxy {
wrapper: WrapperCache::new()
}
}
pub fn init_wrapper(@mut self) {
let script_context = global_script_context();
let cx = script_context.js_compartment.cx.ptr;
let owner = script_context.root_frame.get_ref().window;
let cache = owner.get_wrappercache();
let scope = cache.get_wrapper();
self.wrap_object_shared(cx, scope);
}
}
impl CacheableWrapper for WindowProxy {
fn get_wrappercache(&mut self) -> &mut WrapperCache {
return self.get_wrappercache()
}
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
fail!("not yet implemented")
}
}

View file

@ -39,8 +39,10 @@ pub mod dom {
pub mod DOMParserBinding;
pub mod EventBinding;
pub mod EventTargetBinding;
pub mod HTMLCollectionBinding;
pub mod FormDataBinding;
pub mod HTMLCollectionBinding;
pub mod MouseEventBinding;
pub mod UIEventBinding;
}
}
pub mod blob;
@ -54,8 +56,11 @@ pub mod dom {
pub mod eventtarget;
pub mod formdata;
pub mod htmlcollection;
pub mod mouseevent;
pub mod node;
pub mod uievent;
pub mod window;
pub mod windowproxy;
}
pub mod html {

@ -1 +1 @@
Subproject commit 26dc2e896a57a28f03be43df46868e1a41a15807
Subproject commit 372622906d112ae28825be1d5fcd8737cd03ae58

View file

@ -57,3 +57,22 @@ window.alert(ev.type);
window.alert(ev.defaultPrevented);
ev.preventDefault();
window.alert(ev.defaultPrevented);
window.alert("MouseEvent:");
window.alert(MouseEvent);
let ev2 = new MouseEvent("press", {bubbles: true, screenX: 150, detail: 100});
window.alert(ev2);
window.alert(ev2.screenX);
window.alert(ev2.detail);
window.alert(ev2.getModifierState("ctrl"));
window.alert(ev2 instanceof Event);
window.alert(ev2 instanceof UIEvent);
//TODO: Doesn't work until we throw proper exceptions instead of returning 0 on
// unwrap failure.
/*try {
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(rects), "length").get.call(window);
window.alert("hmm?");
} catch (x) {
window.alert("ok");
}*/