1/* 2 * Copyright (C) 2008 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#if USE(PLUGIN_HOST_PROCESS) 27 28#import "ProxyInstance.h" 29 30#import "NetscapePluginHostProxy.h" 31#import "NetscapePluginInstanceProxy.h" 32#import <runtime/PropertyNameArray.h> 33#import <WebCore/IdentifierRep.h> 34#import <WebCore/JSDOMWindow.h> 35#import <WebCore/npruntime_impl.h> 36 37extern "C" { 38#import "WebKitPluginHost.h" 39} 40 41using namespace JSC; 42using namespace JSC::Bindings; 43using namespace std; 44using namespace WebCore; 45 46namespace WebKit { 47 48class ProxyClass : public JSC::Bindings::Class { 49private: 50 virtual MethodList methodsNamed(const Identifier&, Instance*) const; 51 virtual Field* fieldNamed(const Identifier&, Instance*) const; 52}; 53 54MethodList ProxyClass::methodsNamed(const Identifier& identifier, Instance* instance) const 55{ 56 return static_cast<ProxyInstance*>(instance)->methodsNamed(identifier); 57} 58 59Field* ProxyClass::fieldNamed(const Identifier& identifier, Instance* instance) const 60{ 61 return static_cast<ProxyInstance*>(instance)->fieldNamed(identifier); 62} 63 64static ProxyClass* proxyClass() 65{ 66 DEFINE_STATIC_LOCAL(ProxyClass, proxyClass, ()); 67 return &proxyClass; 68} 69 70class ProxyField : public JSC::Bindings::Field { 71public: 72 ProxyField(uint64_t serverIdentifier) 73 : m_serverIdentifier(serverIdentifier) 74 { 75 } 76 77 uint64_t serverIdentifier() const { return m_serverIdentifier; } 78 79private: 80 virtual JSValue valueFromInstance(ExecState*, const Instance*) const; 81 virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const; 82 83 uint64_t m_serverIdentifier; 84}; 85 86JSValue ProxyField::valueFromInstance(ExecState* exec, const Instance* instance) const 87{ 88 return static_cast<const ProxyInstance*>(instance)->fieldValue(exec, this); 89} 90 91void ProxyField::setValueToInstance(ExecState* exec, const Instance* instance, JSValue value) const 92{ 93 static_cast<const ProxyInstance*>(instance)->setFieldValue(exec, this, value); 94} 95 96class ProxyMethod : public JSC::Bindings::Method { 97public: 98 ProxyMethod(uint64_t serverIdentifier) 99 : m_serverIdentifier(serverIdentifier) 100 { 101 } 102 103 uint64_t serverIdentifier() const { return m_serverIdentifier; } 104 105private: 106 virtual int numParameters() const { return 0; } 107 108 uint64_t m_serverIdentifier; 109}; 110 111ProxyInstance::ProxyInstance(PassRefPtr<RootObject> rootObject, NetscapePluginInstanceProxy* instanceProxy, uint32_t objectID) 112 : Instance(rootObject) 113 , m_instanceProxy(instanceProxy) 114 , m_objectID(objectID) 115{ 116 m_instanceProxy->addInstance(this); 117} 118 119ProxyInstance::~ProxyInstance() 120{ 121 deleteAllValues(m_fields); 122 deleteAllValues(m_methods); 123 124 if (!m_instanceProxy) 125 return; 126 127 m_instanceProxy->removeInstance(this); 128 129 invalidate(); 130} 131 132JSC::Bindings::Class *ProxyInstance::getClass() const 133{ 134 return proxyClass(); 135} 136 137JSValue ProxyInstance::invoke(JSC::ExecState* exec, InvokeType type, uint64_t identifier, const JSC::ArgList& args) 138{ 139 RetainPtr<NSData*> arguments(m_instanceProxy->marshalValues(exec, args)); 140 141 uint32_t requestID = m_instanceProxy->nextRequestID(); 142 143 if (_WKPHNPObjectInvoke(m_instanceProxy->hostProxy()->port(), m_instanceProxy->pluginID(), requestID, m_objectID, 144 type, identifier, (char*)[arguments.get() bytes], [arguments.get() length]) != KERN_SUCCESS) 145 return jsUndefined(); 146 147 auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); 148 if (!reply.get() || !reply->m_returnValue) 149 return jsUndefined(); 150 151 return m_instanceProxy->demarshalValue(exec, (char*)CFDataGetBytePtr(reply->m_result.get()), CFDataGetLength(reply->m_result.get())); 152} 153 154JSValue ProxyInstance::invokeMethod(ExecState* exec, const MethodList& methodList, const ArgList& args) 155{ 156 ASSERT(methodList.size() == 1); 157 158 ProxyMethod* method = static_cast<ProxyMethod*>(methodList[0]); 159 160 return invoke(exec, Invoke, method->serverIdentifier(), args); 161} 162 163bool ProxyInstance::supportsInvokeDefaultMethod() const 164{ 165 uint32_t requestID = m_instanceProxy->nextRequestID(); 166 167 if (_WKPHNPObjectHasInvokeDefaultMethod(m_instanceProxy->hostProxy()->port(), 168 m_instanceProxy->pluginID(), requestID, 169 m_objectID) != KERN_SUCCESS) 170 return false; 171 172 auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); 173 if (reply.get() && reply->m_result) 174 return true; 175 176 return false; 177} 178 179JSValue ProxyInstance::invokeDefaultMethod(ExecState* exec, const ArgList& args) 180{ 181 return invoke(exec, InvokeDefault, 0, args); 182} 183 184bool ProxyInstance::supportsConstruct() const 185{ 186 uint32_t requestID = m_instanceProxy->nextRequestID(); 187 188 if (_WKPHNPObjectHasConstructMethod(m_instanceProxy->hostProxy()->port(), 189 m_instanceProxy->pluginID(), requestID, 190 m_objectID) != KERN_SUCCESS) 191 return false; 192 193 auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); 194 if (reply.get() && reply->m_result) 195 return true; 196 197 return false; 198} 199 200JSValue ProxyInstance::invokeConstruct(ExecState* exec, const ArgList& args) 201{ 202 return invoke(exec, Construct, 0, args); 203} 204 205JSValue ProxyInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const 206{ 207 if (hint == PreferString) 208 return stringValue(exec); 209 if (hint == PreferNumber) 210 return numberValue(exec); 211 return valueOf(exec); 212} 213 214JSValue ProxyInstance::stringValue(ExecState* exec) const 215{ 216 // FIXME: Implement something sensible. 217 return jsString(exec, ""); 218} 219 220JSValue ProxyInstance::numberValue(ExecState* exec) const 221{ 222 // FIXME: Implement something sensible. 223 return jsNumber(exec, 0); 224} 225 226JSValue ProxyInstance::booleanValue() const 227{ 228 // FIXME: Implement something sensible. 229 return jsBoolean(false); 230} 231 232JSValue ProxyInstance::valueOf(ExecState* exec) const 233{ 234 return stringValue(exec); 235} 236 237void ProxyInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArray) 238{ 239 uint32_t requestID = m_instanceProxy->nextRequestID(); 240 241 if (_WKPHNPObjectEnumerate(m_instanceProxy->hostProxy()->port(), m_instanceProxy->pluginID(), requestID, m_objectID) != KERN_SUCCESS) 242 return; 243 244 auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); 245 246 if (!reply.get() || !reply->m_returnValue) 247 return; 248 249 RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:(NSData *)reply->m_result.get() 250 mutabilityOption:NSPropertyListImmutable 251 format:0 252 errorDescription:0]; 253 254 for (NSNumber *number in array.get()) { 255 IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>([number longLongValue]); 256 if (!IdentifierRep::isValid(identifier)) 257 continue; 258 259 if (identifier->isString()) { 260 const char* str = identifier->string(); 261 nameArray.add(Identifier(JSDOMWindow::commonJSGlobalData(), String::fromUTF8WithLatin1Fallback(str, strlen(str)))); 262 } else 263 nameArray.add(Identifier::from(exec, identifier->number())); 264 } 265} 266 267MethodList ProxyInstance::methodsNamed(const Identifier& identifier) 268{ 269 // If we already have an entry in the map, use it. 270 MethodMap::iterator existingMapEntry = m_methods.find(identifier.ustring().rep()); 271 if (existingMapEntry != m_methods.end()) { 272 MethodList methodList; 273 if (existingMapEntry->second) 274 methodList.append(existingMapEntry->second); 275 return methodList; 276 } 277 278 uint64_t methodName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(identifier.ascii())); 279 uint32_t requestID = m_instanceProxy->nextRequestID(); 280 281 if (_WKPHNPObjectHasMethod(m_instanceProxy->hostProxy()->port(), 282 m_instanceProxy->pluginID(), requestID, 283 m_objectID, methodName) != KERN_SUCCESS) 284 return MethodList(); 285 286 auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); 287 if (!reply.get()) 288 return MethodList(); 289 290 if (!reply->m_result && !m_instanceProxy->hostProxy()->shouldCacheMissingPropertiesAndMethods()) 291 return MethodList(); 292 293 // Add a new entry to the map unless an entry was added while we were in waitForReply. 294 pair<MethodMap::iterator, bool> mapAddResult = m_methods.add(identifier.ustring().rep(), 0); 295 if (mapAddResult.second && reply->m_result) 296 mapAddResult.first->second = new ProxyMethod(methodName); 297 298 MethodList methodList; 299 if (mapAddResult.first->second) 300 methodList.append(mapAddResult.first->second); 301 return methodList; 302} 303 304Field* ProxyInstance::fieldNamed(const Identifier& identifier) 305{ 306 // If we already have an entry in the map, use it. 307 FieldMap::iterator existingMapEntry = m_fields.find(identifier.ustring().rep()); 308 if (existingMapEntry != m_fields.end()) 309 return existingMapEntry->second; 310 311 uint64_t propertyName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(identifier.ascii())); 312 uint32_t requestID = m_instanceProxy->nextRequestID(); 313 314 if (_WKPHNPObjectHasProperty(m_instanceProxy->hostProxy()->port(), 315 m_instanceProxy->pluginID(), requestID, 316 m_objectID, propertyName) != KERN_SUCCESS) 317 return 0; 318 319 auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); 320 if (!reply.get()) 321 return 0; 322 323 if (!reply->m_result && !m_instanceProxy->hostProxy()->shouldCacheMissingPropertiesAndMethods()) 324 return 0; 325 326 // Add a new entry to the map unless an entry was added while we were in waitForReply. 327 pair<FieldMap::iterator, bool> mapAddResult = m_fields.add(identifier.ustring().rep(), 0); 328 if (mapAddResult.second && reply->m_result) 329 mapAddResult.first->second = new ProxyField(propertyName); 330 return mapAddResult.first->second; 331} 332 333JSC::JSValue ProxyInstance::fieldValue(ExecState* exec, const Field* field) const 334{ 335 uint64_t serverIdentifier = static_cast<const ProxyField*>(field)->serverIdentifier(); 336 uint32_t requestID = m_instanceProxy->nextRequestID(); 337 338 if (_WKPHNPObjectGetProperty(m_instanceProxy->hostProxy()->port(), 339 m_instanceProxy->pluginID(), requestID, 340 m_objectID, serverIdentifier) != KERN_SUCCESS) 341 return jsUndefined(); 342 343 auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); 344 if (!reply.get() || !reply->m_returnValue) 345 return jsUndefined(); 346 347 return m_instanceProxy->demarshalValue(exec, (char*)CFDataGetBytePtr(reply->m_result.get()), CFDataGetLength(reply->m_result.get())); 348} 349 350void ProxyInstance::setFieldValue(ExecState* exec, const Field* field, JSValue value) const 351{ 352 uint64_t serverIdentifier = static_cast<const ProxyField*>(field)->serverIdentifier(); 353 uint32_t requestID = m_instanceProxy->nextRequestID(); 354 355 data_t valueData; 356 mach_msg_type_number_t valueLength; 357 358 m_instanceProxy->marshalValue(exec, value, valueData, valueLength); 359 kern_return_t kr = _WKPHNPObjectSetProperty(m_instanceProxy->hostProxy()->port(), 360 m_instanceProxy->pluginID(), requestID, 361 m_objectID, serverIdentifier, valueData, valueLength); 362 mig_deallocate(reinterpret_cast<vm_address_t>(valueData), valueLength); 363 if (kr != KERN_SUCCESS) 364 return; 365 366 auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); 367} 368 369void ProxyInstance::invalidate() 370{ 371 if (NetscapePluginHostProxy* hostProxy = m_instanceProxy->hostProxy()) 372 _WKPHNPObjectRelease(hostProxy->port(), 373 m_instanceProxy->pluginID(), m_objectID); 374 m_instanceProxy = 0; 375} 376 377} // namespace WebKit 378 379#endif // USE(PLUGIN_HOST_PROCESS) 380 381