1/* 2 * Copyright (C) 2010 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. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "NPRuntimeObjectMap.h" 28 29#include "JSNPObject.h" 30#include "NPJSObject.h" 31#include "NPRuntimeUtilities.h" 32#include "PluginView.h" 33#include <JavaScriptCore/Error.h> 34#include <JavaScriptCore/JSLock.h> 35#include <JavaScriptCore/SourceCode.h> 36#include <JavaScriptCore/Strong.h> 37#include <WebCore/Frame.h> 38#include <WebCore/NotImplemented.h> 39 40using namespace JSC; 41using namespace WebCore; 42 43namespace WebKit { 44 45 46NPRuntimeObjectMap::NPRuntimeObjectMap(PluginView* pluginView) 47 : m_pluginView(pluginView) 48{ 49} 50 51NPRuntimeObjectMap::PluginProtector::PluginProtector(NPRuntimeObjectMap* npRuntimeObjectMap) 52{ 53 // If we're already in the plug-in view destructor, we shouldn't try to keep it alive. 54 if (!npRuntimeObjectMap->m_pluginView->isBeingDestroyed()) 55 m_pluginView = npRuntimeObjectMap->m_pluginView; 56} 57 58NPRuntimeObjectMap::PluginProtector::~PluginProtector() 59{ 60} 61 62NPObject* NPRuntimeObjectMap::getOrCreateNPObject(JSGlobalData& globalData, JSObject* jsObject) 63{ 64 // If this is a JSNPObject, we can just get its underlying NPObject. 65 if (jsObject->classInfo() == &JSNPObject::s_info) { 66 JSNPObject* jsNPObject = static_cast<JSNPObject*>(jsObject); 67 NPObject* npObject = jsNPObject->npObject(); 68 69 retainNPObject(npObject); 70 return npObject; 71 } 72 73 // First, check if we already know about this object. 74 if (NPJSObject* npJSObject = m_npJSObjects.get(jsObject)) { 75 retainNPObject(npJSObject); 76 return npJSObject; 77 } 78 79 NPJSObject* npJSObject = NPJSObject::create(globalData, this, jsObject); 80 m_npJSObjects.set(jsObject, npJSObject); 81 82 return npJSObject; 83} 84 85void NPRuntimeObjectMap::npJSObjectDestroyed(NPJSObject* npJSObject) 86{ 87 // Remove the object from the map. 88 ASSERT(m_npJSObjects.contains(npJSObject->jsObject())); 89 m_npJSObjects.remove(npJSObject->jsObject()); 90} 91 92JSObject* NPRuntimeObjectMap::getOrCreateJSObject(JSGlobalObject* globalObject, NPObject* npObject) 93{ 94 // If this is an NPJSObject, we can just get the JSObject that it's wrapping. 95 if (NPJSObject::isNPJSObject(npObject)) 96 return NPJSObject::toNPJSObject(npObject)->jsObject(); 97 98 if (JSNPObject* jsNPObject = m_jsNPObjects.get(npObject)) 99 return jsNPObject; 100 101 JSNPObject* jsNPObject = new (&globalObject->globalData()) JSNPObject(globalObject, this, npObject); 102 m_jsNPObjects.set(npObject, jsNPObject); 103 104 return jsNPObject; 105} 106 107void NPRuntimeObjectMap::jsNPObjectDestroyed(JSNPObject* jsNPObject) 108{ 109 // Remove the object from the map. 110 ASSERT(m_jsNPObjects.contains(jsNPObject->npObject())); 111 m_jsNPObjects.remove(jsNPObject->npObject()); 112} 113 114JSValue NPRuntimeObjectMap::convertNPVariantToJSValue(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, const NPVariant& variant) 115{ 116 switch (variant.type) { 117 case NPVariantType_Void: 118 return jsUndefined(); 119 120 case NPVariantType_Null: 121 return jsNull(); 122 123 case NPVariantType_Bool: 124 return jsBoolean(variant.value.boolValue); 125 126 case NPVariantType_Int32: 127 return jsNumber(variant.value.intValue); 128 129 case NPVariantType_Double: 130 return jsNumber(variant.value.doubleValue); 131 132 case NPVariantType_String: 133 return jsString(exec, String::fromUTF8WithLatin1Fallback(variant.value.stringValue.UTF8Characters, 134 variant.value.stringValue.UTF8Length)); 135 case NPVariantType_Object: 136 return getOrCreateJSObject(globalObject, variant.value.objectValue); 137 } 138 139 ASSERT_NOT_REACHED(); 140 return jsUndefined(); 141} 142 143void NPRuntimeObjectMap::convertJSValueToNPVariant(ExecState* exec, JSValue value, NPVariant& variant) 144{ 145 JSLock lock(SilenceAssertionsOnly); 146 147 VOID_TO_NPVARIANT(variant); 148 149 if (value.isNull()) { 150 NULL_TO_NPVARIANT(variant); 151 return; 152 } 153 154 if (value.isUndefined()) { 155 VOID_TO_NPVARIANT(variant); 156 return; 157 } 158 159 if (value.isBoolean()) { 160 BOOLEAN_TO_NPVARIANT(value.toBoolean(exec), variant); 161 return; 162 } 163 164 if (value.isNumber()) { 165 DOUBLE_TO_NPVARIANT(value.toNumber(exec), variant); 166 return; 167 } 168 169 if (value.isString()) { 170 NPString npString = createNPString(value.toString(exec).utf8()); 171 STRINGN_TO_NPVARIANT(npString.UTF8Characters, npString.UTF8Length, variant); 172 return; 173 } 174 175 if (value.isObject()) { 176 NPObject* npObject = getOrCreateNPObject(exec->globalData(), asObject(value)); 177 OBJECT_TO_NPVARIANT(npObject, variant); 178 return; 179 } 180 181 ASSERT_NOT_REACHED(); 182} 183 184bool NPRuntimeObjectMap::evaluate(NPObject* npObject, const String&scriptString, NPVariant* result) 185{ 186 Strong<JSGlobalObject> globalObject(this->globalObject()->globalData(), this->globalObject()); 187 if (!globalObject) 188 return false; 189 190 ExecState* exec = globalObject->globalExec(); 191 192 JSLock lock(SilenceAssertionsOnly); 193 JSValue thisValue = getOrCreateJSObject(globalObject.get(), npObject); 194 195 globalObject->globalData().timeoutChecker.start(); 196 Completion completion = JSC::evaluate(exec, globalObject->globalScopeChain(), makeSource(UString(scriptString.impl())), thisValue); 197 globalObject->globalData().timeoutChecker.stop(); 198 199 ComplType completionType = completion.complType(); 200 201 JSValue resultValue; 202 if (completionType == Normal) { 203 resultValue = completion.value(); 204 if (!resultValue) 205 resultValue = jsUndefined(); 206 } else 207 resultValue = jsUndefined(); 208 209 exec->clearException(); 210 211 convertJSValueToNPVariant(exec, resultValue, *result); 212 return true; 213} 214 215void NPRuntimeObjectMap::invalidate() 216{ 217 Vector<NPJSObject*> npJSObjects; 218 copyValuesToVector(m_npJSObjects, npJSObjects); 219 220 // Deallocate all the object wrappers so we won't leak any JavaScript objects. 221 for (size_t i = 0; i < npJSObjects.size(); ++i) 222 deallocateNPObject(npJSObjects[i]); 223 224 // We shouldn't have any NPJSObjects left now. 225 ASSERT(m_npJSObjects.isEmpty()); 226 227 Vector<JSNPObject*> jsNPObjects; 228 copyValuesToVector(m_jsNPObjects, jsNPObjects); 229 230 // Invalidate all the JSObjects that wrap NPObjects. 231 for (size_t i = 0; i < jsNPObjects.size(); ++i) 232 jsNPObjects[i]->invalidate(); 233 234 m_jsNPObjects.clear(); 235} 236 237JSGlobalObject* NPRuntimeObjectMap::globalObject() const 238{ 239 Frame* frame = m_pluginView->frame(); 240 if (!frame) 241 return 0; 242 243 return frame->script()->globalObject(pluginWorld()); 244} 245 246ExecState* NPRuntimeObjectMap::globalExec() const 247{ 248 JSGlobalObject* globalObject = this->globalObject(); 249 if (!globalObject) 250 return 0; 251 252 return globalObject->globalExec(); 253} 254 255static String& globalExceptionString() 256{ 257 DEFINE_STATIC_LOCAL(String, exceptionString, ()); 258 return exceptionString; 259} 260 261void NPRuntimeObjectMap::setGlobalException(const String& exceptionString) 262{ 263 globalExceptionString() = exceptionString; 264} 265 266void NPRuntimeObjectMap::moveGlobalExceptionToExecState(ExecState* exec) 267{ 268 if (globalExceptionString().isNull()) 269 return; 270 271 { 272 JSLock lock(SilenceAssertionsOnly); 273 throwError(exec, createError(exec, stringToUString(globalExceptionString()))); 274 } 275 276 globalExceptionString() = String(); 277} 278 279} // namespace WebKit 280