2
* Copyright (C) 2010 Apple Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
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.
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.
27
#include "NPRuntimeObjectMap.h"
29
#if ENABLE(NETSCAPE_PLUGIN_API)
31
#include "JSNPObject.h"
32
#include "NPJSObject.h"
33
#include "NPRuntimeUtilities.h"
34
#include "PluginView.h"
35
#include "WebProcess.h"
36
#include <JavaScriptCore/Completion.h>
37
#include <JavaScriptCore/Error.h>
38
#include <JavaScriptCore/JSLock.h>
39
#include <JavaScriptCore/SourceCode.h>
40
#include <JavaScriptCore/Strong.h>
41
#include <JavaScriptCore/StrongInlines.h>
42
#include <WebCore/Frame.h>
45
using namespace WebCore;
50
NPRuntimeObjectMap::NPRuntimeObjectMap(PluginView* pluginView)
51
: m_pluginView(pluginView)
52
, m_finalizationTimer(WebProcess::shared().runLoop(), this, &NPRuntimeObjectMap::invalidateQueuedObjects)
56
NPRuntimeObjectMap::PluginProtector::PluginProtector(NPRuntimeObjectMap* npRuntimeObjectMap)
58
// If we're already in the plug-in view destructor, we shouldn't try to keep it alive.
59
if (!npRuntimeObjectMap->m_pluginView->isBeingDestroyed())
60
m_pluginView = npRuntimeObjectMap->m_pluginView;
63
NPRuntimeObjectMap::PluginProtector::~PluginProtector()
67
NPObject* NPRuntimeObjectMap::getOrCreateNPObject(JSGlobalData& globalData, JSObject* jsObject)
69
// If this is a JSNPObject, we can just get its underlying NPObject.
70
if (jsObject->classInfo() == &JSNPObject::s_info) {
71
JSNPObject* jsNPObject = static_cast<JSNPObject*>(jsObject);
72
NPObject* npObject = jsNPObject->npObject();
74
retainNPObject(npObject);
78
// First, check if we already know about this object.
79
if (NPJSObject* npJSObject = m_npJSObjects.get(jsObject)) {
80
retainNPObject(npJSObject);
84
NPJSObject* npJSObject = NPJSObject::create(globalData, this, jsObject);
85
m_npJSObjects.set(jsObject, npJSObject);
90
void NPRuntimeObjectMap::npJSObjectDestroyed(NPJSObject* npJSObject)
92
// Remove the object from the map.
93
ASSERT(m_npJSObjects.contains(npJSObject->jsObject()));
94
m_npJSObjects.remove(npJSObject->jsObject());
97
JSObject* NPRuntimeObjectMap::getOrCreateJSObject(JSGlobalObject* globalObject, NPObject* npObject)
99
// If this is an NPJSObject, we can just get the JSObject that it's wrapping.
100
if (NPJSObject::isNPJSObject(npObject))
101
return NPJSObject::toNPJSObject(npObject)->jsObject();
103
if (JSNPObject* jsNPObject = m_jsNPObjects.get(npObject))
106
JSNPObject* jsNPObject = JSNPObject::create(globalObject, this, npObject);
107
weakAdd(m_jsNPObjects, npObject, JSC::PassWeak<JSNPObject>(jsNPObject, this, npObject));
111
JSValue NPRuntimeObjectMap::convertNPVariantToJSValue(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, const NPVariant& variant)
113
switch (variant.type) {
114
case NPVariantType_Void:
115
return jsUndefined();
117
case NPVariantType_Null:
120
case NPVariantType_Bool:
121
return jsBoolean(variant.value.boolValue);
123
case NPVariantType_Int32:
124
return jsNumber(variant.value.intValue);
126
case NPVariantType_Double:
127
return jsNumber(variant.value.doubleValue);
129
case NPVariantType_String:
130
return jsString(exec, String::fromUTF8WithLatin1Fallback(variant.value.stringValue.UTF8Characters,
131
variant.value.stringValue.UTF8Length));
132
case NPVariantType_Object:
133
return getOrCreateJSObject(globalObject, variant.value.objectValue);
136
ASSERT_NOT_REACHED();
137
return jsUndefined();
140
void NPRuntimeObjectMap::convertJSValueToNPVariant(ExecState* exec, JSValue value, NPVariant& variant)
142
JSLockHolder lock(exec);
144
VOID_TO_NPVARIANT(variant);
146
if (value.isNull()) {
147
NULL_TO_NPVARIANT(variant);
151
if (value.isUndefined()) {
152
VOID_TO_NPVARIANT(variant);
156
if (value.isBoolean()) {
157
BOOLEAN_TO_NPVARIANT(value.toBoolean(exec), variant);
161
if (value.isNumber()) {
162
DOUBLE_TO_NPVARIANT(value.toNumber(exec), variant);
166
if (value.isString()) {
167
NPString npString = createNPString(value.toString(exec)->value(exec).utf8());
168
STRINGN_TO_NPVARIANT(npString.UTF8Characters, npString.UTF8Length, variant);
172
if (value.isObject()) {
173
NPObject* npObject = getOrCreateNPObject(exec->globalData(), asObject(value));
174
OBJECT_TO_NPVARIANT(npObject, variant);
178
ASSERT_NOT_REACHED();
181
bool NPRuntimeObjectMap::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result)
183
Strong<JSGlobalObject> globalObject(this->globalObject()->globalData(), this->globalObject());
187
ExecState* exec = globalObject->globalExec();
189
JSLockHolder lock(exec);
190
JSValue thisValue = getOrCreateJSObject(globalObject.get(), npObject);
192
globalObject->globalData().timeoutChecker.start();
193
JSValue resultValue = JSC::evaluate(exec, makeSource(scriptString), thisValue);
194
globalObject->globalData().timeoutChecker.stop();
196
convertJSValueToNPVariant(exec, resultValue, *result);
200
void NPRuntimeObjectMap::invalidate()
202
Vector<NPJSObject*> npJSObjects;
203
copyValuesToVector(m_npJSObjects, npJSObjects);
205
// Deallocate all the object wrappers so we won't leak any JavaScript objects.
206
for (size_t i = 0; i < npJSObjects.size(); ++i)
207
deallocateNPObject(npJSObjects[i]);
209
// We shouldn't have any NPJSObjects left now.
210
ASSERT(m_npJSObjects.isEmpty());
212
Vector<NPObject*> objects;
214
for (HashMap<NPObject*, JSC::Weak<JSNPObject> >::iterator ptr = m_jsNPObjects.begin(), end = m_jsNPObjects.end(); ptr != end; ++ptr) {
215
JSNPObject* jsNPObject = ptr->value.get();
216
if (!jsNPObject) // Skip zombies.
218
objects.append(jsNPObject->leakNPObject());
221
m_jsNPObjects.clear();
223
for (size_t i = 0; i < objects.size(); ++i)
224
releaseNPObject(objects[i]);
226
// Deal with any objects that were scheduled for delayed destruction
227
if (m_npObjectsToFinalize.isEmpty())
229
ASSERT(m_finalizationTimer.isActive());
230
m_finalizationTimer.stop();
231
invalidateQueuedObjects();
234
JSGlobalObject* NPRuntimeObjectMap::globalObject() const
236
Frame* frame = m_pluginView->frame();
240
return frame->script()->globalObject(pluginWorld());
243
ExecState* NPRuntimeObjectMap::globalExec() const
245
JSGlobalObject* globalObject = this->globalObject();
249
return globalObject->globalExec();
252
static String& globalExceptionString()
254
DEFINE_STATIC_LOCAL(String, exceptionString, ());
255
return exceptionString;
258
void NPRuntimeObjectMap::setGlobalException(const String& exceptionString)
260
globalExceptionString() = exceptionString;
263
void NPRuntimeObjectMap::moveGlobalExceptionToExecState(ExecState* exec)
265
if (globalExceptionString().isNull())
269
JSLockHolder lock(exec);
270
throwError(exec, createError(exec, globalExceptionString()));
273
globalExceptionString() = String();
276
void NPRuntimeObjectMap::invalidateQueuedObjects()
278
ASSERT(m_npObjectsToFinalize.size());
279
// We deliberately re-request m_npObjectsToFinalize.size() as custom dealloc
280
// functions may execute JS and so get more objects added to the dealloc queue
281
for (size_t i = 0; i < m_npObjectsToFinalize.size(); ++i)
282
deallocateNPObject(m_npObjectsToFinalize[i]);
283
m_npObjectsToFinalize.clear();
286
void NPRuntimeObjectMap::addToInvalidationQueue(NPObject* npObject)
288
if (trySafeReleaseNPObject(npObject))
290
if (m_npObjectsToFinalize.isEmpty())
291
m_finalizationTimer.startOneShot(0);
292
ASSERT(m_finalizationTimer.isActive());
293
m_npObjectsToFinalize.append(npObject);
296
void NPRuntimeObjectMap::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
298
JSNPObject* object = static_cast<JSNPObject*>(handle.get().asCell());
299
weakRemove(m_jsNPObjects, static_cast<NPObject*>(context), object);
300
addToInvalidationQueue(object->leakNPObject());
303
} // namespace WebKit
305
#endif // ENABLE(NETSCAPE_PLUGIN_API)