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 52using namespace WebCore; 53 54namespace JSC { 55namespace Bindings { 56 57using JSC::UString; 58 59static JSC::UString& globalExceptionString() 60{ 61 DEFINE_STATIC_LOCAL(JSC::UString, exceptionStr, ()); 62 return exceptionStr; 63} 64 65void CInstance::setGlobalException(UString exception) 66{ 67 globalExceptionString() = exception; 68} 69 70void 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 83CInstance::CInstance(NPObject* o, PassRefPtr<RootObject> rootObject) 84 : Instance(rootObject) 85{ 86 _object = _NPN_RetainObject(o); 87 _class = 0; 88} 89 90CInstance::~CInstance() 91{ 92 _NPN_ReleaseObject(_object); 93} 94 95RuntimeObject* CInstance::newRuntimeObject(ExecState* exec) 96{ 97 return new (exec) CRuntimeObject(exec, exec->lexicalGlobalObject(), this); 98} 99 100Class *CInstance::getClass() const 101{ 102 if (!_class) 103 _class = CClass::classForIsA(_object->_class); 104 return _class; 105} 106 107bool CInstance::supportsInvokeDefaultMethod() const 108{ 109 return _object->_class->invokeDefault; 110} 111 112class CRuntimeMethod : public RuntimeMethod { 113public: 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 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 130const ClassInfo CRuntimeMethod::s_info = { "CRuntimeMethod", &RuntimeMethod::s_info, 0, 0 }; 131 132JSValue 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 138JSValue 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 186JSValue 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 220bool CInstance::supportsConstruct() const 221{ 222 return _object->_class->construct; 223} 224 225JSValue 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 259JSValue 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 268JSValue 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 275JSValue CInstance::numberValue(ExecState*) const 276{ 277 // FIXME: Implement something sensible. 278 return jsNumber(0); 279} 280 281JSValue CInstance::booleanValue() const 282{ 283 // FIXME: Implement something sensible. 284 return jsBoolean(false); 285} 286 287JSValue CInstance::valueOf(ExecState* exec) const 288{ 289 return stringValue(exec); 290} 291 292void 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