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 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 60 static NPObject* jsAllocate(NPP, NPClass*) 61 { 62 return static_cast<NPObject*>(malloc(sizeof(JavaScriptObject))); 63 } 64 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 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 97 NPObject* _NPN_CreateNoScriptObject(void) 98 { 99 return _NPN_CreateObject(0, NPNoScriptObjectClass); 100 } 101 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 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 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 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 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 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 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 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 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 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 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