aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom/bindings/proxyhandler.rs
blob: 3128c27d72762b098b430dc599475eb8918c267b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* 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::is_dom_proxy;
use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString, jschar};
use js::jsapi::{JS_GetPropertyDescriptorById, JS_NewUCString, JS_malloc, JS_free};
use js::jsapi::{JSBool, JS_DefinePropertyById, JS_NewObjectWithGivenProto};
use js::glue::{RUST_JSVAL_IS_VOID, RUST_JSVAL_TO_OBJECT, GetProxyExtra, RUST_OBJECT_TO_JSVAL};
use js::glue::{GetObjectProto, GetObjectParent, SetProxyExtra, GetProxyHandler};
use js::glue::InvokeGetOwnPropertyDescriptor;
use js::crust::{JS_StrictPropertyStub};
use js::{JSPROP_GETTER, JSPROP_ENUMERATE, JSPROP_READONLY, JSRESOLVE_QUALIFIED};

use std::cast;
use std::libc;
use std::ptr;
use std::str;
use std::sys::size_of;

type c_bool = libc::c_int;

static JSPROXYSLOT_EXPANDO: u32 = 0;

pub extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
                                set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
  unsafe {
    let handler = GetProxyHandler(proxy);
    if InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, set, desc) == 0 {
        return 0;
    }
    if (*desc).obj.is_not_null() {
        return 1;
    }

    //let proto = JS_GetPrototype(proxy);
    let proto = GetObjectProto(proxy);
    if proto.is_null() {
        (*desc).obj = ptr::null();
        return 1;
    }

    JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, cast::transmute(desc))
  }
}

pub extern fn defineProperty(cx: *JSContext, proxy: *JSObject, id: jsid,
                          desc: *JSPropertyDescriptor) -> JSBool {
    unsafe {
        if ((*desc).attrs & JSPROP_GETTER) != 0 && (*desc).setter == JS_StrictPropertyStub {
            /*return JS_ReportErrorFlagsAndNumber(cx,
            JSREPORT_WARNING | JSREPORT_STRICT |
            JSREPORT_STRICT_MODE_ERROR,
            js_GetErrorMessage, NULL,
            JSMSG_GETTER_ONLY);*/
            return 0;
        }

        let expando = EnsureExpandoObject(cx, proxy);
        if expando.is_null() {
            return 0;
        }

        return JS_DefinePropertyById(cx, expando, id, (*desc).value, (*desc).getter,
                                     (*desc).setter, (*desc).attrs);
    }
}

pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
  unsafe {
    let name = str::raw::from_c_str(className);
    let nchars = "[object ]".len() + name.len();
    let chars: *mut jschar = cast::transmute(JS_malloc(cx, (nchars + 1) as libc::size_t * (size_of::<jschar>() as libc::size_t)));
    if chars.is_null() {
        return ptr::null();
    }

    let result = ~"[object " + name + "]";
    for (i, c) in result.iter().enumerate() {
      *chars.offset(i as int) = c as jschar;
    }
    *chars.offset(nchars as int) = 0;
    let jsstr = JS_NewUCString(cx, cast::transmute(chars), nchars as libc::size_t);
    if jsstr.is_null() {
        JS_free(cx, cast::transmute(chars));
    }
    jsstr
  }
}

pub fn GetExpandoObject(obj: *JSObject) -> *JSObject {
    unsafe {
        assert!(is_dom_proxy(obj));
        let val = GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
        if RUST_JSVAL_IS_VOID(val) == 1 {
            ptr::null()
        } else {
            RUST_JSVAL_TO_OBJECT(val)
        }
    }
}

pub fn EnsureExpandoObject(cx: *JSContext, obj: *JSObject) -> *JSObject {
    unsafe {
        assert!(is_dom_proxy(obj));
        let mut expando = GetExpandoObject(obj);
        if expando.is_null() {
            expando = JS_NewObjectWithGivenProto(cx, ptr::null(), ptr::null(),
                                                 GetObjectParent(obj));
            if expando.is_null() {
                return ptr::null();
            }

            SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, RUST_OBJECT_TO_JSVAL(expando));
        }
        return expando;
    }
}

pub fn FillPropertyDescriptor(desc: &mut JSPropertyDescriptor, obj: *JSObject, readonly: bool) {
    desc.obj = obj;
    desc.attrs = if readonly { JSPROP_READONLY } else { 0 } | JSPROP_ENUMERATE;
    desc.getter = ptr::null();
    desc.setter = ptr::null();
    desc.shortid = 0;
}