servo: Get a test the prints ClientRect.toString to work.
authorJosh Matthews <josh@joshmatthews.net>
Wed, 20 Feb 2013 01:22:11 -0500
changeset 380020 d8708357141350ead6311e9ae96be1507935ab01
parent 380019 3e31034c2a723da19b389925aa3330bd35cb563f
child 380021 0194a8665c46292fb94726773676372543d4af31
push id7198
push userjlorenzo@mozilla.com
push dateTue, 18 Apr 2017 12:07:49 +0000
treeherdermozilla-beta@d57aa49c3948 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
servo: Get a test the prints ClientRect.toString to work. Source-Repo: https://github.com/servo/servo Source-Revision: 3f527d8f8f99f3e9ae4a94efd98c7a8c9e430451
servo/src/servo/dom/bindings/codegen/CodegenRust.py
servo/src/servo/dom/bindings/utils.rs
servo/src/servo/dom/node.rs
servo/src/test/test_bindings.html
servo/src/test/test_bindings.js
--- a/servo/src/servo/dom/bindings/codegen/CodegenRust.py
+++ b/servo/src/servo/dom/bindings/codegen/CodegenRust.py
@@ -1068,27 +1068,28 @@ class CGAbstractMethod(CGThing):
 
     static should be True to generate a static method, which only has
     a definition.
 
     If templateArgs is not None it should be a list of strings containing
     template arguments, and the function will be templatized using those
     arguments.
     """
-    def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, extern=False, templateArgs=None):
+    def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, extern=False, pub=False, templateArgs=None):
         CGThing.__init__(self)
         self.descriptor = descriptor
         self.name = name
         self.returnType = returnType
         self.args = args
         self.inline = inline
         self.alwaysInline = alwaysInline
         self.static = static
         self.extern = extern
         self.templateArgs = templateArgs
+        self.pub = pub;
     def _argstring(self):
         return ', '.join([str(a) for a in self.args])
     def _template(self):
         if self.templateArgs is None:
             return ''
         return '<%s>\n' % ', '.join(self.templateArgs)
     def _decorators(self):
         decorators = []
@@ -1097,16 +1098,18 @@ class CGAbstractMethod(CGThing):
         elif self.inline:
             #decorators.append('inline')
             pass
         if self.extern:
             decorators.append('extern')
         if self.static:
             #decorators.append('static')
             pass
+        if self.pub:
+            decorators.append('pub')
         if not decorators:
             return ''
         #maybeNewline = " " if self.inline else "\n"
         maybeNewline = " "
         return ' '.join(decorators) + maybeNewline
     def _returnType(self):
         return (" -> %s" % self.returnType) if self.returnType != "void" else ""
     def declare(self):
@@ -1312,19 +1315,19 @@ class CGGetPerInterfaceObject(CGAbstract
 
   /* 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.
    */
 
   /* Make sure our global is sane.  Hopefully we can remove this sometime */
-  if ((*JS_GetClass(aGlobal)).flags & JSCLASS_DOM_GLOBAL) == 0 {
+  /*if ((*JS_GetClass(aGlobal)).flags & JSCLASS_DOM_GLOBAL) == 0 {
     return ptr::null();
-  }
+  }*/
   /* Check to see whether the interface objects are already installed */
   let protoOrIfaceArray: *mut *JSObject = cast::transmute(GetProtoOrIfaceArray(aGlobal));
   let cachedObject: *JSObject = *protoOrIfaceArray.offset(%s as uint);
   if cachedObject.is_null() {
     let tmp: *JSObject = CreateInterfaceObjects(aCx, aGlobal, aReceiver);
     *protoOrIfaceArray.offset(%s as uint) = tmp;
     tmp
   } else {
@@ -1387,17 +1390,17 @@ def CheckPref(descriptor, globalName, va
 class CGDefineDOMInterfaceMethod(CGAbstractMethod):
     """
     A method for resolve hooks to try to lazily define the interface object for
     a given interface.
     """
     def __init__(self, descriptor):
         args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aReceiver'),
                 Argument('*mut bool', 'aEnabled')]
-        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args)
+        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args, pub=True)
 
     def declare(self):
         if self.descriptor.workers:
             return ''
         #return CGAbstractMethod.declare(self)
         return ""
 
     def define(self):
--- a/servo/src/servo/dom/bindings/utils.rs
+++ b/servo/src/servo/dom/bindings/utils.rs
@@ -1,21 +1,22 @@
 use js;
 use js::rust::Compartment;
 use js::{JS_ARGV, JSCLASS_HAS_RESERVED_SLOTS, JSPROP_ENUMERATE, JSPROP_SHARED, JSVAL_NULL,
-         JS_THIS_OBJECT, JS_SET_RVAL, JSFUN_CONSTRUCTOR, JS_CALLEE};
+         JS_THIS_OBJECT, JS_SET_RVAL, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY,
+         JSPROP_PERMANENT};
 use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSFreeOp, JSNative,
                 JSFunctionSpec, JSPropertySpec, JSVal, JSString};
 use js::jsapi::bindgen::{JS_ValueToString, JS_GetStringCharsZAndLength, JS_ReportError,
                          JS_GetReservedSlot, JS_SetReservedSlot, JS_NewStringCopyN,
                          JS_DefineFunctions, JS_DefineProperty, JS_GetContextPrivate,
                          JS_GetClass, JS_GetPrototype, JS_LinkConstructorAndPrototype,
                          JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction,
                          JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject,
-                         JS_GetInternedStringCharsAndLength};
+                         JS_GetInternedStringCharsAndLength, JS_DefineProperties};
 use js::jsfriendapi::bindgen::{DefineFunctionWithReserved, GetObjectJSClass,
                                JS_NewObjectWithUniqueType};
 use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB,
                   RESOLVE_STUB};
 use js::glue::bindgen::*;
 use core::ptr::null;
 use core::cast;
 use content::content_task::{Content, task_from_context};
@@ -243,17 +244,17 @@ const DOM_OBJECT_SLOT: uint = 0;
 // NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
 // LSetDOMProperty. Those constants need to be changed accordingly if this value
 // changes.
 const DOM_PROTO_INSTANCE_CLASS_SLOT: u32 = 0;
 
 // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. We have to
 // start at 1 past JSCLASS_GLOBAL_SLOT_COUNT because XPConnect uses
 // that one.
-const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT + 1;
+pub const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT + 1;
 
 // NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
 // LSetDOMProperty. Those constants need to be changed accordingly if this value
 // changes.
 const JSCLASS_DOM_GLOBAL: u32 = js::JSCLASS_USERBIT1;
 
 pub struct NativeProperties {
     staticMethods: *JSFunctionSpec,
@@ -285,17 +286,17 @@ pub struct NativePropertyHooks {
 }
 
 pub struct JSNativeHolder {
     native: js::jsapi::JSNative,
     propertyHooks: *NativePropertyHooks
 }
 
 pub struct ConstantSpec {
-    name: &str,
+    name: *libc::c_char,
     value: JSVal
 }
 
 pub struct DOMClass {
     // A list of interfaces that this object implements, in order of decreasing
     // derivedness.
     interface_chain: [prototypes::id::Prototype * 1 /*prototypes::id::_ID_Count*/],
 
@@ -305,18 +306,18 @@ pub struct DOMClass {
 
 pub struct DOMJSClass {
     base: JSClass,
     dom_class: DOMClass
 }
 
 fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject {
     unsafe {
-        assert ((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0;
-        cast::reinterpret_cast(&JS_GetReservedSlot(global, DOM_PROTOTYPE_SLOT))
+        /*assert ((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0;*/
+        cast::transmute(RUST_JSVAL_TO_PRIVATE(JS_GetReservedSlot(global, DOM_PROTOTYPE_SLOT)))
     }
 }
 
 mod prototypes {
     mod id {
         pub enum Prototype {
             ClientRect,
             _ID_Count
@@ -392,18 +393,18 @@ fn CreateInterfaceObject(cx: *JSContext,
             JS_GetFunctionObject(fun)
         }
     };
 
     if constructor.is_null() {
         return ptr::null();
     }
 
-    if staticMethods.is_not_null() /*&&
-       !DefinePrefable(cx, constructor, staticMethods)*/ {
+    if staticMethods.is_not_null() &&
+       !DefineMethods(cx, constructor, staticMethods) {
         return ptr::null();
     }
 
     if constructorClass.is_not_null() {
         let toString = do str::as_c_str("toString") |s| {
             DefineFunctionWithReserved(cx, constructor, s,
                                        InterfaceObjectToString,
                                        0, 0)
@@ -418,18 +419,18 @@ fn CreateInterfaceObject(cx: *JSContext,
         let s = JS_InternString(cx, name);
         if s.is_null() {
             return ptr::null();
         }
         SetFunctionNativeReserved(toStringObj, TOSTRING_NAME_RESERVED_SLOT,
                                   &RUST_STRING_TO_JSVAL(s));
     }
 
-    if constants.is_not_null() /*&&
-       !DefinePrefable(cx, constructor, constants)*/ {
+    if constants.is_not_null() &&
+       !DefineConstants(cx, constructor, constants) {
         return ptr::null();
     }
 
     if proto.is_not_null() && JS_LinkConstructorAndPrototype(cx, constructor, proto) == 0 {
         return ptr::null();
     }
 
     let alreadyDefined = 0;
@@ -442,37 +443,76 @@ fn CreateInterfaceObject(cx: *JSContext,
                          ptr::null(), ptr::null(), 0) == 0 {
         return ptr::null();
     }
 
     return constructor;
   }
 }
 
+fn DefineConstants(cx: *JSContext, obj: *JSObject, constants: *ConstantSpec) -> bool {
+    let mut i = 0;
+    loop {
+        unsafe {
+            let spec = *constants.offset(i);
+            if spec.name.is_null() {
+                return true;
+            }
+            if JS_DefineProperty(cx, obj, spec.name,
+                                 spec.value, ptr::null(),
+                                 ptr::null(),
+                                 JSPROP_ENUMERATE | JSPROP_READONLY |
+                                 JSPROP_PERMANENT) == 0 {
+                return false;
+            }
+        }
+        i += 1;
+    }
+}
+
+fn DefineMethods(cx: *JSContext, obj: *JSObject, methods: *JSFunctionSpec) -> bool {
+    unsafe { JS_DefineFunctions(cx, obj, methods) != 0 }
+}
+
+fn DefineProperties(cx: *JSContext, obj: *JSObject, properties: *JSPropertySpec) -> bool {
+    unsafe { JS_DefineProperties(cx, obj, properties) != 0 }
+}
+
 fn CreateInterfacePrototypeObject(cx: *JSContext, global: *JSObject,
                                   parentProto: *JSObject, protoClass: *JSClass,
                                   methods: *JSFunctionSpec,
                                   properties: *JSPropertySpec,
                                   constants: *ConstantSpec) -> *JSObject {
     let ourProto = JS_NewObjectWithUniqueType(cx, protoClass, parentProto, global);
     if ourProto.is_null() {
         return ptr::null();
     }
 
-    if methods.is_not_null() /*&& !DefinePrefable(cx, ourProto, methods)*/ {
+    if methods.is_not_null() && !DefineMethods(cx, ourProto, methods) {
         return ptr::null();
     }
 
-    if properties.is_not_null() /*&& !DefinePrefable(cx, ourProto, properties)*/ {
+    if properties.is_not_null() && !DefineProperties(cx, ourProto, properties) {
         return ptr::null();
     }
 
-    if constants.is_not_null() /*&& !DefinePrefable(cx, ourProto, constants)*/ {
+    if constants.is_not_null() && !DefineConstants(cx, ourProto, constants) {
         return ptr::null();
     }
 
     return ourProto;
 }
 
 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 = @[0 as *JSObject, ..1]; //XXXjdm number of constructors
+    unsafe {
+        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));
+    }
 }
\ No newline at end of file
--- a/servo/src/servo/dom/node.rs
+++ b/servo/src/servo/dom/node.rs
@@ -10,16 +10,19 @@ use dom::window::Window;
 use layout::debug::DebugMethods;
 use layout::flow::FlowContext;
 use newcss::complete::CompleteSelectResults;
 
 use core::cast::transmute;
 use core::ptr::null;
 use geom::size::Size2D;
 use js::crust::*;
+use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
+use js::jsapi::{JSClass, JSObject, JSPropertySpec, JSContext, jsid, JSVal, JSBool};
+use js::jsapi::bindgen::JS_SetReservedSlot;
 use js::rust::Compartment;
 use std::arc::ARC;
 
 //
 // The basic Node structure
 //
 
 /// This is what a Node looks like if you do not know what kind of node it is. To unpack it, use
@@ -366,9 +369,14 @@ impl Node {
     }
 }
 
 pub fn define_bindings(compartment: @mut Compartment, doc: @Document, win: @Window) {
     bindings::window::init(compartment, win);
     bindings::document::init(compartment, doc);
     bindings::node::init(compartment);
     bindings::element::init(compartment);
+    bindings::utils::initialize_global(compartment.global_obj.ptr);
+    let unused = false;
+    assert bindings::ClientRectBinding::DefineDOMInterface(compartment.cx.ptr,
+                                                           compartment.global_obj.ptr,
+                                                           ptr::mut_addr_of(&unused));
 }
new file mode 100644
--- /dev/null
+++ b/servo/src/test/test_bindings.html
@@ -0,0 +1,1 @@
+<script src="test_bindings.js"></script>
new file mode 100644
--- /dev/null
+++ b/servo/src/test/test_bindings.js
@@ -0,0 +1,1 @@
+window.alert(ClientRect);