dom/bindings/DOMJSProxyHandler.h

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:fd342e6dfaf4
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef mozilla_dom_DOMJSProxyHandler_h
7 #define mozilla_dom_DOMJSProxyHandler_h
8
9 #include "mozilla/Attributes.h"
10 #include "mozilla/Likely.h"
11
12 #include "jsapi.h"
13 #include "jsproxy.h"
14 #include "nsString.h"
15
16 #define DOM_PROXY_OBJECT_SLOT js::PROXY_PRIVATE_SLOT
17
18 namespace mozilla {
19 namespace dom {
20
21 class DOMClass;
22
23 enum {
24 JSPROXYSLOT_EXPANDO = 0
25 };
26
27 template<typename T> struct Prefable;
28
29 // This variable exists solely to provide a unique address for use as an identifier.
30 extern const char HandlerFamily;
31 inline const void* ProxyFamily() { return &HandlerFamily; }
32
33 inline bool IsDOMProxy(JSObject *obj)
34 {
35 const js::Class* clasp = js::GetObjectClass(obj);
36 return clasp->isProxy() &&
37 js::GetProxyHandler(obj)->family() == ProxyFamily();
38 }
39
40 class BaseDOMProxyHandler : public js::BaseProxyHandler
41 {
42 public:
43 BaseDOMProxyHandler(const void* aProxyFamily)
44 : js::BaseProxyHandler(aProxyFamily)
45 {}
46
47 // Implementations of traps that can be implemented in terms of
48 // fundamental traps.
49 bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
50 JS::AutoIdVector& props) MOZ_OVERRIDE;
51 bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
52 JS::Handle<jsid> id,
53 JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
54 bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
55 JS::Handle<jsid> id,
56 JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
57
58 bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
59 JS::Handle<JSObject*> callable) MOZ_OVERRIDE;
60 bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
61 JS::Handle<jsid> id) MOZ_OVERRIDE;
62 virtual bool getOwnPropertyNames(JSContext* cx, JS::Handle<JSObject*> proxy,
63 JS::AutoIdVector &props) MOZ_OVERRIDE;
64 // We override keys() and implement it directly instead of using the
65 // default implementation, which would getOwnPropertyNames and then
66 // filter out the non-enumerable ones. This avoids doing
67 // unnecessary work during enumeration.
68 virtual bool keys(JSContext* cx, JS::Handle<JSObject*> proxy,
69 JS::AutoIdVector &props) MOZ_OVERRIDE;
70
71 protected:
72 // Hook for subclasses to implement shared getOwnPropertyNames()/keys()
73 // functionality. The "flags" argument is either JSITER_OWNONLY (for keys())
74 // or JSITER_OWNONLY | JSITER_HIDDEN (for getOwnPropertyNames()).
75 virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy,
76 unsigned flags,
77 JS::AutoIdVector& props) = 0;
78
79 // Hook for subclasses to allow set() to ignore named props while other things
80 // that look at property descriptors see them. This is intentionally not
81 // named getOwnPropertyDescriptor to avoid subclasses that override it hiding
82 // our public getOwnPropertyDescriptor.
83 virtual bool getOwnPropDescriptor(JSContext* cx,
84 JS::Handle<JSObject*> proxy,
85 JS::Handle<jsid> id,
86 bool ignoreNamedProps,
87 JS::MutableHandle<JSPropertyDescriptor> desc) = 0;
88 };
89
90 class DOMProxyHandler : public BaseDOMProxyHandler
91 {
92 public:
93 DOMProxyHandler()
94 : BaseDOMProxyHandler(ProxyFamily())
95 {
96 }
97
98 bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy) MOZ_OVERRIDE;
99 bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
100 JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE
101 {
102 bool unused;
103 return defineProperty(cx, proxy, id, desc, &unused);
104 }
105 virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
106 JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
107 bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
108 JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
109 bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
110 JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE;
111 bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE;
112 bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible) MOZ_OVERRIDE;
113
114 /*
115 * If assigning to proxy[id] hits a named setter with OverrideBuiltins or
116 * an indexed setter, call it and set *done to true on success. Otherwise, set
117 * *done to false.
118 */
119 virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
120 JS::MutableHandle<JS::Value> vp, bool *done);
121
122 static JSObject* GetExpandoObject(JSObject* obj)
123 {
124 MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
125 JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
126 if (v.isObject()) {
127 return &v.toObject();
128 }
129
130 if (v.isUndefined()) {
131 return nullptr;
132 }
133
134 js::ExpandoAndGeneration* expandoAndGeneration =
135 static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
136 v = expandoAndGeneration->expando;
137 return v.isUndefined() ? nullptr : &v.toObject();
138 }
139 /* GetAndClearExpandoObject does not DROP or clear the preserving wrapper flag. */
140 static JSObject* GetAndClearExpandoObject(JSObject* obj);
141 static JSObject* EnsureExpandoObject(JSContext* cx,
142 JS::Handle<JSObject*> obj);
143 };
144
145 inline DOMProxyHandler*
146 GetDOMProxyHandler(JSObject* obj)
147 {
148 MOZ_ASSERT(IsDOMProxy(obj));
149 return static_cast<DOMProxyHandler*>(js::GetProxyHandler(obj));
150 }
151
152 extern jsid s_length_id;
153
154 int32_t IdToInt32(JSContext* cx, JS::Handle<jsid> id);
155
156 // XXXbz this should really return uint32_t, with the maximum value
157 // meaning "not an index"...
158 inline int32_t
159 GetArrayIndexFromId(JSContext* cx, JS::Handle<jsid> id)
160 {
161 if (MOZ_LIKELY(JSID_IS_INT(id))) {
162 return JSID_TO_INT(id);
163 }
164 if (MOZ_LIKELY(id == s_length_id)) {
165 return -1;
166 }
167 if (MOZ_LIKELY(JSID_IS_ATOM(id))) {
168 JSAtom* atom = JSID_TO_ATOM(id);
169 jschar s = *js::GetAtomChars(atom);
170 if (MOZ_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z'))
171 return -1;
172
173 uint32_t i;
174 JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id));
175 return js::StringIsArrayIndex(str, &i) ? i : -1;
176 }
177 return IdToInt32(cx, id);
178 }
179
180 inline bool
181 IsArrayIndex(int32_t index)
182 {
183 return index >= 0;
184 }
185
186 inline void
187 FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc,
188 JSObject* obj, bool readonly, bool enumerable = true)
189 {
190 desc.object().set(obj);
191 desc.setAttributes((readonly ? JSPROP_READONLY : 0) |
192 (enumerable ? JSPROP_ENUMERATE : 0));
193 desc.setGetter(nullptr);
194 desc.setSetter(nullptr);
195 }
196
197 inline void
198 FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc,
199 JSObject* obj, JS::Value v,
200 bool readonly, bool enumerable = true)
201 {
202 desc.value().set(v);
203 FillPropertyDescriptor(desc, obj, readonly, enumerable);
204 }
205
206 inline void
207 FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc,
208 JSObject* obj, unsigned attributes, JS::Value v)
209 {
210 desc.object().set(obj);
211 desc.value().set(v);
212 desc.setAttributes(attributes);
213 desc.setGetter(nullptr);
214 desc.setSetter(nullptr);
215 }
216
217 } // namespace dom
218 } // namespace mozilla
219
220 #endif /* mozilla_dom_DOMProxyHandler_h */

mercurial