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 40 using namespace JSC; 41 using namespace WebCore; 42 43 namespace WebKit { 44 45 46 NPRuntimeObjectMap::NPRuntimeObjectMap(PluginView* pluginView) 47 : m_pluginView(pluginView) 48 { 49 } 50 51 NPRuntimeObjectMap::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 58 NPRuntimeObjectMap::PluginProtector::~PluginProtector() 59 { 60 } 61 62 NPObject* 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 85 void 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 92 JSObject* 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 107 void 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 114 JSValue 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 143 void 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 184 bool 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 215 void 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 237 JSGlobalObject* 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 246 ExecState* NPRuntimeObjectMap::globalExec() const 247 { 248 JSGlobalObject* globalObject = this->globalObject(); 249 if (!globalObject) 250 return 0; 251 252 return globalObject->globalExec(); 253 } 254 255 static String& globalExceptionString() 256 { 257 DEFINE_STATIC_LOCAL(String, exceptionString, ()); 258 return exceptionString; 259 } 260 261 void NPRuntimeObjectMap::setGlobalException(const String& exceptionString) 262 { 263 globalExceptionString() = exceptionString; 264 } 265 266 void 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