Foo::s_info should be Foo::info(), so that you can change how the s_info is actually...
[WebKit-https.git] / Source / WebCore / bridge / c / c_instance.cpp
1 /*
2  * Copyright (C) 2003, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(NETSCAPE_PLUGIN_API)
29
30 #include "c_instance.h"
31
32 #include "CRuntimeObject.h"
33 #include "IdentifierRep.h"
34 #include "JSDOMBinding.h"
35 #include "c_class.h"
36 #include "c_runtime.h"
37 #include "c_utility.h"
38 #include "npruntime_impl.h"
39 #include "runtime_method.h"
40 #include "runtime_root.h"
41 #include <interpreter/CallFrame.h>
42 #include <runtime/ArgList.h>
43 #include <runtime/Error.h>
44 #include <runtime/FunctionPrototype.h>
45 #include <runtime/JSLock.h>
46 #include <runtime/PropertyNameArray.h>
47 #include <wtf/Assertions.h>
48 #include <wtf/StdLibExtras.h>
49 #include <wtf/StringExtras.h>
50 #include <wtf/Vector.h>
51
52 using namespace WebCore;
53
54 namespace JSC {
55 namespace Bindings {
56
57 static String& globalExceptionString()
58 {
59     DEFINE_STATIC_LOCAL(String, exceptionStr, ());
60     return exceptionStr;
61 }
62
63 void CInstance::setGlobalException(String exception)
64 {
65     globalExceptionString() = exception;
66 }
67
68 void CInstance::moveGlobalExceptionToExecState(ExecState* exec)
69 {
70     if (globalExceptionString().isNull())
71         return;
72
73     {
74         JSLockHolder lock(exec);
75         throwError(exec, createError(exec, globalExceptionString()));
76     }
77
78     globalExceptionString() = String();
79 }
80
81 CInstance::CInstance(NPObject* o, PassRefPtr<RootObject> rootObject)
82     : Instance(rootObject)
83 {
84     _object = _NPN_RetainObject(o);
85     _class = 0;
86 }
87
88 CInstance::~CInstance()
89 {
90     _NPN_ReleaseObject(_object);
91 }
92
93 RuntimeObject* CInstance::newRuntimeObject(ExecState* exec)
94 {
95     return CRuntimeObject::create(exec, exec->lexicalGlobalObject(), this);
96 }
97
98 Class *CInstance::getClass() const
99 {
100     if (!_class)
101         _class = CClass::classForIsA(_object->_class);
102     return _class;
103 }
104
105 bool CInstance::supportsInvokeDefaultMethod() const
106 {
107     return _object->_class->invokeDefault;
108 }
109
110 class CRuntimeMethod : public RuntimeMethod {
111 public:
112     typedef RuntimeMethod Base;
113
114     static CRuntimeMethod* create(ExecState* exec, JSGlobalObject* globalObject, const String& name, Bindings::Method* method)
115     {
116         // FIXME: deprecatedGetDOMStructure uses the prototype off of the wrong global object
117         // We need to pass in the right global object for "i".
118         Structure* domStructure = WebCore::deprecatedGetDOMStructure<CRuntimeMethod>(exec);
119         CRuntimeMethod* runtimeMethod = new (NotNull, allocateCell<CRuntimeMethod>(*exec->heap())) CRuntimeMethod(globalObject, domStructure, method);
120         runtimeMethod->finishCreation(exec->vm(), name);
121         return runtimeMethod;
122     }
123
124     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
125     {
126         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
127     }
128
129     DECLARE_INFO;
130
131 private:
132     CRuntimeMethod(JSGlobalObject* globalObject, Structure* structure, Bindings::Method* method)
133         : RuntimeMethod(globalObject, structure, method)
134     {
135     }
136
137     void finishCreation(VM& vm, const String& name)
138     {
139         Base::finishCreation(vm, name);
140         ASSERT(inherits(info()));
141     }
142
143 };
144
145 const ClassInfo CRuntimeMethod::s_info = { "CRuntimeMethod", &RuntimeMethod::s_info, 0, 0, CREATE_METHOD_TABLE(CRuntimeMethod) };
146
147 JSValue CInstance::getMethod(ExecState* exec, PropertyName propertyName)
148 {
149     Method* method = getClass()->methodNamed(propertyName, this);
150     return CRuntimeMethod::create(exec, exec->lexicalGlobalObject(), propertyName.publicName(), method);
151 }
152
153 JSValue CInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod)
154 {
155     if (!asObject(runtimeMethod)->inherits(CRuntimeMethod::info()))
156         return throwError(exec, createTypeError(exec, "Attempt to invoke non-plug-in method on plug-in object."));
157
158     CMethod* method = static_cast<CMethod*>(runtimeMethod->method());
159     ASSERT(method);
160
161     NPIdentifier ident = method->identifier();
162     if (!_object->_class->hasMethod(_object, ident))
163         return jsUndefined();
164
165     unsigned count = exec->argumentCount();
166     Vector<NPVariant, 8> cArgs(count);
167
168     unsigned i;
169     for (i = 0; i < count; i++)
170         convertValueToNPVariant(exec, exec->argument(i), &cArgs[i]);
171
172     // Invoke the 'C' method.
173     bool retval = true;
174     NPVariant resultVariant;
175     VOID_TO_NPVARIANT(resultVariant);
176
177     {
178         JSLock::DropAllLocks dropAllLocks(exec);
179         ASSERT(globalExceptionString().isNull());
180         retval = _object->_class->invoke(_object, ident, cArgs.data(), count, &resultVariant);
181         moveGlobalExceptionToExecState(exec);
182     }
183
184     if (!retval)
185         throwError(exec, createError(exec, ASCIILiteral("Error calling method on NPObject.")));
186
187     for (i = 0; i < count; i++)
188         _NPN_ReleaseVariantValue(&cArgs[i]);
189
190     JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get());
191     _NPN_ReleaseVariantValue(&resultVariant);
192     return resultValue;
193 }
194
195
196 JSValue CInstance::invokeDefaultMethod(ExecState* exec)
197 {
198     if (!_object->_class->invokeDefault)
199         return jsUndefined();
200
201     unsigned count = exec->argumentCount();
202     Vector<NPVariant, 8> cArgs(count);
203
204     unsigned i;
205     for (i = 0; i < count; i++)
206         convertValueToNPVariant(exec, exec->argument(i), &cArgs[i]);
207
208     // Invoke the 'C' method.
209     bool retval = true;
210     NPVariant resultVariant;
211     VOID_TO_NPVARIANT(resultVariant);
212     {
213         JSLock::DropAllLocks dropAllLocks(exec);
214         ASSERT(globalExceptionString().isNull());
215         retval = _object->_class->invokeDefault(_object, cArgs.data(), count, &resultVariant);
216         moveGlobalExceptionToExecState(exec);
217     }
218
219     if (!retval)
220         throwError(exec, createError(exec, ASCIILiteral("Error calling method on NPObject.")));
221
222     for (i = 0; i < count; i++)
223         _NPN_ReleaseVariantValue(&cArgs[i]);
224
225     JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get());
226     _NPN_ReleaseVariantValue(&resultVariant);
227     return resultValue;
228 }
229
230 bool CInstance::supportsConstruct() const
231 {
232     return _object->_class->construct;
233 }
234
235 JSValue CInstance::invokeConstruct(ExecState* exec, const ArgList& args)
236 {
237     if (!_object->_class->construct)
238         return jsUndefined();
239
240     unsigned count = args.size();
241     Vector<NPVariant, 8> cArgs(count);
242
243     unsigned i;
244     for (i = 0; i < count; i++)
245         convertValueToNPVariant(exec, args.at(i), &cArgs[i]);
246
247     // Invoke the 'C' method.
248     bool retval = true;
249     NPVariant resultVariant;
250     VOID_TO_NPVARIANT(resultVariant);
251     {
252         JSLock::DropAllLocks dropAllLocks(exec);
253         ASSERT(globalExceptionString().isNull());
254         retval = _object->_class->construct(_object, cArgs.data(), count, &resultVariant);
255         moveGlobalExceptionToExecState(exec);
256     }
257
258     if (!retval)
259         throwError(exec, createError(exec, ASCIILiteral("Error calling method on NPObject.")));
260
261     for (i = 0; i < count; i++)
262         _NPN_ReleaseVariantValue(&cArgs[i]);
263
264     JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get());
265     _NPN_ReleaseVariantValue(&resultVariant);
266     return resultValue;
267 }
268
269 JSValue CInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
270 {
271     if (hint == PreferString)
272         return stringValue(exec);
273     if (hint == PreferNumber)
274         return numberValue(exec);
275     return valueOf(exec);
276 }
277
278 JSValue CInstance::stringValue(ExecState* exec) const
279 {
280     JSValue value;
281     if (toJSPrimitive(exec, "toString", value))
282         return value;
283
284     // Fallback to default implementation.
285     return jsString(exec, "NPObject");
286 }
287
288 JSValue CInstance::numberValue(ExecState*) const
289 {
290     // FIXME: Implement something sensible.
291     return jsNumber(0);
292 }
293
294 JSValue CInstance::booleanValue() const
295 {
296     // As per ECMA 9.2.
297     return jsBoolean(getObject());
298 }
299
300 JSValue CInstance::valueOf(ExecState* exec) const
301 {
302     JSValue value;
303     if (toJSPrimitive(exec, "valueOf", value))
304         return value;
305
306     // Fallback to default implementation.
307     return stringValue(exec);
308 }
309
310 bool CInstance::toJSPrimitive(ExecState* exec, const char* name, JSValue& resultValue) const
311 {
312     NPIdentifier ident = _NPN_GetStringIdentifier(name);
313     if (!_object->_class->hasMethod(_object, ident))
314         return false;
315
316     // Invoke the 'C' method.
317     bool retval = true;
318     NPVariant resultVariant;
319     VOID_TO_NPVARIANT(resultVariant);
320
321     {
322         JSLock::DropAllLocks dropAllLocks(exec);
323         ASSERT(globalExceptionString().isNull());
324         retval = _object->_class->invoke(_object, ident, 0, 0, &resultVariant);
325         moveGlobalExceptionToExecState(exec);
326     }
327
328     if (!retval)
329         throwError(exec, createError(exec, ASCIILiteral("Error calling method on NPObject.")));
330
331     resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get());
332     _NPN_ReleaseVariantValue(&resultVariant);
333     return true;
334 }
335
336 void CInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArray)
337 {
338     if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(_object->_class) || !_object->_class->enumerate)
339         return;
340
341     uint32_t count;
342     NPIdentifier* identifiers;
343
344     {
345         JSLock::DropAllLocks dropAllLocks(exec);
346         ASSERT(globalExceptionString().isNull());
347         bool ok = _object->_class->enumerate(_object, &identifiers, &count);
348         moveGlobalExceptionToExecState(exec);
349         if (!ok)
350             return;
351     }
352
353     for (uint32_t i = 0; i < count; i++) {
354         IdentifierRep* identifier = static_cast<IdentifierRep*>(identifiers[i]);
355
356         if (identifier->isString())
357             nameArray.add(identifierFromNPIdentifier(exec, identifier->string()));
358         else
359             nameArray.add(Identifier::from(exec, identifier->number()));
360     }
361
362     // FIXME: This should really call NPN_MemFree but that's in WebKit
363     free(identifiers);
364 }
365
366 }
367 }
368
369 #endif // ENABLE(NETSCAPE_PLUGIN_API)