1/* 2 * Copyright (C) 2003, 2006 Apple 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 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 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 52using namespace WebCore; 53 54namespace JSC { 55namespace Bindings { 56 57static String& globalExceptionString() 58{ 59 DEPRECATED_DEFINE_STATIC_LOCAL(String, exceptionStr, ()); 60 return exceptionStr; 61} 62 63void CInstance::setGlobalException(String exception) 64{ 65 globalExceptionString() = exception; 66} 67 68void CInstance::moveGlobalExceptionToExecState(ExecState* exec) 69{ 70 if (globalExceptionString().isNull()) 71 return; 72 73 { 74 JSLockHolder lock(exec); 75 exec->vm().throwException(exec, createError(exec, globalExceptionString())); 76 } 77 78 globalExceptionString() = String(); 79} 80 81CInstance::CInstance(NPObject* o, PassRefPtr<RootObject> rootObject) 82 : Instance(rootObject) 83{ 84 _object = _NPN_RetainObject(o); 85 _class = 0; 86} 87 88CInstance::~CInstance() 89{ 90 _NPN_ReleaseObject(_object); 91} 92 93RuntimeObject* CInstance::newRuntimeObject(ExecState* exec) 94{ 95 // FIXME: deprecatedGetDOMStructure uses the prototype off of the wrong global object. 96 return CRuntimeObject::create(exec->vm(), WebCore::deprecatedGetDOMStructure<CRuntimeObject>(exec), this); 97} 98 99Class *CInstance::getClass() const 100{ 101 if (!_class) 102 _class = CClass::classForIsA(_object->_class); 103 return _class; 104} 105 106bool CInstance::supportsInvokeDefaultMethod() const 107{ 108 return _object->_class->invokeDefault; 109} 110 111class CRuntimeMethod : public RuntimeMethod { 112public: 113 typedef RuntimeMethod Base; 114 115 static CRuntimeMethod* create(ExecState* exec, JSGlobalObject* globalObject, const String& name, Bindings::Method* method) 116 { 117 // FIXME: deprecatedGetDOMStructure uses the prototype off of the wrong global object 118 // We need to pass in the right global object for "i". 119 Structure* domStructure = WebCore::deprecatedGetDOMStructure<CRuntimeMethod>(exec); 120 CRuntimeMethod* runtimeMethod = new (NotNull, allocateCell<CRuntimeMethod>(*exec->heap())) CRuntimeMethod(globalObject, domStructure, method); 121 runtimeMethod->finishCreation(exec->vm(), name); 122 return runtimeMethod; 123 } 124 125 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 126 { 127 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); 128 } 129 130 DECLARE_INFO; 131 132private: 133 CRuntimeMethod(JSGlobalObject* globalObject, Structure* structure, Bindings::Method* method) 134 : RuntimeMethod(globalObject, structure, method) 135 { 136 } 137 138 void finishCreation(VM& vm, const String& name) 139 { 140 Base::finishCreation(vm, name); 141 ASSERT(inherits(info())); 142 } 143 144}; 145 146const ClassInfo CRuntimeMethod::s_info = { "CRuntimeMethod", &RuntimeMethod::s_info, 0, 0, CREATE_METHOD_TABLE(CRuntimeMethod) }; 147 148JSValue CInstance::getMethod(ExecState* exec, PropertyName propertyName) 149{ 150 Method* method = getClass()->methodNamed(propertyName, this); 151 return CRuntimeMethod::create(exec, exec->lexicalGlobalObject(), propertyName.publicName(), method); 152} 153 154JSValue CInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod) 155{ 156 if (!asObject(runtimeMethod)->inherits(CRuntimeMethod::info())) 157 return exec->vm().throwException(exec, createTypeError(exec, "Attempt to invoke non-plug-in method on plug-in object.")); 158 159 CMethod* method = static_cast<CMethod*>(runtimeMethod->method()); 160 ASSERT(method); 161 162 NPIdentifier ident = method->identifier(); 163 if (!_object->_class->hasMethod(_object, ident)) 164 return jsUndefined(); 165 166 unsigned count = exec->argumentCount(); 167 Vector<NPVariant, 8> cArgs(count); 168 169 unsigned i; 170 for (i = 0; i < count; i++) 171 convertValueToNPVariant(exec, exec->uncheckedArgument(i), &cArgs[i]); 172 173 // Invoke the 'C' method. 174 bool retval = true; 175 NPVariant resultVariant; 176 VOID_TO_NPVARIANT(resultVariant); 177 178 { 179 JSLock::DropAllLocks dropAllLocks(exec); 180 ASSERT(globalExceptionString().isNull()); 181 retval = _object->_class->invoke(_object, ident, cArgs.data(), count, &resultVariant); 182 moveGlobalExceptionToExecState(exec); 183 } 184 185 if (!retval) 186 exec->vm().throwException(exec, createError(exec, ASCIILiteral("Error calling method on NPObject."))); 187 188 for (i = 0; i < count; i++) 189 _NPN_ReleaseVariantValue(&cArgs[i]); 190 191 JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get()); 192 _NPN_ReleaseVariantValue(&resultVariant); 193 return resultValue; 194} 195 196 197JSValue CInstance::invokeDefaultMethod(ExecState* exec) 198{ 199 if (!_object->_class->invokeDefault) 200 return jsUndefined(); 201 202 unsigned count = exec->argumentCount(); 203 Vector<NPVariant, 8> cArgs(count); 204 205 unsigned i; 206 for (i = 0; i < count; i++) 207 convertValueToNPVariant(exec, exec->uncheckedArgument(i), &cArgs[i]); 208 209 // Invoke the 'C' method. 210 bool retval = true; 211 NPVariant resultVariant; 212 VOID_TO_NPVARIANT(resultVariant); 213 { 214 JSLock::DropAllLocks dropAllLocks(exec); 215 ASSERT(globalExceptionString().isNull()); 216 retval = _object->_class->invokeDefault(_object, cArgs.data(), count, &resultVariant); 217 moveGlobalExceptionToExecState(exec); 218 } 219 220 if (!retval) 221 exec->vm().throwException(exec, createError(exec, ASCIILiteral("Error calling method on NPObject."))); 222 223 for (i = 0; i < count; i++) 224 _NPN_ReleaseVariantValue(&cArgs[i]); 225 226 JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get()); 227 _NPN_ReleaseVariantValue(&resultVariant); 228 return resultValue; 229} 230 231bool CInstance::supportsConstruct() const 232{ 233 return _object->_class->construct; 234} 235 236JSValue CInstance::invokeConstruct(ExecState* exec, const ArgList& args) 237{ 238 if (!_object->_class->construct) 239 return jsUndefined(); 240 241 unsigned count = args.size(); 242 Vector<NPVariant, 8> cArgs(count); 243 244 unsigned i; 245 for (i = 0; i < count; i++) 246 convertValueToNPVariant(exec, args.at(i), &cArgs[i]); 247 248 // Invoke the 'C' method. 249 bool retval = true; 250 NPVariant resultVariant; 251 VOID_TO_NPVARIANT(resultVariant); 252 { 253 JSLock::DropAllLocks dropAllLocks(exec); 254 ASSERT(globalExceptionString().isNull()); 255 retval = _object->_class->construct(_object, cArgs.data(), count, &resultVariant); 256 moveGlobalExceptionToExecState(exec); 257 } 258 259 if (!retval) 260 exec->vm().throwException(exec, createError(exec, ASCIILiteral("Error calling method on NPObject."))); 261 262 for (i = 0; i < count; i++) 263 _NPN_ReleaseVariantValue(&cArgs[i]); 264 265 JSValue resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get()); 266 _NPN_ReleaseVariantValue(&resultVariant); 267 return resultValue; 268} 269 270JSValue CInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const 271{ 272 if (hint == PreferString) 273 return stringValue(exec); 274 if (hint == PreferNumber) 275 return numberValue(exec); 276 return valueOf(exec); 277} 278 279JSValue CInstance::stringValue(ExecState* exec) const 280{ 281 JSValue value; 282 if (toJSPrimitive(exec, "toString", value)) 283 return value; 284 285 // Fallback to default implementation. 286 return jsNontrivialString(exec, ASCIILiteral("NPObject")); 287} 288 289JSValue CInstance::numberValue(ExecState*) const 290{ 291 // FIXME: Implement something sensible. 292 return jsNumber(0); 293} 294 295JSValue CInstance::booleanValue() const 296{ 297 // As per ECMA 9.2. 298 return jsBoolean(getObject()); 299} 300 301JSValue CInstance::valueOf(ExecState* exec) const 302{ 303 JSValue value; 304 if (toJSPrimitive(exec, "valueOf", value)) 305 return value; 306 307 // Fallback to default implementation. 308 return stringValue(exec); 309} 310 311bool CInstance::toJSPrimitive(ExecState* exec, const char* name, JSValue& resultValue) const 312{ 313 NPIdentifier ident = _NPN_GetStringIdentifier(name); 314 if (!_object->_class->hasMethod(_object, ident)) 315 return false; 316 317 // Invoke the 'C' method. 318 bool retval = true; 319 NPVariant resultVariant; 320 VOID_TO_NPVARIANT(resultVariant); 321 322 { 323 JSLock::DropAllLocks dropAllLocks(exec); 324 ASSERT(globalExceptionString().isNull()); 325 retval = _object->_class->invoke(_object, ident, 0, 0, &resultVariant); 326 moveGlobalExceptionToExecState(exec); 327 } 328 329 if (!retval) 330 exec->vm().throwException(exec, createError(exec, ASCIILiteral("Error calling method on NPObject."))); 331 332 resultValue = convertNPVariantToValue(exec, &resultVariant, m_rootObject.get()); 333 _NPN_ReleaseVariantValue(&resultVariant); 334 return true; 335} 336 337void CInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArray) 338{ 339 if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(_object->_class) || !_object->_class->enumerate) 340 return; 341 342 uint32_t count; 343 NPIdentifier* identifiers; 344 345 { 346 JSLock::DropAllLocks dropAllLocks(exec); 347 ASSERT(globalExceptionString().isNull()); 348 bool ok = _object->_class->enumerate(_object, &identifiers, &count); 349 moveGlobalExceptionToExecState(exec); 350 if (!ok) 351 return; 352 } 353 354 for (uint32_t i = 0; i < count; i++) { 355 IdentifierRep* identifier = static_cast<IdentifierRep*>(identifiers[i]); 356 357 if (identifier->isString()) 358 nameArray.add(identifierFromNPIdentifier(exec, identifier->string())); 359 else 360 nameArray.add(Identifier::from(exec, identifier->number())); 361 } 362 363 // FIXME: This should really call NPN_MemFree but that's in WebKit 364 free(identifiers); 365} 366 367} 368} 369 370#endif // ENABLE(NETSCAPE_PLUGIN_API) 371