• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NPRuntimeObjectMap(PluginView * pluginView)46 NPRuntimeObjectMap::NPRuntimeObjectMap(PluginView* pluginView)
47     : m_pluginView(pluginView)
48 {
49 }
50 
PluginProtector(NPRuntimeObjectMap * npRuntimeObjectMap)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 
~PluginProtector()58 NPRuntimeObjectMap::PluginProtector::~PluginProtector()
59 {
60 }
61 
getOrCreateNPObject(JSGlobalData & globalData,JSObject * jsObject)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 
npJSObjectDestroyed(NPJSObject * npJSObject)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 
getOrCreateJSObject(JSGlobalObject * globalObject,NPObject * npObject)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 
jsNPObjectDestroyed(JSNPObject * jsNPObject)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 
convertNPVariantToJSValue(JSC::ExecState * exec,JSC::JSGlobalObject * globalObject,const NPVariant & variant)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 
convertJSValueToNPVariant(ExecState * exec,JSValue value,NPVariant & variant)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 
evaluate(NPObject * npObject,const String & scriptString,NPVariant * result)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 
invalidate()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 
globalObject() const237 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 
globalExec() const246 ExecState* NPRuntimeObjectMap::globalExec() const
247 {
248     JSGlobalObject* globalObject = this->globalObject();
249     if (!globalObject)
250         return 0;
251 
252     return globalObject->globalExec();
253 }
254 
globalExceptionString()255 static String& globalExceptionString()
256 {
257     DEFINE_STATIC_LOCAL(String, exceptionString, ());
258     return exceptionString;
259 }
260 
setGlobalException(const String & exceptionString)261 void NPRuntimeObjectMap::setGlobalException(const String& exceptionString)
262 {
263     globalExceptionString() = exceptionString;
264 }
265 
moveGlobalExceptionToExecState(ExecState * exec)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