1 /*
2 * Copyright (C) 2004, 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 "NP_jsobject.h"
31
32 #include "PlatformString.h"
33 #include "PluginView.h"
34 #include "StringSourceProvider.h"
35 #include "c_utility.h"
36 #include "c_instance.h"
37 #include "IdentifierRep.h"
38 #include "JSDOMBinding.h"
39 #include "npruntime_impl.h"
40 #include "npruntime_priv.h"
41 #include "runtime_root.h"
42 #include <runtime/Error.h>
43 #include <runtime/JSGlobalObject.h>
44 #include <runtime/JSLock.h>
45 #include <runtime/PropertyNameArray.h>
46 #include <parser/SourceCode.h>
47 #include <runtime/Completion.h>
48 #include <runtime/Completion.h>
49
50 using namespace JSC;
51 using namespace JSC::Bindings;
52 using namespace WebCore;
53
getListFromVariantArgs(ExecState * exec,const NPVariant * args,unsigned argCount,RootObject * rootObject,MarkedArgumentBuffer & aList)54 static void getListFromVariantArgs(ExecState* exec, const NPVariant* args, unsigned argCount, RootObject* rootObject, MarkedArgumentBuffer& aList)
55 {
56 for (unsigned i = 0; i < argCount; ++i)
57 aList.append(convertNPVariantToValue(exec, &args[i], rootObject));
58 }
59
jsAllocate(NPP,NPClass *)60 static NPObject* jsAllocate(NPP, NPClass*)
61 {
62 return static_cast<NPObject*>(malloc(sizeof(JavaScriptObject)));
63 }
64
jsDeallocate(NPObject * npObj)65 static void jsDeallocate(NPObject* npObj)
66 {
67 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(npObj);
68
69 if (obj->rootObject && obj->rootObject->isValid())
70 obj->rootObject->gcUnprotect(obj->imp);
71
72 if (obj->rootObject)
73 obj->rootObject->deref();
74
75 free(obj);
76 }
77
78 static NPClass javascriptClass = { 1, jsAllocate, jsDeallocate, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
79 static NPClass noScriptClass = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
80
81 NPClass* NPScriptObjectClass = &javascriptClass;
82 static NPClass* NPNoScriptObjectClass = &noScriptClass;
83
_NPN_CreateScriptObject(NPP npp,JSObject * imp,PassRefPtr<RootObject> rootObject)84 NPObject* _NPN_CreateScriptObject(NPP npp, JSObject* imp, PassRefPtr<RootObject> rootObject)
85 {
86 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(_NPN_CreateObject(npp, NPScriptObjectClass));
87
88 obj->rootObject = rootObject.releaseRef();
89
90 if (obj->rootObject)
91 obj->rootObject->gcProtect(imp);
92 obj->imp = imp;
93
94 return reinterpret_cast<NPObject*>(obj);
95 }
96
_NPN_CreateNoScriptObject(void)97 NPObject* _NPN_CreateNoScriptObject(void)
98 {
99 return _NPN_CreateObject(0, NPNoScriptObjectClass);
100 }
101
_NPN_InvokeDefault(NPP,NPObject * o,const NPVariant * args,uint32_t argCount,NPVariant * result)102 bool _NPN_InvokeDefault(NPP, NPObject* o, const NPVariant* args, uint32_t argCount, NPVariant* result)
103 {
104 if (o->_class == NPScriptObjectClass) {
105 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
106
107 VOID_TO_NPVARIANT(*result);
108
109 // Lookup the function object.
110 RootObject* rootObject = obj->rootObject;
111 if (!rootObject || !rootObject->isValid())
112 return false;
113
114 ExecState* exec = rootObject->globalObject()->globalExec();
115 JSLock lock(SilenceAssertionsOnly);
116
117 // Call the function object.
118 JSValue function = obj->imp;
119 CallData callData;
120 CallType callType = function.getCallData(callData);
121 if (callType == CallTypeNone)
122 return false;
123
124 MarkedArgumentBuffer argList;
125 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
126 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
127 globalObject->globalData()->timeoutChecker.start();
128 JSValue resultV = JSC::call(exec, function, callType, callData, function, argList);
129 globalObject->globalData()->timeoutChecker.stop();
130
131 // Convert and return the result of the function call.
132 convertValueToNPVariant(exec, resultV, result);
133 exec->clearException();
134 return true;
135 }
136
137 if (o->_class->invokeDefault)
138 return o->_class->invokeDefault(o, args, argCount, result);
139 VOID_TO_NPVARIANT(*result);
140 return true;
141 }
142
_NPN_Invoke(NPP npp,NPObject * o,NPIdentifier methodName,const NPVariant * args,uint32_t argCount,NPVariant * result)143 bool _NPN_Invoke(NPP npp, NPObject* o, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result)
144 {
145 if (o->_class == NPScriptObjectClass) {
146 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
147
148 IdentifierRep* i = static_cast<IdentifierRep*>(methodName);
149 if (!i->isString())
150 return false;
151
152 // Special case the "eval" method.
153 if (methodName == _NPN_GetStringIdentifier("eval")) {
154 if (argCount != 1)
155 return false;
156 if (args[0].type != NPVariantType_String)
157 return false;
158 return _NPN_Evaluate(npp, o, const_cast<NPString*>(&args[0].value.stringValue), result);
159 }
160
161 // Look up the function object.
162 RootObject* rootObject = obj->rootObject;
163 if (!rootObject || !rootObject->isValid())
164 return false;
165 ExecState* exec = rootObject->globalObject()->globalExec();
166 JSLock lock(SilenceAssertionsOnly);
167 JSValue function = obj->imp->get(exec, identifierFromNPIdentifier(i->string()));
168 CallData callData;
169 CallType callType = function.getCallData(callData);
170 if (callType == CallTypeNone)
171 return false;
172
173 // Call the function object.
174 MarkedArgumentBuffer argList;
175 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
176 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
177 globalObject->globalData()->timeoutChecker.start();
178 JSValue resultV = JSC::call(exec, function, callType, callData, obj->imp, argList);
179 globalObject->globalData()->timeoutChecker.stop();
180
181 // Convert and return the result of the function call.
182 convertValueToNPVariant(exec, resultV, result);
183 exec->clearException();
184 return true;
185 }
186
187 if (o->_class->invoke)
188 return o->_class->invoke(o, methodName, args, argCount, result);
189
190 VOID_TO_NPVARIANT(*result);
191 return true;
192 }
193
_NPN_Evaluate(NPP instance,NPObject * o,NPString * s,NPVariant * variant)194 bool _NPN_Evaluate(NPP instance, NPObject* o, NPString* s, NPVariant* variant)
195 {
196 if (o->_class == NPScriptObjectClass) {
197 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
198
199 RootObject* rootObject = obj->rootObject;
200 if (!rootObject || !rootObject->isValid())
201 return false;
202
203 // There is a crash in Flash when evaluating a script that destroys the
204 // PluginView, so we destroy it asynchronously.
205 PluginView::keepAlive(instance);
206
207 ExecState* exec = rootObject->globalObject()->globalExec();
208 JSLock lock(SilenceAssertionsOnly);
209 String scriptString = convertNPStringToUTF16(s);
210 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
211 globalObject->globalData()->timeoutChecker.start();
212 Completion completion = JSC::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(scriptString), JSC::JSValue());
213 globalObject->globalData()->timeoutChecker.stop();
214 ComplType type = completion.complType();
215
216 JSValue result;
217 if (type == Normal) {
218 result = completion.value();
219 if (!result)
220 result = jsUndefined();
221 } else
222 result = jsUndefined();
223
224 convertValueToNPVariant(exec, result, variant);
225 exec->clearException();
226 return true;
227 }
228
229 VOID_TO_NPVARIANT(*variant);
230 return false;
231 }
232
_NPN_GetProperty(NPP,NPObject * o,NPIdentifier propertyName,NPVariant * variant)233 bool _NPN_GetProperty(NPP, NPObject* o, NPIdentifier propertyName, NPVariant* variant)
234 {
235 if (o->_class == NPScriptObjectClass) {
236 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
237
238 RootObject* rootObject = obj->rootObject;
239 if (!rootObject || !rootObject->isValid())
240 return false;
241
242 ExecState* exec = rootObject->globalObject()->globalExec();
243 IdentifierRep* i = static_cast<IdentifierRep*>(propertyName);
244
245 JSLock lock(SilenceAssertionsOnly);
246 JSValue result;
247 if (i->isString())
248 result = obj->imp->get(exec, identifierFromNPIdentifier(i->string()));
249 else
250 result = obj->imp->get(exec, i->number());
251
252 convertValueToNPVariant(exec, result, variant);
253 exec->clearException();
254 return true;
255 }
256
257 if (o->_class->hasProperty && o->_class->getProperty) {
258 if (o->_class->hasProperty(o, propertyName))
259 return o->_class->getProperty(o, propertyName, variant);
260 return false;
261 }
262
263 VOID_TO_NPVARIANT(*variant);
264 return false;
265 }
266
_NPN_SetProperty(NPP,NPObject * o,NPIdentifier propertyName,const NPVariant * variant)267 bool _NPN_SetProperty(NPP, NPObject* o, NPIdentifier propertyName, const NPVariant* variant)
268 {
269 if (o->_class == NPScriptObjectClass) {
270 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
271
272 RootObject* rootObject = obj->rootObject;
273 if (!rootObject || !rootObject->isValid())
274 return false;
275
276 ExecState* exec = rootObject->globalObject()->globalExec();
277 JSLock lock(SilenceAssertionsOnly);
278 IdentifierRep* i = static_cast<IdentifierRep*>(propertyName);
279
280 if (i->isString()) {
281 PutPropertySlot slot;
282 obj->imp->put(exec, identifierFromNPIdentifier(i->string()), convertNPVariantToValue(exec, variant, rootObject), slot);
283 } else
284 obj->imp->put(exec, i->number(), convertNPVariantToValue(exec, variant, rootObject));
285 exec->clearException();
286 return true;
287 }
288
289 if (o->_class->setProperty)
290 return o->_class->setProperty(o, propertyName, variant);
291
292 return false;
293 }
294
_NPN_RemoveProperty(NPP,NPObject * o,NPIdentifier propertyName)295 bool _NPN_RemoveProperty(NPP, NPObject* o, NPIdentifier propertyName)
296 {
297 if (o->_class == NPScriptObjectClass) {
298 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
299
300 RootObject* rootObject = obj->rootObject;
301 if (!rootObject || !rootObject->isValid())
302 return false;
303
304 ExecState* exec = rootObject->globalObject()->globalExec();
305 IdentifierRep* i = static_cast<IdentifierRep*>(propertyName);
306 if (i->isString()) {
307 if (!obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->string()))) {
308 exec->clearException();
309 return false;
310 }
311 } else {
312 if (!obj->imp->hasProperty(exec, i->number())) {
313 exec->clearException();
314 return false;
315 }
316 }
317
318 JSLock lock(SilenceAssertionsOnly);
319 if (i->isString())
320 obj->imp->deleteProperty(exec, identifierFromNPIdentifier(i->string()));
321 else
322 obj->imp->deleteProperty(exec, i->number());
323
324 exec->clearException();
325 return true;
326 }
327 return false;
328 }
329
_NPN_HasProperty(NPP,NPObject * o,NPIdentifier propertyName)330 bool _NPN_HasProperty(NPP, NPObject* o, NPIdentifier propertyName)
331 {
332 if (o->_class == NPScriptObjectClass) {
333 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
334
335 RootObject* rootObject = obj->rootObject;
336 if (!rootObject || !rootObject->isValid())
337 return false;
338
339 ExecState* exec = rootObject->globalObject()->globalExec();
340 IdentifierRep* i = static_cast<IdentifierRep*>(propertyName);
341 JSLock lock(SilenceAssertionsOnly);
342 if (i->isString()) {
343 bool result = obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->string()));
344 exec->clearException();
345 return result;
346 }
347
348 bool result = obj->imp->hasProperty(exec, i->number());
349 exec->clearException();
350 return result;
351 }
352
353 if (o->_class->hasProperty)
354 return o->_class->hasProperty(o, propertyName);
355
356 return false;
357 }
358
_NPN_HasMethod(NPP,NPObject * o,NPIdentifier methodName)359 bool _NPN_HasMethod(NPP, NPObject* o, NPIdentifier methodName)
360 {
361 if (o->_class == NPScriptObjectClass) {
362 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
363
364 IdentifierRep* i = static_cast<IdentifierRep*>(methodName);
365 if (!i->isString())
366 return false;
367
368 RootObject* rootObject = obj->rootObject;
369 if (!rootObject || !rootObject->isValid())
370 return false;
371
372 ExecState* exec = rootObject->globalObject()->globalExec();
373 JSLock lock(SilenceAssertionsOnly);
374 JSValue func = obj->imp->get(exec, identifierFromNPIdentifier(i->string()));
375 exec->clearException();
376 return !func.isUndefined();
377 }
378
379 if (o->_class->hasMethod)
380 return o->_class->hasMethod(o, methodName);
381
382 return false;
383 }
384
_NPN_SetException(NPObject *,const NPUTF8 * message)385 void _NPN_SetException(NPObject*, const NPUTF8* message)
386 {
387 // Ignoring the NPObject param is consistent with the Mozilla implementation.
388 UString exception(message);
389 CInstance::setGlobalException(exception);
390 }
391
_NPN_Enumerate(NPP,NPObject * o,NPIdentifier ** identifier,uint32_t * count)392 bool _NPN_Enumerate(NPP, NPObject* o, NPIdentifier** identifier, uint32_t* count)
393 {
394 if (o->_class == NPScriptObjectClass) {
395 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
396
397 RootObject* rootObject = obj->rootObject;
398 if (!rootObject || !rootObject->isValid())
399 return false;
400
401 ExecState* exec = rootObject->globalObject()->globalExec();
402 JSLock lock(SilenceAssertionsOnly);
403 PropertyNameArray propertyNames(exec);
404
405 obj->imp->getPropertyNames(exec, propertyNames);
406 unsigned size = static_cast<unsigned>(propertyNames.size());
407 // FIXME: This should really call NPN_MemAlloc but that's in WebKit
408 NPIdentifier* identifiers = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier) * size));
409
410 for (unsigned i = 0; i < size; ++i)
411 identifiers[i] = _NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().c_str());
412
413 *identifier = identifiers;
414 *count = size;
415
416 exec->clearException();
417 return true;
418 }
419
420 if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(o->_class) && o->_class->enumerate)
421 return o->_class->enumerate(o, identifier, count);
422
423 return false;
424 }
425
_NPN_Construct(NPP,NPObject * o,const NPVariant * args,uint32_t argCount,NPVariant * result)426 bool _NPN_Construct(NPP, NPObject* o, const NPVariant* args, uint32_t argCount, NPVariant* result)
427 {
428 if (o->_class == NPScriptObjectClass) {
429 JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o);
430
431 VOID_TO_NPVARIANT(*result);
432
433 // Lookup the constructor object.
434 RootObject* rootObject = obj->rootObject;
435 if (!rootObject || !rootObject->isValid())
436 return false;
437
438 ExecState* exec = rootObject->globalObject()->globalExec();
439 JSLock lock(SilenceAssertionsOnly);
440
441 // Call the constructor object.
442 JSValue constructor = obj->imp;
443 ConstructData constructData;
444 ConstructType constructType = constructor.getConstructData(constructData);
445 if (constructType == ConstructTypeNone)
446 return false;
447
448 MarkedArgumentBuffer argList;
449 getListFromVariantArgs(exec, args, argCount, rootObject, argList);
450 ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
451 globalObject->globalData()->timeoutChecker.start();
452 JSValue resultV = JSC::construct(exec, constructor, constructType, constructData, argList);
453 globalObject->globalData()->timeoutChecker.stop();
454
455 // Convert and return the result.
456 convertValueToNPVariant(exec, resultV, result);
457 exec->clearException();
458 return true;
459 }
460
461 if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(o->_class) && o->_class->construct)
462 return o->_class->construct(o, args, argCount, result);
463
464 return false;
465 }
466
467 #endif // ENABLE(NETSCAPE_PLUGIN_API)
468