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 "NPRemoteObjectMap.h"
28
29#if ENABLE(PLUGIN_PROCESS)
30
31#include "NPObjectMessageReceiver.h"
32#include "NPObjectProxy.h"
33#include "NPRuntimeUtilities.h"
34#include "NPVariantData.h"
35#include <wtf/OwnPtr.h>
36
37namespace WebKit {
38
39static uint64_t generateNPObjectID()
40{
41    static uint64_t generateNPObjectID;
42    return ++generateNPObjectID;
43}
44
45PassRefPtr<NPRemoteObjectMap> NPRemoteObjectMap::create(CoreIPC::Connection* connection)
46{
47    return adoptRef(new NPRemoteObjectMap(connection));
48}
49
50NPRemoteObjectMap::NPRemoteObjectMap(CoreIPC::Connection* connection)
51    : m_connection(connection)
52{
53}
54
55NPRemoteObjectMap::~NPRemoteObjectMap()
56{
57    ASSERT(m_npObjectProxies.isEmpty());
58    ASSERT(m_registeredNPObjects.isEmpty());
59}
60
61NPObject* NPRemoteObjectMap::createNPObjectProxy(uint64_t remoteObjectID, Plugin* plugin)
62{
63    NPObjectProxy* npObjectProxy = NPObjectProxy::create(this, plugin, remoteObjectID);
64
65    m_npObjectProxies.add(npObjectProxy);
66
67    return npObjectProxy;
68}
69
70void NPRemoteObjectMap::npObjectProxyDestroyed(NPObject* npObject)
71{
72    NPObjectProxy* npObjectProxy = NPObjectProxy::toNPObjectProxy(npObject);
73    ASSERT(m_npObjectProxies.contains(npObjectProxy));
74
75    m_npObjectProxies.remove(npObjectProxy);
76}
77
78uint64_t NPRemoteObjectMap::registerNPObject(NPObject* npObject, Plugin* plugin)
79{
80    uint64_t npObjectID = generateNPObjectID();
81    m_registeredNPObjects.set(npObjectID, NPObjectMessageReceiver::create(this, plugin, npObjectID, npObject).leakPtr());
82
83    return npObjectID;
84}
85
86void NPRemoteObjectMap::unregisterNPObject(uint64_t npObjectID)
87{
88    m_registeredNPObjects.remove(npObjectID);
89}
90
91static uint64_t remoteNPObjectID(Plugin* plugin, NPObject* npObject)
92{
93    if (!NPObjectProxy::isNPObjectProxy(npObject))
94        return 0;
95
96    NPObjectProxy* npObjectProxy = NPObjectProxy::toNPObjectProxy(npObject);
97    if (npObjectProxy->plugin() != plugin)
98        return 0;
99
100    return npObjectProxy->npObjectID();
101}
102
103NPVariantData NPRemoteObjectMap::npVariantToNPVariantData(const NPVariant& variant, Plugin* plugin)
104{
105    switch (variant.type) {
106    case NPVariantType_Void:
107        return NPVariantData::makeVoid();
108
109    case NPVariantType_Null:
110        return NPVariantData::makeNull();
111
112    case NPVariantType_Bool:
113        return NPVariantData::makeBool(variant.value.boolValue);
114
115    case NPVariantType_Int32:
116        return NPVariantData::makeInt32(variant.value.intValue);
117
118    case NPVariantType_Double:
119        return NPVariantData::makeDouble(variant.value.doubleValue);
120
121    case NPVariantType_String:
122        return NPVariantData::makeString(variant.value.stringValue.UTF8Characters, variant.value.stringValue.UTF8Length);
123
124    case NPVariantType_Object: {
125        NPObject* npObject = variant.value.objectValue;
126
127        if (uint64_t npObjectID = remoteNPObjectID(plugin, npObject)) {
128            // FIXME: Under some circumstances, this might leak the NPObjectProxy object.
129            // Figure out how to avoid that.
130            retainNPObject(npObject);
131            return NPVariantData::makeRemoteNPObjectID(npObjectID);
132        }
133
134        uint64_t npObjectID = registerNPObject(npObject, plugin);
135        return NPVariantData::makeLocalNPObjectID(npObjectID);
136    }
137
138    }
139
140    ASSERT_NOT_REACHED();
141    return NPVariantData::makeVoid();
142}
143
144NPVariant NPRemoteObjectMap::npVariantDataToNPVariant(const NPVariantData& npVariantData, Plugin* plugin)
145{
146    NPVariant npVariant;
147
148    switch (npVariantData.type()) {
149    case NPVariantData::Void:
150        VOID_TO_NPVARIANT(npVariant);
151        break;
152    case NPVariantData::Null:
153        NULL_TO_NPVARIANT(npVariant);
154        break;
155    case NPVariantData::Bool:
156        BOOLEAN_TO_NPVARIANT(npVariantData.boolValue(), npVariant);
157        break;
158    case NPVariantData::Int32:
159        INT32_TO_NPVARIANT(npVariantData.int32Value(), npVariant);
160        break;
161    case NPVariantData::Double:
162        DOUBLE_TO_NPVARIANT(npVariantData.doubleValue(), npVariant);
163        break;
164    case NPVariantData::String: {
165        NPString npString = createNPString(npVariantData.stringValue());
166        STRINGN_TO_NPVARIANT(npString.UTF8Characters, npString.UTF8Length, npVariant);
167        break;
168    }
169    case NPVariantData::LocalNPObjectID: {
170        uint64_t npObjectID = npVariantData.localNPObjectIDValue();
171        ASSERT(npObjectID);
172
173        NPObjectMessageReceiver* npObjectMessageReceiver = m_registeredNPObjects.get(npObjectID);
174        if (!npObjectMessageReceiver) {
175            ASSERT_NOT_REACHED();
176            VOID_TO_NPVARIANT(npVariant);
177            break;
178        }
179
180        NPObject* npObject = npObjectMessageReceiver->npObject();
181        ASSERT(npObject);
182
183        retainNPObject(npObject);
184        OBJECT_TO_NPVARIANT(npObject, npVariant);
185        break;
186    }
187    case NPVariantData::RemoteNPObjectID: {
188        NPObject* npObjectProxy = createNPObjectProxy(npVariantData.remoteNPObjectIDValue(), plugin);
189        OBJECT_TO_NPVARIANT(npObjectProxy, npVariant);
190        break;
191    }
192    }
193
194    return npVariant;
195}
196
197void NPRemoteObjectMap::pluginDestroyed(Plugin* plugin)
198{
199    Vector<NPObjectMessageReceiver*> messageReceivers;
200
201    // Gather the receivers associated with this plug-in.
202    for (HashMap<uint64_t, NPObjectMessageReceiver*>::const_iterator it = m_registeredNPObjects.begin(), end = m_registeredNPObjects.end(); it != end; ++it) {
203        NPObjectMessageReceiver* npObjectMessageReceiver = it->value;
204        if (npObjectMessageReceiver->plugin() == plugin)
205            messageReceivers.append(npObjectMessageReceiver);
206    }
207
208    // Now delete all the receivers.
209    deleteAllValues(messageReceivers);
210
211    Vector<NPObjectProxy*> objectProxies;
212    for (HashSet<NPObjectProxy*>::const_iterator it = m_npObjectProxies.begin(), end = m_npObjectProxies.end(); it != end; ++it) {
213        NPObjectProxy* npObjectProxy = *it;
214
215        if (npObjectProxy->plugin() == plugin)
216            objectProxies.append(npObjectProxy);
217    }
218
219    // Invalidate and remove all proxies associated with this plug-in.
220    for (size_t i = 0; i < objectProxies.size(); ++i) {
221        NPObjectProxy* npObjectProxy = objectProxies[i];
222
223        npObjectProxy->invalidate();
224
225        ASSERT(m_npObjectProxies.contains(npObjectProxy));
226        m_npObjectProxies.remove(npObjectProxy);
227    }
228}
229
230void NPRemoteObjectMap::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder, OwnPtr<CoreIPC::MessageEncoder>& replyEncoder)
231{
232    NPObjectMessageReceiver* messageReceiver = m_registeredNPObjects.get(decoder.destinationID());
233    if (!messageReceiver)
234        return;
235
236    messageReceiver->didReceiveSyncNPObjectMessageReceiverMessage(connection, decoder, replyEncoder);
237}
238
239} // namespace WebKit
240
241#endif // ENABLE(PLUGIN_PROCESS)
242