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