servo: Merge #573 - WebIDL setters, dictionary inheritance, fallible unwrapping, and more (from jdm:domevent); r=metajack
authorJosh Matthews <josh@joshmatthews.net>
Fri, 12 Jul 2013 08:45:33 -0700
changeset 333513 039b69ce1aba30adc75db0dc93bef69d43769429
parent 333512 85513b988f5d6d1c3f4f5ea0020b870c73d3599d
child 333514 5a5f406916660f4a32a1061f9369766ae14bc30e
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmetajack
servo: Merge #573 - WebIDL setters, dictionary inheritance, fallible unwrapping, and more (from jdm:domevent); r=metajack Source-Repo: https://github.com/servo/servo Source-Revision: 0c4119b4966fa8bd24637576f654d13484009ee3
servo/src/components/script/dom/bindings/codegen/Bindings.conf
servo/src/components/script/dom/bindings/codegen/CodegenRust.py
servo/src/components/script/dom/bindings/codegen/Event.webidl
servo/src/components/script/dom/bindings/codegen/MouseEvent.webidl
servo/src/components/script/dom/bindings/codegen/RegisterBindings.cpp
servo/src/components/script/dom/bindings/codegen/UIEvent.webidl
servo/src/components/script/dom/bindings/codegen/parser/WebIDL.py
servo/src/components/script/dom/bindings/conversions.rs
servo/src/components/script/dom/bindings/utils.rs
servo/src/components/script/dom/mouseevent.rs
servo/src/components/script/dom/node.rs
servo/src/components/script/dom/uievent.rs
servo/src/components/script/dom/windowproxy.rs
servo/src/components/script/script.rc
servo/src/test/html/test_bindings.js
--- a/servo/src/components/script/dom/bindings/codegen/Bindings.conf
+++ b/servo/src/components/script/dom/bindings/codegen/Bindings.conf
@@ -251,16 +251,19 @@ DOMInterfaces = {
 {
     'nativeType': 'nsIChannel',
     'notflattened': True
 },
 {
     'workers': True,
 }],
 
+'MouseEvent': {
+},
+
 'NodeList': [
 {
     'nativeType': 'nsINodeList',
     'prefable': True,
     'resultNotAddRefed': [ 'item' ]
 }],
 
 'PaintRequestList': [
@@ -328,16 +331,19 @@ DOMInterfaces = {
 'SVGTransformList': [
 {
     'nativeType': 'mozilla::DOMSVGTransformList',
     'headerFile': 'DOMSVGTransformList.h',
     'prefable': True,
     'resultNotAddRefed': [ 'getItem' ]
 }],
 
+'UIEvent': {
+},
+
 'WebGLRenderingContext': {
   'nativeType': 'mozilla::WebGLContext',
   'headerFile': 'WebGLContext.h',
   'resultNotAddRefed': [ 'canvas', 'getContextAttributes', 'getExtension',
                          'getAttachedShaders' ],
   'implicitJSContext': [ 'texImage2D', 'texSubImage2D' ],
 },
 
@@ -494,17 +500,17 @@ def addExternalIface(iface, nativeType=N
         domInterface['headerFile'] = headerFile
     if not pointerType is None:
         domInterface['pointerType'] = pointerType
     DOMInterfaces[iface] = domInterface
 
 # 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')
 
 addExternalHTMLElement('HTMLCanvasElement')
 addExternalHTMLElement('HTMLImageElement')
 addExternalHTMLElement('HTMLOptionElement')
 addExternalHTMLElement('HTMLOptGroupElement')
 addExternalHTMLElement('HTMLVideoElement')
@@ -515,17 +521,17 @@ addExternalIface('CSSValue')
 addExternalIface('Document', nativeType='Document', pointerType='@mut ')
 addExternalIface('DOMStringList', nativeType='nsDOMStringList',
                  headerFile='nsDOMLists.h')
 addExternalIface('Element', nativeType='AbstractNode<ScriptView>', pointerType='')
 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')
 addExternalIface('SVGNumber')
 addExternalIface('SVGPathSeg')
 addExternalIface('SVGPoint')
 addExternalIface('SVGTransform')
 addExternalIface('TextMetrics', headerFile='nsIDOMCanvasRenderingContext2D.h')
@@ -547,9 +553,10 @@ addExternalIface('WebGLRenderbuffer', na
 addExternalIface('WebGLShader', nativeType='mozilla::WebGLShader',
                  headerFile='WebGLContext.h')
 addExternalIface('WebGLShaderPrecisionFormat',
                  nativeType='mozilla::WebGLShaderPrecisionFormat',
                  headerFile='WebGLContext.h')
 addExternalIface('WebGLTexture', nativeType='mozilla::WebGLTexture',
                  headerFile='WebGLContext.h')
 addExternalIface('Window')
+addExternalIface('WindowProxy', nativeType='WindowProxy')
 addExternalIface('XULElement')
--- a/servo/src/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/servo/src/components/script/dom/bindings/codegen/CodegenRust.py
@@ -19,26 +19,31 @@ TRACE_HOOK_NAME = '_trace'
 CONSTRUCT_HOOK_NAME = '_constructor'
 HASINSTANCE_HOOK_NAME = '_hasInstance'
 
 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
-
-    if newContents == oldFileContents:
-        return False
+    #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.
+
+    #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)
     f.close()
 
     return True
 
 def toStringBool(arg):
@@ -86,16 +91,18 @@ class CastableObjectUnwrapper():
     called by the name in the "target" argument.
 
     codeOnFailure is the code to run if unwrapping fails.
     """
     def __init__(self, descriptor, source, target, codeOnFailure):
         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,
                               "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define() }
         if descriptor.hasXPConnectImpls:
             # We don't use xpc_qsUnwrapThis because it will always throw on
             # unwrap failure, whereas we want to control whether we throw or
             # not.
@@ -110,32 +117,38 @@ class CastableObjectUnwrapper():
                 "// We should be castable!\n"
                 "MOZ_ASSERT(!objRef.ptr);\n"
                 "// We should have an object, too!\n"
                 "MOZ_ASSERT(objPtr);\n"
                 "${target} = objPtr;").substitute(self.substitution)), 4).define()
 
     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)) {
 #${codeOnFailure}
 #  }
 #}""").substitute(self.substitution)
 
 class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
     """
     As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
     """
     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():
     """
     Abstract base class for things that spit out code.
     """
     def __init__(self):
         pass # Nothing for now
@@ -389,16 +402,20 @@ class CGMethodCall(CGThing):
 class FakeCastableDescriptor():
     def __init__(self, descriptor):
         self.castable = True
         self.workers = descriptor.workers
         self.nativeType = descriptor.nativeType
         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
                 dictionary.members) or
             (dictionary.parent and
              dictionaryHasSequenceMember(dictionary.parent)))
 
 def typeIsSequenceOrHasSequenceMember(type):
@@ -538,17 +555,17 @@ def getJSToNativeConversionTemplate(type
         if not isDefinitelyObject:
             # Handle the non-object cases by wrapping up the whole
             # thing in an if cascade.
             templateBody = (
                 "if JSVAL_IS_OBJECT(${val}) {\n" +
                 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" +
                 CGIndenter(onFailureNotAnObject(failureCode)).define() +
                 "}")
             if type.nullable():
                 templateBody = handleDefaultNull(templateBody, codeToSetNull)
             else:
@@ -873,36 +890,30 @@ for (uint32_t i = 0; i < length; ++i) {
         argIsPointer = type.nullable() or type.unroll().inner.isExternal()
 
         # Sequences and non-worker callbacks have to hold a strong ref to the
         # thing being passed down.
         forceOwningType = (descriptor.interface.isCallback() and
                            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
         #    tuple.
         #  - holderType is the type we want to return as the third element
         #    of our tuple.
 
         # Set up some sensible defaults for these things insofar as we can.
         holderType = None
         if argIsPointer:
-            if forceOwningType:
-                declType = "nsRefPtr<" + typeName + ">"
-            else:
-                declType = typePtr
+            declType = "Option<" + typePtr + ">"
         else:
-            if forceOwningType:
-                declType = "OwningNonNull<" + typeName + ">"
-            else:
-                declType = descriptor.pointerType + typeName
+            declType = typePtr
 
         templateBody = ""
         if descriptor.castable:
             if descriptor.prefable:
                 raise TypeError("We don't support prefable castable object "
                                 "arguments (like %s), because we don't know "
                                 "how to handle them being preffed off" %
                                 descriptor.interface.identifier.name)
@@ -926,51 +937,29 @@ for (uint32_t i = 0; i < length; ++i) {
             templateBody += str(CallbackObjectUnwrapper(
                     descriptor,
                     "&${val}.toObject()",
                     "${declName}",
                     codeOnFailure=failureCode))
         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")
-
-            # And store our tmp, before it goes out of scope.
-            templateBody += "${declName} = tmp;"
+            templateBody += (
+                "  }\n"
+                "  Ok(unwrapped) => ${declName} = Some(unwrapped)\n"
+                "}\n")
 
         templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
-                                          type, "${declName} = NULL",
+                                          type, "${declName} = None",
                                           failureCode)
 
         declType = CGGeneric(declType)
         if holderType is not None:
             holderType = CGGeneric(holderType)
         return (templateBody, declType, holderType, isOptional, None)
 
     if type.isSpiderMonkeyInterface():
@@ -1300,20 +1289,25 @@ def instantiateJSToNativeConversionTempl
     originalHolderName = replacements["holderName"]
     if holderType is not None:
         if dealWithOptional:
             replacements["holderName"] = (
                 "const_cast< %s & >(%s.Value())" %
                 (holderType.define(), originalHolderName))
             mutableHolderType = CGWrapper(holderType, pre="Optional< ", post=" >")
             holderType = CGWrapper(mutableHolderType, pre="const ")
-        result.append(
-            CGList([holderType, CGGeneric(" "),
-                    CGGeneric(originalHolderName),
-                    CGGeneric(";")]))
+        tmpresult = [CGGeneric("let "),
+                     CGGeneric(originalHolderName),
+                     CGGeneric(": "),
+                     holderType]
+        if initialValue:
+            tmpresult += [CGGeneric(" = "),
+                          initialValue]
+        tmpresult += [CGGeneric(";")]
+        result.append(CGList(tmpresult))
 
     originalDeclName = replacements["declName"]
     if declType is not None:
         if dealWithOptional:
             replacements["declName"] = (
                 "const_cast< %s & >(%s.Value())" %
                 (declType.define(), originalDeclName))
             mutableDeclType = CGWrapper(declType, pre="Optional< ", post=" >")
@@ -2068,17 +2062,17 @@ class CGNativePropertyHooks(CGThing):
             resolveOwnProperty = "ResolveOwnProperty"
             enumerateOwnProperties = "EnumerateOwnProperties"
         else:
             enumerateOwnProperties = resolveOwnProperty = "0 as *u8"
         parent = self.descriptor.interface.parent
         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
 # don't want to indent empty lines.  So only indent lines that have a
 # non-newline character on them.
 lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
 class CGIndenter(CGThing):
     """
@@ -2724,21 +2718,21 @@ class CGCreateInterfaceObjectsMethod(CGA
         #return CGIndenter(CGWrapper(functionBody, pre="/*", post="*/return ptr::null()")).define()
         return CGIndenter(functionBody).define()
 
 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 """
 
   /* aGlobal and aReceiver are usually the same, but they can be different
      too. For example a sandbox often has an xray wrapper for a window as the
      prototype of the sandbox's global. In that case aReceiver is the xray
      wrapper and aGlobal is the sandbox's global.
@@ -2760,17 +2754,17 @@ class CGGetPerInterfaceObject(CGAbstract
   }""" % (self.id, self.id)
 
 class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
     """
     A method for getting the interface prototype object.
     """
     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
      object as needed. */""" + CGGetPerInterfaceObject.definition_body(self)
 
 class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
     """
     A method for getting the interface constructor object.
@@ -2841,17 +2835,17 @@ class CGDefineDOMInterfaceMethod(CGAbstr
     //regexp_toShared: ptr::null(),
     defaultValue: ptr::null(),
     iteratorNext: ptr::null(),
     finalize: ptr::null(),
     getElementIfPresent: ptr::null(),
     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:
             body += """  (*script_context).dom_static.attribute_ids.insert(prototypes::id::%s as uint,
                                              vec::cast_to_mut(vec::from_slice(sAttributes_ids)));
 """ % self.descriptor.name
             body = "" #XXXjdm xray stuff isn't necessary yet
 
@@ -3102,29 +3096,48 @@ class FakeArgument():
         self.optional = False
         self.variadic = False
         self.defaultValue = None
         self.treatNullAs = interfaceMember.treatNullAs
         self.treatUndefinedAs = interfaceMember.treatUndefinedAs
         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
     setters.  This will generate the function declaration and unwrap the
     |this| object.  Subclasses are expected to override the generate_code
     function to do the rest of the work.  This function should return a
     CGThing which is already properly indented.
     """
     def __init__(self, descriptor, name, args, unwrapFailureCode=None):
         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
 
     def definition_body(self):
         # Our descriptor might claim that we're not castable, simply because
         # we're someone's consequential interface.  But for this-unwrapping, we
         # know that we're the real deal.  So fake a descriptor here for
@@ -3133,17 +3146,17 @@ class CGAbstractBindingMethod(CGAbstract
             str(CastableObjectUnwrapper(
                         FakeCastableDescriptor(self.descriptor),
                         "obj", "this", self.unwrapFailureCode))))
         return CGList([ self.getThis(), unwrapThis,
                         self.generate_code() ], "\n").define()
 
     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"
                       "\n"
                       "let this: *rust_box<%s>;" % self.descriptor.nativeType))
 
     def generate_code(self):
         assert(False) # Override me
@@ -3243,16 +3256,66 @@ class CGSpecializedGetter(CGAbstractExte
                       self.descriptor.getExtendedAttributes(self.attr,
                                                             getter=True))
         if resultOutParam or self.attr.type.nullable() or not infallible:
             nativeName = "Get" + nativeName
         return CGWrapper(CGIndenter(CGGetterCall(self.attr.type, nativeName,
                                                  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
     JS for the given attribute. Apart from isCreator, all the defaults are used,
     since the fallbility does not change based on the boolean values,
     and the template will be discarded.
 
     CURRENT ASSUMPTIONS:
@@ -3781,27 +3844,27 @@ class CGDescriptor(CGThing):
                     hasMethod = True
                 elif m.isAttr():
                     cgThings.append(CGSpecializedGetter(descriptor, m))
                     if m.hasLenientThis():
                         hasLenientGetter = True
                     else:
                         hasGetter = True
                     if not m.readonly:
-                        #cgThings.append(CGSpecializedSetter(descriptor, m))
+                        cgThings.append(CGSpecializedSetter(descriptor, m))
                         if m.hasLenientThis():
                             hasLenientSetter = True
                         else:
                             hasSetter = True
                     cgThings.append(CGMemberJITInfo(descriptor, m))
             if hasMethod: cgThings.append(CGGenericMethod(descriptor))
             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))
 
         if descriptor.concrete and not descriptor.proxy:
             if not descriptor.workers and descriptor.wrapperCache:
                 #cgThings.append(CGAddPropertyHook(descriptor))
                 pass
 
@@ -3921,126 +3984,138 @@ class CGDictionary(CGThing):
                 raise err
             self.generatable = False
 
     def declare(self):
         if not self.generatable:
             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," %
                        (m[0].identifier.name, self.getMemberType(m))
                        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 " +
                           self.makeIdName(m.identifier.name) + ";" for
                           m in d.members) + "\n"
                 "}").substitute( { "selfName": self.makeClassName(d),
                                     "inheritance": inheritance }))
 
     def define(self):
         if not self.generatable:
             return ""
         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))
                   for m in d.members]
         idinit = CGList(idinit, " ||\n")
         idinit = CGWrapper(idinit, pre="if (",
                            post=(") {\n"
                                  "  return false;\n"
                                  "}"),
                            reindent=True)
 
         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
 
         return string.Template(
             # NOTE: jsids are per-runtime, so don't use them in workers
             ("static initedIds: bool = false;\n" +
              "\n".join("static %s: jsid = JSID_VOID;" %
                        self.makeIdName(m.identifier.name)
                        for m in d.members) + "\n"
              "\n"
              "impl ${selfName} {\n"
-             "fn new() -> ${selfName} {\n"
-             "  ${selfName} {\n" +
-             "\n".join("    %s: %s," % (m[0].identifier.name, defaultValue(self.getMemberType(m))) for m in self.memberInfo) + "\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"
-             "  //MOZ_ASSERT(!initedIds);\n"
-             "/*${idInit}\n"
-             "  initedIds = true;*/ //XXXjdm\n"
-             "  return true;\n"
-             "}\n"
+             "  pub fn InitIds(&mut self, cx: *JSContext) -> bool {\n"
+             "    //MOZ_ASSERT(!initedIds);\n"
+             "  /*${idInit}\n"
+             "    initedIds = true;*/ //XXXjdm\n"
+             "    return true;\n"
+             "  }\n"
              "\n" if not self.workers else "") +
-            "fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool\n"
-            "{\n"
-            "  unsafe {\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"
-             "    return 0;\n"
-             "  }\n" if not self.workers else "") +
+            ("      if (!initedIds && !self.InitIds(cx)) {\n"
+             "        return 0;\n"
+             "      }\n" if not self.workers else "") +
             "${initParent}"
-            "  let mut found: JSBool = 0;\n"
-            "  let temp: JSVal = JSVAL_NULL;\n"
-            "  let isNull = RUST_JSVAL_IS_NULL(val) != 0 || RUST_JSVAL_IS_VOID(val) != 0;\n"
-            "  if !isNull && RUST_JSVAL_IS_PRIMITIVE(val) != 0 {\n"
-            "    return 0; //XXXjdm throw properly here\n"
-            "    //return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
-            "  }\n"
+            "      let mut found: JSBool = 0;\n"
+            "      let temp: JSVal = JSVAL_NULL;\n"
+            "      let isNull = RUST_JSVAL_IS_NULL(val) != 0 || RUST_JSVAL_IS_VOID(val) != 0;\n"
+            "      if !isNull && RUST_JSVAL_IS_PRIMITIVE(val) != 0 {\n"
+            "        return 0; //XXXjdm throw properly here\n"
+            "        //return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
+            "      }\n"
             "\n"
             "${initMembers}\n"
-            "  return 1;\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)
                 })
 
     @staticmethod
     def makeDictionaryName(dictionary, workers):
         suffix = "Workers" if workers else ""
         return dictionary.identifier.name + suffix
 
     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
         # We can't handle having a holderType here
         assert holderType is None
         if dealWithOptional:
             declType = CGWrapper(declType, pre="Optional< ", post=" >")
         return declType.define()
@@ -4204,16 +4279,20 @@ class CGBindingRoot(CGThing):
                           'dom::clientrect::*', #XXXjdm
                           'dom::clientrectlist::*', #XXXjdm
                           'dom::htmlcollection::*', #XXXjdm
                           'dom::bindings::proxyhandler::*',
                           'dom::domparser::*', #XXXjdm
                           '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',
                           'std::cast',
                           'std::libc',
                           'std::ptr',
                           'std::vec',
                           'std::str',
--- a/servo/src/components/script/dom/bindings/codegen/Event.webidl
+++ b/servo/src/components/script/dom/bindings/codegen/Event.webidl
@@ -1,8 +1,20 @@
+/* -*- 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;
   readonly attribute EventTarget? target;
   readonly attribute EventTarget? currentTarget;
 
   const unsigned short NONE = 0;
   const unsigned short CAPTURING_PHASE = 1;
new file mode 100644
--- /dev/null
+++ b/servo/src/components/script/dom/bindings/codegen/MouseEvent.webidl
@@ -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;
+};
deleted file mode 100644
--- a/servo/src/components/script/dom/bindings/codegen/RegisterBindings.cpp
+++ /dev/null
@@ -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
-
new file mode 100644
--- /dev/null
+++ b/servo/src/components/script/dom/bindings/codegen/UIEvent.webidl
@@ -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;
+};
--- a/servo/src/components/script/dom/bindings/codegen/parser/WebIDL.py
+++ b/servo/src/components/script/dom/bindings/codegen/parser/WebIDL.py
@@ -424,34 +424,42 @@ class IDLExternalInterface(IDLObjectWith
 
     def addExtendedAttributes(self, attrs):
         assert len(attrs) == 0
 
     def resolve(self, parentScope):
         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)
-
-        self.parent = parent
+        assert not isPartial or not 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.
         self.interfacesBasedOnSelf = set([self])
 
         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
 
     def ctor(self):
         identifier = IDLUnresolvedIdentifier(self.location, "constructor",
                                              allowForbidden=True)
         try:
             return self._lookupIdentifier(identifier)
@@ -477,16 +485,21 @@ class IDLInterface(IDLObjectWithScope):
         return retval
 
     def finish(self, scope):
         if self._finished:
             return
 
         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):
             raise WebIDLError("%s inherits from %s which does not have "
                               "a definition" %
                               (self.identifier.name,
                                self.parent.identifier.name),
                               [self.location])
@@ -744,16 +757,31 @@ class IDLInterface(IDLObjectWithScope):
             loopPoint = iface.findInterfaceLoopPoint(otherInterface)
             if loopPoint:
                 return loopPoint
         return None
 
     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)
         assert isinstance(name, IDLUnresolvedIdentifier)
         assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
 
         self.parent = parent
         self._finished = False
@@ -2737,19 +2765,35 @@ class Parser(Tokenizer):
         p[0] = p[1]
 
     def p_Interface(self, p):
         """
             Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
         """
         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):
         """
             Interface : INTERFACE IDENTIFIER SEMICOLON
         """
         location = self.getLocation(p, 1)
         identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
 
@@ -2761,16 +2805,39 @@ class Parser(Tokenizer):
             pass
 
         p[0] = IDLExternalInterface(location, self.globalScope(), identifier)
 
     def p_PartialInterface(self, p):
         """
             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):
         """
             Inheritance : COLON ScopedName
         """
         p[0] = IDLIdentifierPlaceholder(self.getLocation(p, 2), p[2])
 
--- a/servo/src/components/script/dom/bindings/conversions.rs
+++ b/servo/src/components/script/dom/bindings/conversions.rs
@@ -20,16 +20,44 @@ impl JSValConvertible for u32 {
 
     fn from_jsval(val: JSVal) -> Option<u32> {
         unsafe {
             Some(RUST_JSVAL_TO_INT(val) as 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 {
             JSVAL_TRUE
         } else {
             JSVAL_FALSE
         }
     }
--- a/servo/src/components/script/dom/bindings/utils.rs
+++ b/servo/src/components/script/dom/bindings/utils.rs
@@ -12,16 +12,17 @@ use std::libc;
 use std::ptr;
 use std::ptr::{null, to_unsafe_ptr};
 use std::result;
 use std::str;
 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};
 use js::jsapi::{JS_EncodeString, JS_free, JS_GetStringCharsAndLength};
 use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype};
 use js::jsapi::{JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject};
 use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
 use js::jsapi::{JS_NewStringCopyN, JS_DefineFunctions, JS_DefineProperty};
@@ -112,26 +113,72 @@ pub struct rust_box<T> {
 }
 
 fn is_dom_class(clasp: *JSClass) -> bool {
     unsafe {
         ((*clasp).flags & js::JSCLASS_IS_DOMJSCLASS) != 0
     }
 }
 
+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);
     y
 }
 
 //XXX very incomplete
 pub fn jsval_to_str(cx: *JSContext, v: JSVal) -> Result<~str, ()> {
@@ -348,17 +395,17 @@ pub enum ConstantVal {
 pub struct ConstantSpec {
     name: *libc::c_char,
     value: ConstantVal
 }
 
 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
 }
 
 pub struct DOMJSClass {
     base: JSClass,
     dom_class: DOMClass
@@ -368,24 +415,29 @@ pub fn GetProtoOrIfaceArray(global: *JSO
     unsafe {
         /*assert ((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0;*/
         cast::transmute(RUST_JSVAL_TO_PRIVATE(JS_GetReservedSlot(global, DOM_PROTOTYPE_SLOT)))
     }
 }
 
 pub mod prototypes {
     pub mod id {
+        #[deriving(Eq)]
         pub enum Prototype {
+            Blob,
             ClientRect,
             ClientRectList,
             DOMParser,
             HTMLCollection,
             Event,
             EventTarget,
             FormData,
+            UIEvent,
+            MouseEvent,
+            WindowProxy,
             _ID_Count
         }
     }
 }
 
 pub fn CreateInterfaceObjects2(cx: *JSContext, global: *JSObject, receiver: *JSObject,
                                protoProto: *JSObject, protoClass: *JSClass,
                                constructorClass: *JSClass, constructor: JSNative,
@@ -578,17 +630,17 @@ fn CreateInterfacePrototypeObject(cx: *J
 }
 
 pub extern fn ThrowingConstructor(_cx: *JSContext, _argc: uint, _vp: *JSVal) -> JSBool {
     //XXX should trigger exception here
     return 0;
 }
 
 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);
         let inner = ptr::to_unsafe_ptr(&(*box).payload);
         JS_SetReservedSlot(global,
                            DOM_PROTOTYPE_SLOT,
                            RUST_PRIVATE_TO_JSVAL(inner as *libc::c_void));
     }
new file mode 100644
--- /dev/null
+++ b/servo/src/components/script/dom/mouseevent.rs
@@ -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;
+        }
+    }
+
+}
\ No newline at end of file
--- a/servo/src/components/script/dom/node.rs
+++ b/servo/src/components/script/dom/node.rs
@@ -509,9 +509,18 @@ pub fn define_bindings(compartment: @mut
                                                           compartment.global_obj.ptr,
                                                           &mut unused));
     assert!(codegen::EventBinding::DefineDOMInterface(compartment.cx.ptr,
                                                       compartment.global_obj.ptr,
                                                       &mut unused));
     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));
 }
new file mode 100644
--- /dev/null
+++ b/servo/src/components/script/dom/uievent.rs
@@ -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;
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/src/components/script/dom/windowproxy.rs
@@ -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")
+    }
+}
--- a/servo/src/components/script/script.rc
+++ b/servo/src/components/script/script.rc
@@ -34,33 +34,38 @@ pub mod dom {
         pub mod proxyhandler;
         pub mod domparser;
         pub mod codegen {
             pub mod ClientRectBinding;
             pub mod ClientRectListBinding;
             pub mod DOMParserBinding;
             pub mod EventBinding;
             pub mod EventTargetBinding;
+            pub mod FormDataBinding;
             pub mod HTMLCollectionBinding;
-            pub mod FormDataBinding;
+            pub mod MouseEventBinding;
+            pub mod UIEventBinding;
         }
     }
     pub mod blob;
     pub mod characterdata;
     pub mod clientrect;
     pub mod clientrectlist;
     pub mod document;
     pub mod domparser;
     pub mod element;
     pub mod event;
     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 {
     pub mod cssparse;
     pub mod hubbub_html_parser;
 }
 
 pub mod layout_interface;
--- a/servo/src/test/html/test_bindings.js
+++ b/servo/src/test/html/test_bindings.js
@@ -51,9 +51,28 @@ window.alert(parser);
 //window.alert(parser.parseFromString("<html></html>", "text/html"));
 
 window.alert("Event:");
 window.alert(Event);
 let ev = new Event("foopy");
 window.alert(ev.type);
 window.alert(ev.defaultPrevented);
 ev.preventDefault();
-window.alert(ev.defaultPrevented);
\ No newline at end of file
+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");
+}*/