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/. */
6 #ifndef mozilla_dom_DOMJSProxyHandler_h
7 #define mozilla_dom_DOMJSProxyHandler_h
9 #include "mozilla/Attributes.h"
10 #include "mozilla/Likely.h"
16 #define DOM_PROXY_OBJECT_SLOT js::PROXY_PRIVATE_SLOT
23 * DOM proxies have an extra slot for the expando object at index
24 * JSPROXYSLOT_EXPANDO.
26 * The expando object is a plain JSObject whose properties correspond to
27 * "expandos" (custom properties set by the script author).
29 * The exact value stored in the JSPROXYSLOT_EXPANDO slot depends on whether
30 * the interface is annotated with the [OverrideBuiltins] extended attribute.
32 * If it is, the proxy is initialized with a PrivateValue, which contains a
33 * pointer to a js::ExpandoAndGeneration object; this contains a pointer to
34 * the actual expando object as well as the "generation" of the object.
36 * If it is not, the proxy is initialized with an UndefinedValue. In
37 * EnsureExpandoObject, it is set to an ObjectValue that points to the
38 * expando object directly. (It is set back to an UndefinedValue only when
39 * the object is about to die.)
41 JSPROXYSLOT_EXPANDO
= 0
44 template<typename T
> struct Prefable
;
46 class BaseDOMProxyHandler
: public js::BaseProxyHandler
49 explicit MOZ_CONSTEXPR
BaseDOMProxyHandler(const void* aProxyFamily
, bool aHasPrototype
= false)
50 : js::BaseProxyHandler(aProxyFamily
, aHasPrototype
)
53 // Implementations of methods that can be implemented in terms of
54 // other lower-level methods.
55 bool getOwnPropertyDescriptor(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
57 JS::MutableHandle
<JSPropertyDescriptor
> desc
) const MOZ_OVERRIDE
;
58 virtual bool ownPropertyKeys(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
59 JS::AutoIdVector
&props
) const MOZ_OVERRIDE
;
61 bool getPropertyDescriptor(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
63 JS::MutableHandle
<JSPropertyDescriptor
> desc
) const MOZ_OVERRIDE
;
65 virtual bool enumerate(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
66 JS::MutableHandle
<JSObject
*> objp
) const MOZ_OVERRIDE
;
68 // We override getOwnEnumerablePropertyKeys() and implement it directly
69 // instead of using the default implementation, which would call
70 // ownPropertyKeys and then filter out the non-enumerable ones. This avoids
71 // unnecessary work during enumeration.
72 virtual bool getOwnEnumerablePropertyKeys(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
73 JS::AutoIdVector
&props
) const MOZ_OVERRIDE
;
75 bool watch(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
, JS::Handle
<jsid
> id
,
76 JS::Handle
<JSObject
*> callable
) const MOZ_OVERRIDE
;
77 bool unwatch(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
78 JS::Handle
<jsid
> id
) const MOZ_OVERRIDE
;
81 // Hook for subclasses to implement shared ownPropertyKeys()/keys()
82 // functionality. The "flags" argument is either JSITER_OWNONLY (for keys())
83 // or JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS (for
84 // ownPropertyKeys()).
85 virtual bool ownPropNames(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
87 JS::AutoIdVector
& props
) const = 0;
89 // Hook for subclasses to allow set() to ignore named props while other things
90 // that look at property descriptors see them. This is intentionally not
91 // named getOwnPropertyDescriptor to avoid subclasses that override it hiding
92 // our public getOwnPropertyDescriptor.
93 virtual bool getOwnPropDescriptor(JSContext
* cx
,
94 JS::Handle
<JSObject
*> proxy
,
96 bool ignoreNamedProps
,
97 JS::MutableHandle
<JSPropertyDescriptor
> desc
) const = 0;
100 class DOMProxyHandler
: public BaseDOMProxyHandler
103 MOZ_CONSTEXPR
DOMProxyHandler()
104 : BaseDOMProxyHandler(&family
)
107 bool defineProperty(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
, JS::Handle
<jsid
> id
,
108 JS::MutableHandle
<JSPropertyDescriptor
> desc
) const MOZ_OVERRIDE
111 return defineProperty(cx
, proxy
, id
, desc
, &unused
);
113 virtual bool defineProperty(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
, JS::Handle
<jsid
> id
,
114 JS::MutableHandle
<JSPropertyDescriptor
> desc
, bool* defined
)
116 bool delete_(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
,
117 JS::Handle
<jsid
> id
, bool* bp
) const MOZ_OVERRIDE
;
118 bool preventExtensions(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
,
119 bool *succeeded
) const MOZ_OVERRIDE
;
120 bool isExtensible(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
, bool *extensible
)
122 bool has(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
, JS::Handle
<jsid
> id
,
123 bool* bp
) const MOZ_OVERRIDE
;
124 bool set(JSContext
*cx
, JS::Handle
<JSObject
*> proxy
, JS::Handle
<JSObject
*> receiver
,
125 JS::Handle
<jsid
> id
, bool strict
, JS::MutableHandle
<JS::Value
> vp
)
129 * If assigning to proxy[id] hits a named setter with OverrideBuiltins or
130 * an indexed setter, call it and set *done to true on success. Otherwise, set
133 virtual bool setCustom(JSContext
* cx
, JS::Handle
<JSObject
*> proxy
, JS::Handle
<jsid
> id
,
134 JS::MutableHandle
<JS::Value
> vp
, bool *done
) const;
136 static JSObject
* GetExpandoObject(JSObject
* obj
);
138 /* GetAndClearExpandoObject does not DROP or clear the preserving wrapper flag. */
139 static JSObject
* GetAndClearExpandoObject(JSObject
* obj
);
140 static JSObject
* EnsureExpandoObject(JSContext
* cx
,
141 JS::Handle
<JSObject
*> obj
);
143 static const char family
;
146 inline bool IsDOMProxy(JSObject
*obj
)
148 const js::Class
* clasp
= js::GetObjectClass(obj
);
149 return clasp
->isProxy() &&
150 js::GetProxyHandler(obj
)->family() == &DOMProxyHandler::family
;
153 inline const DOMProxyHandler
*
154 GetDOMProxyHandler(JSObject
* obj
)
156 MOZ_ASSERT(IsDOMProxy(obj
));
157 return static_cast<const DOMProxyHandler
*>(js::GetProxyHandler(obj
));
160 extern jsid s_length_id
;
162 int32_t IdToInt32(JSContext
* cx
, JS::Handle
<jsid
> id
);
164 // XXXbz this should really return uint32_t, with the maximum value
165 // meaning "not an index"...
167 GetArrayIndexFromId(JSContext
* cx
, JS::Handle
<jsid
> id
)
169 if (MOZ_LIKELY(JSID_IS_INT(id
))) {
170 return JSID_TO_INT(id
);
172 if (MOZ_LIKELY(id
== s_length_id
)) {
175 if (MOZ_LIKELY(JSID_IS_ATOM(id
))) {
176 JSAtom
* atom
= JSID_TO_ATOM(id
);
179 JS::AutoCheckCannotGC nogc
;
180 if (js::AtomHasLatin1Chars(atom
)) {
181 s
= *js::GetLatin1AtomChars(nogc
, atom
);
183 s
= *js::GetTwoByteAtomChars(nogc
, atom
);
186 if (MOZ_LIKELY((unsigned)s
>= 'a' && (unsigned)s
<= 'z'))
190 JSLinearString
* str
= js::AtomToLinearString(JSID_TO_ATOM(id
));
191 return js::StringIsArrayIndex(str
, &i
) ? i
: -1;
193 return IdToInt32(cx
, id
);
197 IsArrayIndex(int32_t index
)
203 FillPropertyDescriptor(JS::MutableHandle
<JSPropertyDescriptor
> desc
,
204 JSObject
* obj
, bool readonly
, bool enumerable
= true)
206 desc
.object().set(obj
);
207 desc
.setAttributes((readonly
? JSPROP_READONLY
: 0) |
208 (enumerable
? JSPROP_ENUMERATE
: 0));
209 desc
.setGetter(nullptr);
210 desc
.setSetter(nullptr);
214 FillPropertyDescriptor(JS::MutableHandle
<JSPropertyDescriptor
> desc
,
215 JSObject
* obj
, JS::Value v
,
216 bool readonly
, bool enumerable
= true)
219 FillPropertyDescriptor(desc
, obj
, readonly
, enumerable
);
223 FillPropertyDescriptor(JS::MutableHandle
<JSPropertyDescriptor
> desc
,
224 JSObject
* obj
, unsigned attributes
, JS::Value v
)
226 desc
.object().set(obj
);
228 desc
.setAttributes(attributes
);
229 desc
.setGetter(nullptr);
230 desc
.setSetter(nullptr);
234 } // namespace mozilla
236 #endif /* mozilla_dom_DOMProxyHandler_h */