Move WebCore into Source
[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 "c_class.h"
35 #include "c_runtime.h"
36 #include "c_utility.h"
37 #include "npruntime_impl.h"
38 #include "runtime_method.h"
39 #include "runtime_root.h"
40 #include <interpreter/CallFrame.h>
41 #include <runtime/ArgList.h>
42 #include <runtime/Error.h>
43 #include <runtime/JSLock.h>
44 #include <runtime/JSNumberCell.h>
45 #include <runtime/PropertyNameArray.h>
46 #include <wtf/Assertions.h>
47 #include <wtf/StdLibExtras.h>
48 #include <wtf/StringExtras.h>
49 #include <wtf/Vector.h>
50
51 using namespace WebCore;
52
53 namespace JSC {
54 namespace Bindings {
55
56 using JSC::UString;
57
58 static JSC::UString& globalExceptionString()
59 {
60     DEFINE_STATIC_LOCAL(JSC::UString, exceptionStr, ());
61     return exceptionStr;
62 }
63
64 void CInstance::setGlobalException(UString exception)
65 {
66     globalExceptionString() = exception;
67 }
68
69 void CInstance::moveGlobalExceptionToExecState(ExecState* exec)
70 {
71     if (globalExceptionString().isNull())
72         return;
73
74     {
75         JSLock lock(SilenceAssertionsOnly);
76         throwError(exec, createError(exec, globalExceptionString()));
77     }
78
79     globalExceptionString() = UString();
80 }
81
82 CInstance::CInstance(NPObject* o, PassRefPtr<RootObject> rootObject)
83     : Instance(rootObject)
84 {
85     _object = _NPN_RetainObject(o);
86     _class = 0;
87 }
88
89 CInstance::~CInstance() 
90 {
91     _NPN_ReleaseObject(_object);
92 }
93
94 RuntimeObject* CInstance::newRuntimeObject(ExecState* exec)
95 {
96     return new (exec) CRuntimeObject(exec, exec->lexicalGlobalObject(), this);
97 }
98
99 Class *CInstance::getClass() const
100 {
101     if (!_class)
102         _class = CClass::classForIsA(_object->_class);
103     return _class;
104 }
105
106 bool CInstance::supportsInvokeDefaultMethod() const
107 {
108     return _object->_class->invokeDefault;
109 }
110
111 class CRuntimeMethod : public RuntimeMethod {
112 public:
113     CRuntimeMethod(ExecState* exec, JSGlobalObject* globalObject, const Identifier& name, Bindings::MethodList& list)
114         : RuntimeMethod(exec, globalObject, name, list)
115     {
116     }
117
118     virtual const ClassInfo* classInfo() const { return &s_info; }
119
120     static const ClassInfo s_info;
121 };
122
123 const ClassInfo CRuntimeMethod::s_info = { "CRuntimeMethod", &RuntimeMethod::s_info, 0, 0 };
124
125 JSValue CInstance::getMethod(ExecState* exec, const Identifier& propertyName)
126 {
127     MethodList methodList = getClass()->methodsNamed(propertyName, this);
128     return new (exec) CRuntimeMethod(exec, exec->lexicalGlobalObject(), propertyName, methodList);
129 }
130
131 JSValue CInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod)
132 {
133     if (!asObject(runtimeMethod)->inherits(&CRuntimeMethod::s_info))
134         return throwError(exec, createTypeError(exec, "Attempt to invoke non-plug-in method on plug-in object."));
135
136     const MethodList& methodList = *runtimeMethod->methods();
137
138     // Overloading methods are not allowed by NPObjects.  Should only be one
139     // name match for a particular method.
140     ASSERT(methodList.size() == 1);
141
142     CMethod* method = static_cast<CMethod*>(methodList[0]);
143
144     NPIdentifier ident = method->identifier();
145     if (!_object->_class->hasMethod(_object, ident))
146         return jsUndefined();
147
148     unsigned count = exec->argumentCount();
149     Vector<NPVariant, 8> cArgs(count);
150
151     unsigned i;
152     for (i = 0; i < count; i++)
153         convertValueToNPVariant(exec, exec->argument(i), &cArgs[i]);
154
155     // Invoke the 'C' method.
156     bool retval = true;
157     NPVariant resultVariant;
158     VOID_TO_NPVARIANT(resultVariant);
159
160     {
161         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
162         ASSERT(globalExceptionString().isNull());
163         retval = _object->_class->invoke(_object, ident, cArgs.data(), count, &resultVariant);
164         moveGlobalExceptionToExecState(exec);
165     }
166     
167     if (!retval)
168         throwError(exec, createError(exec, "Error calling method on NPObject."));
169
170     for (i = 0; i < count; i++)
171         _NPN_ReleaseVariantValue(&cArgs[i]);
172
173     JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get());
174     _NPN_ReleaseVariantValue(&resultVariant);
175     return resultValue;
176 }
177
178
179 JSValue CInstance::invokeDefaultMethod(ExecState* exec)
180 {
181     if (!_object->_class->invokeDefault)
182         return jsUndefined();
183
184     unsigned count = exec->argumentCount();
185     Vector<NPVariant, 8> cArgs(count);
186
187     unsigned i;
188     for (i = 0; i < count; i++)
189         convertValueToNPVariant(exec, exec->argument(i), &cArgs[i]);
190
191     // Invoke the 'C' method.
192     bool retval = true;
193     NPVariant resultVariant;
194     VOID_TO_NPVARIANT(resultVariant);
195     {
196         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
197         ASSERT(globalExceptionString().isNull());
198         retval = _object->_class->invokeDefault(_object, cArgs.data(), count, &resultVariant);
199         moveGlobalExceptionToExecState(exec);
200     }
201     
202     if (!retval)
203         throwError(exec, createError(exec, "Error calling method on NPObject."));
204
205     for (i = 0; i < count; i++)
206         _NPN_ReleaseVariantValue(&cArgs[i]);
207
208     JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get());
209     _NPN_ReleaseVariantValue(&resultVariant);
210     return resultValue;
211 }
212
213 bool CInstance::supportsConstruct() const
214 {
215     return _object->_class->construct;
216 }
217     
218 JSValue CInstance::invokeConstruct(ExecState* exec, const ArgList& args)
219 {
220     if (!_object->_class->construct)
221         return jsUndefined();
222
223     unsigned count = args.size();
224     Vector<NPVariant, 8> cArgs(count);
225
226     unsigned i;
227     for (i = 0; i < count; i++)
228         convertValueToNPVariant(exec, args.at(i), &cArgs[i]);
229
230     // Invoke the 'C' method.
231     bool retval = true;
232     NPVariant resultVariant;
233     VOID_TO_NPVARIANT(resultVariant);
234     {
235         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
236         ASSERT(globalExceptionString().isNull());
237         retval = _object->_class->construct(_object, cArgs.data(), count, &resultVariant);
238         moveGlobalExceptionToExecState(exec);
239     }
240     
241     if (!retval)
242         throwError(exec, createError(exec, "Error calling method on NPObject."));
243
244     for (i = 0; i < count; i++)
245         _NPN_ReleaseVariantValue(&cArgs[i]);
246
247     JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get());
248     _NPN_ReleaseVariantValue(&resultVariant);
249     return resultValue;
250 }
251
252 JSValue CInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
253 {
254     if (hint == PreferString)
255         return stringValue(exec);
256     if (hint == PreferNumber)
257         return numberValue(exec);
258     return valueOf(exec);
259 }
260
261 JSValue CInstance::stringValue(ExecState* exec) const
262 {
263     char buf[1024];
264     snprintf(buf, sizeof(buf), "NPObject %p, NPClass %p", _object, _object->_class);
265     return jsString(exec, buf);
266 }
267
268 JSValue CInstance::numberValue(ExecState*) const
269 {
270     // FIXME: Implement something sensible.
271     return jsNumber(0);
272 }
273
274 JSValue CInstance::booleanValue() const
275 {
276     // FIXME: Implement something sensible.
277     return jsBoolean(false);
278 }
279
280 JSValue CInstance::valueOf(ExecState* exec) const 
281 {
282     return stringValue(exec);
283 }
284
285 void CInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArray)
286 {
287     if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(_object->_class) || !_object->_class->enumerate)
288         return;
289
290     uint32_t count;
291     NPIdentifier* identifiers;
292
293     {
294         JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly);
295         ASSERT(globalExceptionString().isNull());
296         bool ok = _object->_class->enumerate(_object, &identifiers, &count);
297         moveGlobalExceptionToExecState(exec);
298         if (!ok)
299             return;
300     }
301
302     for (uint32_t i = 0; i < count; i++) {
303         IdentifierRep* identifier = static_cast<IdentifierRep*>(identifiers[i]);
304
305         if (identifier->isString())
306             nameArray.add(identifierFromNPIdentifier(exec, identifier->string()));
307         else
308             nameArray.add(Identifier::from(exec, identifier->number()));
309     }
310
311     // FIXME: This should really call NPN_MemFree but that's in WebKit
312     free(identifiers);
313 }
314
315 }
316 }
317
318 #endif // ENABLE(NETSCAPE_PLUGIN_API)