1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bindings/DOMJSProxyHandler.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,220 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef mozilla_dom_DOMJSProxyHandler_h 1.10 +#define mozilla_dom_DOMJSProxyHandler_h 1.11 + 1.12 +#include "mozilla/Attributes.h" 1.13 +#include "mozilla/Likely.h" 1.14 + 1.15 +#include "jsapi.h" 1.16 +#include "jsproxy.h" 1.17 +#include "nsString.h" 1.18 + 1.19 +#define DOM_PROXY_OBJECT_SLOT js::PROXY_PRIVATE_SLOT 1.20 + 1.21 +namespace mozilla { 1.22 +namespace dom { 1.23 + 1.24 +class DOMClass; 1.25 + 1.26 +enum { 1.27 + JSPROXYSLOT_EXPANDO = 0 1.28 +}; 1.29 + 1.30 +template<typename T> struct Prefable; 1.31 + 1.32 +// This variable exists solely to provide a unique address for use as an identifier. 1.33 +extern const char HandlerFamily; 1.34 +inline const void* ProxyFamily() { return &HandlerFamily; } 1.35 + 1.36 +inline bool IsDOMProxy(JSObject *obj) 1.37 +{ 1.38 + const js::Class* clasp = js::GetObjectClass(obj); 1.39 + return clasp->isProxy() && 1.40 + js::GetProxyHandler(obj)->family() == ProxyFamily(); 1.41 +} 1.42 + 1.43 +class BaseDOMProxyHandler : public js::BaseProxyHandler 1.44 +{ 1.45 +public: 1.46 + BaseDOMProxyHandler(const void* aProxyFamily) 1.47 + : js::BaseProxyHandler(aProxyFamily) 1.48 + {} 1.49 + 1.50 + // Implementations of traps that can be implemented in terms of 1.51 + // fundamental traps. 1.52 + bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy, 1.53 + JS::AutoIdVector& props) MOZ_OVERRIDE; 1.54 + bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, 1.55 + JS::Handle<jsid> id, 1.56 + JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE; 1.57 + bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, 1.58 + JS::Handle<jsid> id, 1.59 + JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE; 1.60 + 1.61 + bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, 1.62 + JS::Handle<JSObject*> callable) MOZ_OVERRIDE; 1.63 + bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, 1.64 + JS::Handle<jsid> id) MOZ_OVERRIDE; 1.65 + virtual bool getOwnPropertyNames(JSContext* cx, JS::Handle<JSObject*> proxy, 1.66 + JS::AutoIdVector &props) MOZ_OVERRIDE; 1.67 + // We override keys() and implement it directly instead of using the 1.68 + // default implementation, which would getOwnPropertyNames and then 1.69 + // filter out the non-enumerable ones. This avoids doing 1.70 + // unnecessary work during enumeration. 1.71 + virtual bool keys(JSContext* cx, JS::Handle<JSObject*> proxy, 1.72 + JS::AutoIdVector &props) MOZ_OVERRIDE; 1.73 + 1.74 +protected: 1.75 + // Hook for subclasses to implement shared getOwnPropertyNames()/keys() 1.76 + // functionality. The "flags" argument is either JSITER_OWNONLY (for keys()) 1.77 + // or JSITER_OWNONLY | JSITER_HIDDEN (for getOwnPropertyNames()). 1.78 + virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy, 1.79 + unsigned flags, 1.80 + JS::AutoIdVector& props) = 0; 1.81 + 1.82 + // Hook for subclasses to allow set() to ignore named props while other things 1.83 + // that look at property descriptors see them. This is intentionally not 1.84 + // named getOwnPropertyDescriptor to avoid subclasses that override it hiding 1.85 + // our public getOwnPropertyDescriptor. 1.86 + virtual bool getOwnPropDescriptor(JSContext* cx, 1.87 + JS::Handle<JSObject*> proxy, 1.88 + JS::Handle<jsid> id, 1.89 + bool ignoreNamedProps, 1.90 + JS::MutableHandle<JSPropertyDescriptor> desc) = 0; 1.91 +}; 1.92 + 1.93 +class DOMProxyHandler : public BaseDOMProxyHandler 1.94 +{ 1.95 +public: 1.96 + DOMProxyHandler() 1.97 + : BaseDOMProxyHandler(ProxyFamily()) 1.98 + { 1.99 + } 1.100 + 1.101 + bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy) MOZ_OVERRIDE; 1.102 + bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, 1.103 + JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE 1.104 + { 1.105 + bool unused; 1.106 + return defineProperty(cx, proxy, id, desc, &unused); 1.107 + } 1.108 + virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, 1.109 + JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined); 1.110 + bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver, 1.111 + JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE; 1.112 + bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, 1.113 + JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE; 1.114 + bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE; 1.115 + bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible) MOZ_OVERRIDE; 1.116 + 1.117 + /* 1.118 + * If assigning to proxy[id] hits a named setter with OverrideBuiltins or 1.119 + * an indexed setter, call it and set *done to true on success. Otherwise, set 1.120 + * *done to false. 1.121 + */ 1.122 + virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, 1.123 + JS::MutableHandle<JS::Value> vp, bool *done); 1.124 + 1.125 + static JSObject* GetExpandoObject(JSObject* obj) 1.126 + { 1.127 + MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object"); 1.128 + JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); 1.129 + if (v.isObject()) { 1.130 + return &v.toObject(); 1.131 + } 1.132 + 1.133 + if (v.isUndefined()) { 1.134 + return nullptr; 1.135 + } 1.136 + 1.137 + js::ExpandoAndGeneration* expandoAndGeneration = 1.138 + static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); 1.139 + v = expandoAndGeneration->expando; 1.140 + return v.isUndefined() ? nullptr : &v.toObject(); 1.141 + } 1.142 + /* GetAndClearExpandoObject does not DROP or clear the preserving wrapper flag. */ 1.143 + static JSObject* GetAndClearExpandoObject(JSObject* obj); 1.144 + static JSObject* EnsureExpandoObject(JSContext* cx, 1.145 + JS::Handle<JSObject*> obj); 1.146 +}; 1.147 + 1.148 +inline DOMProxyHandler* 1.149 +GetDOMProxyHandler(JSObject* obj) 1.150 +{ 1.151 + MOZ_ASSERT(IsDOMProxy(obj)); 1.152 + return static_cast<DOMProxyHandler*>(js::GetProxyHandler(obj)); 1.153 +} 1.154 + 1.155 +extern jsid s_length_id; 1.156 + 1.157 +int32_t IdToInt32(JSContext* cx, JS::Handle<jsid> id); 1.158 + 1.159 +// XXXbz this should really return uint32_t, with the maximum value 1.160 +// meaning "not an index"... 1.161 +inline int32_t 1.162 +GetArrayIndexFromId(JSContext* cx, JS::Handle<jsid> id) 1.163 +{ 1.164 + if (MOZ_LIKELY(JSID_IS_INT(id))) { 1.165 + return JSID_TO_INT(id); 1.166 + } 1.167 + if (MOZ_LIKELY(id == s_length_id)) { 1.168 + return -1; 1.169 + } 1.170 + if (MOZ_LIKELY(JSID_IS_ATOM(id))) { 1.171 + JSAtom* atom = JSID_TO_ATOM(id); 1.172 + jschar s = *js::GetAtomChars(atom); 1.173 + if (MOZ_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z')) 1.174 + return -1; 1.175 + 1.176 + uint32_t i; 1.177 + JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id)); 1.178 + return js::StringIsArrayIndex(str, &i) ? i : -1; 1.179 + } 1.180 + return IdToInt32(cx, id); 1.181 +} 1.182 + 1.183 +inline bool 1.184 +IsArrayIndex(int32_t index) 1.185 +{ 1.186 + return index >= 0; 1.187 +} 1.188 + 1.189 +inline void 1.190 +FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc, 1.191 + JSObject* obj, bool readonly, bool enumerable = true) 1.192 +{ 1.193 + desc.object().set(obj); 1.194 + desc.setAttributes((readonly ? JSPROP_READONLY : 0) | 1.195 + (enumerable ? JSPROP_ENUMERATE : 0)); 1.196 + desc.setGetter(nullptr); 1.197 + desc.setSetter(nullptr); 1.198 +} 1.199 + 1.200 +inline void 1.201 +FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc, 1.202 + JSObject* obj, JS::Value v, 1.203 + bool readonly, bool enumerable = true) 1.204 +{ 1.205 + desc.value().set(v); 1.206 + FillPropertyDescriptor(desc, obj, readonly, enumerable); 1.207 +} 1.208 + 1.209 +inline void 1.210 +FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc, 1.211 + JSObject* obj, unsigned attributes, JS::Value v) 1.212 +{ 1.213 + desc.object().set(obj); 1.214 + desc.value().set(v); 1.215 + desc.setAttributes(attributes); 1.216 + desc.setGetter(nullptr); 1.217 + desc.setSetter(nullptr); 1.218 +} 1.219 + 1.220 +} // namespace dom 1.221 +} // namespace mozilla 1.222 + 1.223 +#endif /* mozilla_dom_DOMProxyHandler_h */