1/*
2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003-2006, 2008-2009, 2013, 2016 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
5 * Copyright (C) 2009 Google, Inc. All rights reserved.
6 * Copyright (C) 2012 Ericsson AB. All rights reserved.
7 * Copyright (C) 2013 Michael Pruett <michael@68k.org>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#pragma once
25
26#include "DOMWrapperWorld.h"
27#include "JSDOMGlobalObject.h"
28#include "JSDOMWrapper.h"
29#include "ScriptWrappable.h"
30#include "ScriptWrappableInlines.h"
31#include "WebCoreTypedArrayController.h"
32#include <JavaScriptCore/JSArrayBuffer.h>
33#include <JavaScriptCore/TypedArrayInlines.h>
34#include <JavaScriptCore/Weak.h>
35#include <JavaScriptCore/WeakInlines.h>
36
37namespace WebCore {
38
39WEBCORE_EXPORT JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject&, const JSC::ClassInfo*);
40WEBCORE_EXPORT JSC::Structure* cacheDOMStructure(JSDOMGlobalObject&, JSC::Structure*, const JSC::ClassInfo*);
41
42template<typename WrapperClass> JSC::Structure* getDOMStructure(JSC::VM&, JSDOMGlobalObject&);
43template<typename WrapperClass> JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState*);
44template<typename WrapperClass> JSC::JSObject* getDOMPrototype(JSC::VM&, JSC::JSGlobalObject*);
45
46JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, JSC::ArrayBuffer*);
47void* wrapperKey(JSC::ArrayBuffer*);
48
49JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, void*);
50JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*);
51JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*);
52
53bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*, JSC::WeakHandleOwner*);
54bool setInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*, JSDOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner);
55bool setInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner);
56
57bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*);
58bool clearInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*, JSDOMObject* wrapper);
59bool clearInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*, JSC::JSArrayBuffer* wrapper);
60
61template<typename DOMClass> JSC::JSObject* getCachedWrapper(DOMWrapperWorld&, DOMClass&);
62template<typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld& world, Ref<DOMClass>& object) { return getCachedWrapper(world, object.get()); }
63template<typename DOMClass, typename WrapperClass> void cacheWrapper(DOMWrapperWorld&, DOMClass*, WrapperClass*);
64template<typename DOMClass, typename WrapperClass> void uncacheWrapper(DOMWrapperWorld&, DOMClass*, WrapperClass*);
65template<typename DOMClass, typename T> auto createWrapper(JSDOMGlobalObject*, Ref<T>&&) -> typename std::enable_if<std::is_same<DOMClass, T>::value, typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass*>::type;
66template<typename DOMClass, typename T> auto createWrapper(JSDOMGlobalObject*, Ref<T>&&) -> typename std::enable_if<!std::is_same<DOMClass, T>::value, typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass*>::type;
67
68template<typename DOMClass> JSC::JSValue wrap(JSC::ExecState*, JSDOMGlobalObject*, DOMClass&);
69
70
71// Inline functions and template definitions.
72
73inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
74{
75 // FIXME: Callers to this function should be using the global object
76 // from which the object is being created, instead of assuming the lexical one.
77 // e.g. subframe.document.body should use the subframe's global object, not the lexical one.
78 return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
79}
80
81template<typename WrapperClass> inline JSC::Structure* getDOMStructure(JSC::VM& vm, JSDOMGlobalObject& globalObject)
82{
83 if (JSC::Structure* structure = getCachedDOMStructure(globalObject, WrapperClass::info()))
84 return structure;
85 return cacheDOMStructure(globalObject, WrapperClass::createStructure(vm, &globalObject, WrapperClass::createPrototype(vm, globalObject)), WrapperClass::info());
86}
87
88template<typename WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
89{
90 // FIXME: This function is wrong. It uses the wrong global object for creating the prototype structure.
91 return getDOMStructure<WrapperClass>(exec->vm(), *deprecatedGlobalObjectForPrototype(exec));
92}
93
94template<typename WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::VM& vm, JSDOMGlobalObject& globalObject)
95{
96 return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(vm, globalObject)->storedPrototype()));
97}
98
99inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld& world, JSC::ArrayBuffer*)
100{
101 return static_cast<WebCoreTypedArrayController*>(world.vm().m_typedArrayController.get())->wrapperOwner();
102}
103
104inline void* wrapperKey(JSC::ArrayBuffer* domObject)
105{
106 return domObject;
107}
108
109inline JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, void*) { return nullptr; }
110inline bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*, JSC::WeakHandleOwner*) { return false; }
111inline bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*) { return false; }
112
113inline JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject)
114{
115 if (!world.isNormal())
116 return nullptr;
117 return domObject->wrapper();
118}
119
120inline JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* buffer)
121{
122 if (!world.isNormal())
123 return nullptr;
124 return buffer->m_wrapper.get();
125}
126
127inline bool setInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner)
128{
129 if (!world.isNormal())
130 return false;
131 domObject->setWrapper(wrapper, wrapperOwner, &world);
132 return true;
133}
134
135inline bool setInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner)
136{
137 if (!world.isNormal())
138 return false;
139 domObject->m_wrapper = JSC::Weak<JSC::JSArrayBuffer>(wrapper, wrapperOwner, &world);
140 return true;
141}
142
143inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMObject* wrapper)
144{
145 if (!world.isNormal())
146 return false;
147 domObject->clearWrapper(wrapper);
148 return true;
149}
150
151inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper)
152{
153 if (!world.isNormal())
154 return false;
155 weakClear(domObject->m_wrapper, wrapper);
156 return true;
157}
158
159template<typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld& world, DOMClass& domObject)
160{
161 if (auto* wrapper = getInlineCachedWrapper(world, &domObject))
162 return wrapper;
163 return world.wrappers().get(wrapperKey(&domObject));
164}
165
166template<typename DOMClass, typename WrapperClass> inline void cacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper)
167{
168 JSC::WeakHandleOwner* owner = wrapperOwner(world, domObject);
169 if (setInlineCachedWrapper(world, domObject, wrapper, owner))
170 return;
171 weakAdd(world.wrappers(), wrapperKey(domObject), JSC::Weak<JSC::JSObject>(wrapper, owner, &world));
172}
173
174template<typename DOMClass, typename WrapperClass> inline void uncacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper)
175{
176 if (clearInlineCachedWrapper(world, domObject, wrapper))
177 return;
178 weakRemove(world.wrappers(), wrapperKey(domObject), wrapper);
179}
180
181template<typename DOMClass, typename T> inline auto createWrapper(JSDOMGlobalObject* globalObject, Ref<T>&& domObject) -> typename std::enable_if<std::is_same<DOMClass, T>::value, typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass*>::type
182{
183 using WrapperClass = typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass;
184
185 ASSERT(!getCachedWrapper(globalObject->world(), domObject));
186 auto* domObjectPtr = domObject.ptr();
187 auto* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(globalObject->vm(), *globalObject), globalObject, WTFMove(domObject));
188 cacheWrapper(globalObject->world(), domObjectPtr, wrapper);
189 return wrapper;
190}
191
192template<typename DOMClass, typename T> inline auto createWrapper(JSDOMGlobalObject* globalObject, Ref<T>&& domObject) -> typename std::enable_if<!std::is_same<DOMClass, T>::value, typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass*>::type
193{
194 return createWrapper<DOMClass>(globalObject, static_reference_cast<DOMClass>(WTFMove(domObject)));
195}
196
197template<typename DOMClass> inline JSC::JSValue wrap(JSC::ExecState* state, JSDOMGlobalObject* globalObject, DOMClass& domObject)
198{
199 if (auto* wrapper = getCachedWrapper(globalObject->world(), domObject))
200 return wrapper;
201 return toJSNewlyCreated(state, globalObject, Ref<DOMClass>(domObject));
202}
203
204} // namespace WebCore
205