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