Home | History | Annotate | Download | only in Netscape
      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