• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2008 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#if USE(PLUGIN_HOST_PROCESS)
27
28#import "ProxyInstance.h"
29
30#import "NetscapePluginHostProxy.h"
31#import "NetscapePluginInstanceProxy.h"
32#import <runtime/PropertyNameArray.h>
33#import <WebCore/IdentifierRep.h>
34#import <WebCore/JSDOMWindow.h>
35#import <WebCore/npruntime_impl.h>
36
37extern "C" {
38#import "WebKitPluginHost.h"
39}
40
41using namespace JSC;
42using namespace JSC::Bindings;
43using namespace std;
44using namespace WebCore;
45
46namespace WebKit {
47
48class ProxyClass : public JSC::Bindings::Class {
49private:
50    virtual MethodList methodsNamed(const Identifier&, Instance*) const;
51    virtual Field* fieldNamed(const Identifier&, Instance*) const;
52};
53
54MethodList ProxyClass::methodsNamed(const Identifier& identifier, Instance* instance) const
55{
56    return static_cast<ProxyInstance*>(instance)->methodsNamed(identifier);
57}
58
59Field* ProxyClass::fieldNamed(const Identifier& identifier, Instance* instance) const
60{
61    return static_cast<ProxyInstance*>(instance)->fieldNamed(identifier);
62}
63
64static ProxyClass* proxyClass()
65{
66    DEFINE_STATIC_LOCAL(ProxyClass, proxyClass, ());
67    return &proxyClass;
68}
69
70class ProxyField : public JSC::Bindings::Field {
71public:
72    ProxyField(uint64_t serverIdentifier)
73        : m_serverIdentifier(serverIdentifier)
74    {
75    }
76
77    uint64_t serverIdentifier() const { return m_serverIdentifier; }
78
79private:
80    virtual JSValue valueFromInstance(ExecState*, const Instance*) const;
81    virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const;
82
83    uint64_t m_serverIdentifier;
84};
85
86JSValue ProxyField::valueFromInstance(ExecState* exec, const Instance* instance) const
87{
88    return static_cast<const ProxyInstance*>(instance)->fieldValue(exec, this);
89}
90
91void ProxyField::setValueToInstance(ExecState* exec, const Instance* instance, JSValue value) const
92{
93    static_cast<const ProxyInstance*>(instance)->setFieldValue(exec, this, value);
94}
95
96class ProxyMethod : public JSC::Bindings::Method {
97public:
98    ProxyMethod(uint64_t serverIdentifier)
99        : m_serverIdentifier(serverIdentifier)
100    {
101    }
102
103    uint64_t serverIdentifier() const { return m_serverIdentifier; }
104
105private:
106    virtual int numParameters() const { return 0; }
107
108    uint64_t m_serverIdentifier;
109};
110
111ProxyInstance::ProxyInstance(PassRefPtr<RootObject> rootObject, NetscapePluginInstanceProxy* instanceProxy, uint32_t objectID)
112    : Instance(rootObject)
113    , m_instanceProxy(instanceProxy)
114    , m_objectID(objectID)
115{
116    m_instanceProxy->addInstance(this);
117}
118
119ProxyInstance::~ProxyInstance()
120{
121    deleteAllValues(m_fields);
122    deleteAllValues(m_methods);
123
124    if (!m_instanceProxy)
125        return;
126
127    m_instanceProxy->removeInstance(this);
128
129    invalidate();
130}
131
132JSC::Bindings::Class *ProxyInstance::getClass() const
133{
134    return proxyClass();
135}
136
137JSValue ProxyInstance::invoke(JSC::ExecState* exec, InvokeType type, uint64_t identifier, const JSC::ArgList& args)
138{
139    RetainPtr<NSData*> arguments(m_instanceProxy->marshalValues(exec, args));
140
141    uint32_t requestID = m_instanceProxy->nextRequestID();
142
143    if (_WKPHNPObjectInvoke(m_instanceProxy->hostProxy()->port(), m_instanceProxy->pluginID(), requestID, m_objectID,
144                            type, identifier, (char*)[arguments.get() bytes], [arguments.get() length]) != KERN_SUCCESS)
145        return jsUndefined();
146
147    auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID);
148    if (!reply.get() || !reply->m_returnValue)
149        return jsUndefined();
150
151    return m_instanceProxy->demarshalValue(exec, (char*)CFDataGetBytePtr(reply->m_result.get()), CFDataGetLength(reply->m_result.get()));
152}
153
154JSValue ProxyInstance::invokeMethod(ExecState* exec, const MethodList& methodList, const ArgList& args)
155{
156    ASSERT(methodList.size() == 1);
157
158    ProxyMethod* method = static_cast<ProxyMethod*>(methodList[0]);
159
160    return invoke(exec, Invoke, method->serverIdentifier(), args);
161}
162
163bool ProxyInstance::supportsInvokeDefaultMethod() const
164{
165    uint32_t requestID = m_instanceProxy->nextRequestID();
166
167    if (_WKPHNPObjectHasInvokeDefaultMethod(m_instanceProxy->hostProxy()->port(),
168                                            m_instanceProxy->pluginID(), requestID,
169                                            m_objectID) != KERN_SUCCESS)
170        return false;
171
172    auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
173    if (reply.get() && reply->m_result)
174        return true;
175
176    return false;
177}
178
179JSValue ProxyInstance::invokeDefaultMethod(ExecState* exec, const ArgList& args)
180{
181    return invoke(exec, InvokeDefault, 0, args);
182}
183
184bool ProxyInstance::supportsConstruct() const
185{
186    uint32_t requestID = m_instanceProxy->nextRequestID();
187
188    if (_WKPHNPObjectHasConstructMethod(m_instanceProxy->hostProxy()->port(),
189                                        m_instanceProxy->pluginID(), requestID,
190                                        m_objectID) != KERN_SUCCESS)
191        return false;
192
193    auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
194    if (reply.get() && reply->m_result)
195        return true;
196
197    return false;
198}
199
200JSValue ProxyInstance::invokeConstruct(ExecState* exec, const ArgList& args)
201{
202    return invoke(exec, Construct, 0, args);
203}
204
205JSValue ProxyInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
206{
207    if (hint == PreferString)
208        return stringValue(exec);
209    if (hint == PreferNumber)
210        return numberValue(exec);
211    return valueOf(exec);
212}
213
214JSValue ProxyInstance::stringValue(ExecState* exec) const
215{
216    // FIXME: Implement something sensible.
217    return jsString(exec, "");
218}
219
220JSValue ProxyInstance::numberValue(ExecState* exec) const
221{
222    // FIXME: Implement something sensible.
223    return jsNumber(exec, 0);
224}
225
226JSValue ProxyInstance::booleanValue() const
227{
228    // FIXME: Implement something sensible.
229    return jsBoolean(false);
230}
231
232JSValue ProxyInstance::valueOf(ExecState* exec) const
233{
234    return stringValue(exec);
235}
236
237void ProxyInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArray)
238{
239    uint32_t requestID = m_instanceProxy->nextRequestID();
240
241    if (_WKPHNPObjectEnumerate(m_instanceProxy->hostProxy()->port(), m_instanceProxy->pluginID(), requestID, m_objectID) != KERN_SUCCESS)
242        return;
243
244    auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID);
245
246    if (!reply.get() || !reply->m_returnValue)
247        return;
248
249    RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:(NSData *)reply->m_result.get()
250                                                                 mutabilityOption:NSPropertyListImmutable
251                                                                           format:0
252                                                                 errorDescription:0];
253
254    for (NSNumber *number in array.get()) {
255        IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>([number longLongValue]);
256        if (!IdentifierRep::isValid(identifier))
257            continue;
258
259        if (identifier->isString()) {
260            const char* str = identifier->string();
261            nameArray.add(Identifier(JSDOMWindow::commonJSGlobalData(), String::fromUTF8WithLatin1Fallback(str, strlen(str))));
262        } else
263            nameArray.add(Identifier::from(exec, identifier->number()));
264    }
265}
266
267MethodList ProxyInstance::methodsNamed(const Identifier& identifier)
268{
269    // If we already have an entry in the map, use it.
270    MethodMap::iterator existingMapEntry = m_methods.find(identifier.ustring().rep());
271    if (existingMapEntry != m_methods.end()) {
272        MethodList methodList;
273        if (existingMapEntry->second)
274            methodList.append(existingMapEntry->second);
275        return methodList;
276    }
277
278    uint64_t methodName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(identifier.ascii()));
279    uint32_t requestID = m_instanceProxy->nextRequestID();
280
281    if (_WKPHNPObjectHasMethod(m_instanceProxy->hostProxy()->port(),
282                               m_instanceProxy->pluginID(), requestID,
283                               m_objectID, methodName) != KERN_SUCCESS)
284        return MethodList();
285
286    auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
287    if (!reply.get())
288        return MethodList();
289
290    if (!reply->m_result && !m_instanceProxy->hostProxy()->shouldCacheMissingPropertiesAndMethods())
291        return MethodList();
292
293    // Add a new entry to the map unless an entry was added while we were in waitForReply.
294    pair<MethodMap::iterator, bool> mapAddResult = m_methods.add(identifier.ustring().rep(), 0);
295    if (mapAddResult.second && reply->m_result)
296        mapAddResult.first->second = new ProxyMethod(methodName);
297
298    MethodList methodList;
299    if (mapAddResult.first->second)
300        methodList.append(mapAddResult.first->second);
301    return methodList;
302}
303
304Field* ProxyInstance::fieldNamed(const Identifier& identifier)
305{
306    // If we already have an entry in the map, use it.
307    FieldMap::iterator existingMapEntry = m_fields.find(identifier.ustring().rep());
308    if (existingMapEntry != m_fields.end())
309        return existingMapEntry->second;
310
311    uint64_t propertyName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(identifier.ascii()));
312    uint32_t requestID = m_instanceProxy->nextRequestID();
313
314    if (_WKPHNPObjectHasProperty(m_instanceProxy->hostProxy()->port(),
315                                 m_instanceProxy->pluginID(), requestID,
316                                 m_objectID, propertyName) != KERN_SUCCESS)
317        return 0;
318
319    auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
320    if (!reply.get())
321        return 0;
322
323    if (!reply->m_result && !m_instanceProxy->hostProxy()->shouldCacheMissingPropertiesAndMethods())
324        return 0;
325
326    // Add a new entry to the map unless an entry was added while we were in waitForReply.
327    pair<FieldMap::iterator, bool> mapAddResult = m_fields.add(identifier.ustring().rep(), 0);
328    if (mapAddResult.second && reply->m_result)
329        mapAddResult.first->second = new ProxyField(propertyName);
330    return mapAddResult.first->second;
331}
332
333JSC::JSValue ProxyInstance::fieldValue(ExecState* exec, const Field* field) const
334{
335    uint64_t serverIdentifier = static_cast<const ProxyField*>(field)->serverIdentifier();
336    uint32_t requestID = m_instanceProxy->nextRequestID();
337
338    if (_WKPHNPObjectGetProperty(m_instanceProxy->hostProxy()->port(),
339                                 m_instanceProxy->pluginID(), requestID,
340                                 m_objectID, serverIdentifier) != KERN_SUCCESS)
341        return jsUndefined();
342
343    auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID);
344    if (!reply.get() || !reply->m_returnValue)
345        return jsUndefined();
346
347    return m_instanceProxy->demarshalValue(exec, (char*)CFDataGetBytePtr(reply->m_result.get()), CFDataGetLength(reply->m_result.get()));
348}
349
350void ProxyInstance::setFieldValue(ExecState* exec, const Field* field, JSValue value) const
351{
352    uint64_t serverIdentifier = static_cast<const ProxyField*>(field)->serverIdentifier();
353    uint32_t requestID = m_instanceProxy->nextRequestID();
354
355    data_t valueData;
356    mach_msg_type_number_t valueLength;
357
358    m_instanceProxy->marshalValue(exec, value, valueData, valueLength);
359    kern_return_t kr = _WKPHNPObjectSetProperty(m_instanceProxy->hostProxy()->port(),
360                                                m_instanceProxy->pluginID(), requestID,
361                                                m_objectID, serverIdentifier, valueData, valueLength);
362    mig_deallocate(reinterpret_cast<vm_address_t>(valueData), valueLength);
363    if (kr != KERN_SUCCESS)
364        return;
365
366    auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = m_instanceProxy->waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
367}
368
369void ProxyInstance::invalidate()
370{
371    if (NetscapePluginHostProxy* hostProxy = m_instanceProxy->hostProxy())
372        _WKPHNPObjectRelease(hostProxy->port(),
373                             m_instanceProxy->pluginID(), m_objectID);
374    m_instanceProxy = 0;
375}
376
377} // namespace WebKit
378
379#endif // USE(PLUGIN_HOST_PROCESS)
380
381