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) && ENABLE(NETSCAPE_PLUGIN_API)
27
28#import "NetscapePluginHostProxy.h"
29
30#import <mach/mach.h>
31#import <wtf/StdLibExtras.h>
32
33#import "HostedNetscapePluginStream.h"
34#import "NetscapePluginHostManager.h"
35#import "NetscapePluginInstanceProxy.h"
36#import "WebFrameInternal.h"
37#import "WebHostedNetscapePluginView.h"
38#import "WebKitSystemInterface.h"
39#import <WebCore/Frame.h>
40#import <WebCore/IdentifierRep.h>
41#import <WebCore/ScriptController.h>
42#import <string>
43
44extern "C" {
45#import "WebKitPluginHost.h"
46#import "WebKitPluginClientServer.h"
47}
48
49using namespace std;
50using namespace JSC;
51using namespace WebCore;
52
53@interface WebPlaceholderModalWindow : NSWindow
54@end
55
56@implementation WebPlaceholderModalWindow
57// Prevent NSApp from calling requestUserAttention: when the window is shown
58// modally, even if the app is inactive. See 6823049.
59- (BOOL)_wantsUserAttention
60{
61    return NO;
62}
63@end
64
65namespace WebKit {
66
67class PluginDestroyDeferrer {
68public:
69    PluginDestroyDeferrer(NetscapePluginInstanceProxy* proxy)
70        : m_proxy(proxy)
71    {
72        m_proxy->willCallPluginFunction();
73    }
74
75    ~PluginDestroyDeferrer()
76    {
77        bool stopped;
78        m_proxy->didCallPluginFunction(stopped);
79    }
80
81private:
82    RefPtr<NetscapePluginInstanceProxy> m_proxy;
83};
84
85typedef HashMap<mach_port_t, NetscapePluginHostProxy*> PluginProxyMap;
86static PluginProxyMap& pluginProxyMap()
87{
88    DEFINE_STATIC_LOCAL(PluginProxyMap, pluginProxyMap, ());
89
90    return pluginProxyMap;
91}
92
93unsigned NetscapePluginHostProxy::s_processingRequests;
94
95NetscapePluginHostProxy::NetscapePluginHostProxy(mach_port_t clientPort, mach_port_t pluginHostPort, const ProcessSerialNumber& pluginHostPSN, bool shouldCacheMissingPropertiesAndMethods)
96    : m_clientPort(clientPort)
97    , m_portSet(MACH_PORT_NULL)
98    , m_pluginHostPort(pluginHostPort)
99    , m_isModal(false)
100    , m_menuBarIsVisible(true)
101    , m_fullscreenWindowIsShowing(false)
102    , m_pluginHostPSN(pluginHostPSN)
103    , m_shouldCacheMissingPropertiesAndMethods(shouldCacheMissingPropertiesAndMethods)
104{
105    pluginProxyMap().add(m_clientPort, this);
106
107    // FIXME: We should use libdispatch for this.
108    CFMachPortContext context = { 0, this, 0, 0, 0 };
109    m_deadNameNotificationPort.adoptCF(CFMachPortCreate(0, deadNameNotificationCallback, &context, 0));
110
111    mach_port_t previous;
112    mach_port_request_notification(mach_task_self(), pluginHostPort, MACH_NOTIFY_DEAD_NAME, 0,
113                                   CFMachPortGetPort(m_deadNameNotificationPort.get()), MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
114    ASSERT(previous == MACH_PORT_NULL);
115
116    RetainPtr<CFRunLoopSourceRef> deathPortSource(AdoptCF, CFMachPortCreateRunLoopSource(0, m_deadNameNotificationPort.get(), 0));
117
118    CFRunLoopAddSource(CFRunLoopGetCurrent(), deathPortSource.get(), kCFRunLoopDefaultMode);
119
120    m_clientPortSource.adoptCF(WKCreateMIGServerSource((mig_subsystem_t)&WKWebKitPluginClient_subsystem, m_clientPort));
121    CFRunLoopAddSource(CFRunLoopGetCurrent(), m_clientPortSource.get(), kCFRunLoopDefaultMode);
122    CFRunLoopAddSource(CFRunLoopGetCurrent(), m_clientPortSource.get(), (CFStringRef)NSEventTrackingRunLoopMode);
123}
124
125NetscapePluginHostProxy::~NetscapePluginHostProxy()
126{
127    pluginProxyMap().remove(m_clientPort);
128
129    // Free the port set
130    if (m_portSet) {
131        mach_port_extract_member(mach_task_self(), m_clientPort, m_portSet);
132        mach_port_extract_member(mach_task_self(), CFMachPortGetPort(m_deadNameNotificationPort.get()), m_portSet);
133        mach_port_destroy(mach_task_self(), m_portSet);
134    }
135
136    ASSERT(m_clientPortSource);
137    CFRunLoopSourceInvalidate(m_clientPortSource.get());
138    m_clientPortSource = 0;
139}
140
141void NetscapePluginHostProxy::pluginHostDied()
142{
143    PluginInstanceMap instances;
144    m_instances.swap(instances);
145
146    PluginInstanceMap::const_iterator end = instances.end();
147    for (PluginInstanceMap::const_iterator it = instances.begin(); it != end; ++it)
148        it->second->pluginHostDied();
149
150    NetscapePluginHostManager::shared().pluginHostDied(this);
151
152    // The plug-in crashed while its menu bar was hidden. Make sure to show it.
153    if (!m_menuBarIsVisible)
154        setMenuBarVisible(true);
155
156    // The plug-in crashed while it had a modal dialog up.
157    if (m_isModal)
158        endModal();
159
160    delete this;
161}
162
163void NetscapePluginHostProxy::addPluginInstance(NetscapePluginInstanceProxy* instance)
164{
165    ASSERT(!m_instances.contains(instance->pluginID()));
166
167    m_instances.set(instance->pluginID(), instance);
168}
169
170void NetscapePluginHostProxy::removePluginInstance(NetscapePluginInstanceProxy* instance)
171{
172    ASSERT(m_instances.get(instance->pluginID()) == instance);
173
174    m_instances.remove(instance->pluginID());
175}
176
177NetscapePluginInstanceProxy* NetscapePluginHostProxy::pluginInstance(uint32_t pluginID)
178{
179    NetscapePluginInstanceProxy* result = m_instances.get(pluginID).get();
180    ASSERT(!result || result->hostProxy() == this);
181    return result;
182}
183
184void NetscapePluginHostProxy::deadNameNotificationCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
185{
186    ASSERT(msg);
187    ASSERT(static_cast<mach_msg_header_t*>(msg)->msgh_id == MACH_NOTIFY_DEAD_NAME);
188
189    static_cast<NetscapePluginHostProxy*>(info)->pluginHostDied();
190}
191
192void NetscapePluginHostProxy::setMenuBarVisible(bool visible)
193{
194    m_menuBarIsVisible = visible;
195
196    [NSMenu setMenuBarVisible:visible];
197}
198
199void NetscapePluginHostProxy::didEnterFullscreen() const
200{
201    SetFrontProcess(&m_pluginHostPSN);
202}
203
204void NetscapePluginHostProxy::didExitFullscreen() const
205{
206    // If the plug-in host is the current application then we should bring ourselves to the front when it exits full-screen mode.
207
208    ProcessSerialNumber frontProcess;
209    GetFrontProcess(&frontProcess);
210    Boolean isSameProcess = 0;
211    SameProcess(&frontProcess, &m_pluginHostPSN, &isSameProcess);
212    if (!isSameProcess)
213        return;
214
215    ProcessSerialNumber currentProcess;
216    GetCurrentProcess(&currentProcess);
217    SetFrontProcess(&currentProcess);
218}
219
220void NetscapePluginHostProxy::setFullscreenWindowIsShowing(bool isShowing)
221{
222    if (m_fullscreenWindowIsShowing == isShowing)
223        return;
224
225    m_fullscreenWindowIsShowing = isShowing;
226    if (m_fullscreenWindowIsShowing)
227        didEnterFullscreen();
228    else
229        didExitFullscreen();
230
231}
232
233void NetscapePluginHostProxy::applicationDidBecomeActive()
234{
235    SetFrontProcess(&m_pluginHostPSN);
236}
237
238void NetscapePluginHostProxy::beginModal()
239{
240    ASSERT(!m_placeholderWindow);
241    ASSERT(!m_activationObserver);
242
243    m_placeholderWindow.adoptNS([[WebPlaceholderModalWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1, 1) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]);
244
245    m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillBecomeActiveNotification object:NSApp queue:nil
246                                                                         usingBlock:^(NSNotification *){ applicationDidBecomeActive(); }];
247
248    // We need to be able to get the setModal(false) call from the plug-in host.
249    CFRunLoopAddSource(CFRunLoopGetCurrent(), m_clientPortSource.get(), (CFStringRef)NSModalPanelRunLoopMode);
250
251    [NSApp runModalForWindow:m_placeholderWindow.get()];
252
253    [m_placeholderWindow.get() orderOut:nil];
254    m_placeholderWindow = 0;
255}
256
257void NetscapePluginHostProxy::endModal()
258{
259    ASSERT(m_placeholderWindow);
260    ASSERT(m_activationObserver);
261
262    [[NSNotificationCenter defaultCenter] removeObserver:m_activationObserver.get()];
263    m_activationObserver = nil;
264
265    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_clientPortSource.get(), (CFStringRef)NSModalPanelRunLoopMode);
266
267    [NSApp stopModal];
268
269    // Make ourselves the front process.
270    ProcessSerialNumber psn;
271    GetCurrentProcess(&psn);
272    SetFrontProcess(&psn);
273}
274
275
276void NetscapePluginHostProxy::setModal(bool modal)
277{
278    if (modal == m_isModal)
279        return;
280
281    m_isModal = modal;
282
283    if (m_isModal)
284        beginModal();
285    else
286        endModal();
287}
288
289bool NetscapePluginHostProxy::processRequests()
290{
291    s_processingRequests++;
292
293   if (!m_portSet) {
294        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &m_portSet);
295        mach_port_insert_member(mach_task_self(), m_clientPort, m_portSet);
296        mach_port_insert_member(mach_task_self(), CFMachPortGetPort(m_deadNameNotificationPort.get()), m_portSet);
297    }
298
299    char buffer[4096];
300
301    mach_msg_header_t* msg = reinterpret_cast<mach_msg_header_t*>(buffer);
302
303    kern_return_t kr = mach_msg(msg, MACH_RCV_MSG, 0, sizeof(buffer), m_portSet, 0, MACH_PORT_NULL);
304
305    if (kr != KERN_SUCCESS) {
306        LOG_ERROR("Could not receive mach message, error %x", kr);
307        s_processingRequests--;
308        return false;
309    }
310
311    if (msg->msgh_local_port == m_clientPort) {
312        __ReplyUnion__WKWebKitPluginClient_subsystem reply;
313        mach_msg_header_t* replyHeader = reinterpret_cast<mach_msg_header_t*>(&reply);
314
315        if (WebKitPluginClient_server(msg, replyHeader) && replyHeader->msgh_remote_port != MACH_PORT_NULL) {
316            kr = mach_msg(replyHeader, MACH_SEND_MSG, replyHeader->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
317
318            if (kr != KERN_SUCCESS) {
319                LOG_ERROR("Could not send mach message, error %x", kr);
320                s_processingRequests--;
321                return false;
322            }
323        }
324
325        s_processingRequests--;
326        return true;
327    }
328
329    if (msg->msgh_local_port == CFMachPortGetPort(m_deadNameNotificationPort.get())) {
330        ASSERT(msg->msgh_id == MACH_NOTIFY_DEAD_NAME);
331        pluginHostDied();
332        s_processingRequests--;
333        return false;
334    }
335
336    ASSERT_NOT_REACHED();
337    s_processingRequests--;
338    return false;
339}
340
341} // namespace WebKit
342
343using namespace WebKit;
344
345// Helper class for deallocating data
346class DataDeallocator {
347public:
348    DataDeallocator(data_t data, mach_msg_type_number_t dataLength)
349        : m_data(reinterpret_cast<vm_address_t>(data))
350        , m_dataLength(dataLength)
351    {
352    }
353
354    ~DataDeallocator()
355    {
356        if (!m_data)
357            return;
358
359        vm_deallocate(mach_task_self(), m_data, m_dataLength);
360    }
361
362private:
363    vm_address_t m_data;
364    vm_size_t m_dataLength;
365};
366
367// MiG callbacks
368kern_return_t WKPCStatusText(mach_port_t clientPort, uint32_t pluginID, data_t text, mach_msg_type_number_t textCnt)
369{
370    DataDeallocator deallocator(text, textCnt);
371
372    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
373    if (!hostProxy)
374        return KERN_FAILURE;
375
376    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
377    if (!instanceProxy)
378        return KERN_FAILURE;
379
380    instanceProxy->status(text);
381    return KERN_SUCCESS;
382}
383
384kern_return_t WKPCLoadURL(mach_port_t clientPort, uint32_t pluginID, data_t url, mach_msg_type_number_t urlLength, data_t target, mach_msg_type_number_t targetLength,
385                          data_t postData, mach_msg_type_number_t postDataLength, uint32_t flags,
386                          uint16_t* outResult, uint32_t* outStreamID)
387{
388    DataDeallocator urlDeallocator(url, urlLength);
389    DataDeallocator targetDeallocator(target, targetLength);
390    DataDeallocator postDataDeallocator(postData, postDataLength);
391
392    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
393    if (!hostProxy)
394        return KERN_FAILURE;
395
396    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
397    if (!instanceProxy)
398        return KERN_FAILURE;
399
400    uint32_t streamID = 0;
401    NPError result = instanceProxy->loadURL(url, target, postData, postDataLength, static_cast<LoadURLFlags>(flags), streamID);
402
403    *outResult = result;
404    *outStreamID = streamID;
405    return KERN_SUCCESS;
406}
407
408kern_return_t WKPCCancelLoadURL(mach_port_t clientPort, uint32_t pluginID, uint32_t streamID, int16_t reason)
409{
410    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
411    if (!hostProxy)
412        return KERN_FAILURE;
413
414    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
415    if (!instanceProxy)
416        return KERN_FAILURE;
417
418    if (!instanceProxy->cancelStreamLoad(streamID, reason))
419        return KERN_FAILURE;
420
421    return KERN_SUCCESS;
422}
423
424kern_return_t WKPCInvalidateRect(mach_port_t clientPort, uint32_t pluginID, double x, double y, double width, double height)
425{
426    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
427    if (!hostProxy)
428        return KERN_SUCCESS;
429
430    if (!hostProxy->isProcessingRequests()) {
431        if (NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID))
432            instanceProxy->invalidateRect(x, y, width, height);
433        return KERN_SUCCESS;
434    }
435
436    // Defer the work
437    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{
438        if (NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort)) {
439            if (NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID))
440                instanceProxy->invalidateRect(x, y, width, height);
441        }
442    });
443
444    return KERN_SUCCESS;
445}
446
447kern_return_t WKPCGetScriptableNPObjectReply(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID)
448{
449    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
450    if (!hostProxy)
451        return KERN_FAILURE;
452
453    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
454    if (!instanceProxy)
455        return KERN_FAILURE;
456
457    instanceProxy->setCurrentReply(requestID, new NetscapePluginInstanceProxy::GetScriptableNPObjectReply(objectID));
458    return KERN_SUCCESS;
459}
460
461kern_return_t WKPCBooleanReply(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, boolean_t result)
462{
463    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
464    if (!hostProxy)
465        return KERN_FAILURE;
466
467    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
468    if (!instanceProxy)
469        return KERN_FAILURE;
470
471    instanceProxy->setCurrentReply(requestID, new NetscapePluginInstanceProxy::BooleanReply(result));
472    return KERN_SUCCESS;
473}
474
475kern_return_t WKPCBooleanAndDataReply(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, boolean_t returnValue, data_t resultData, mach_msg_type_number_t resultLength)
476{
477    DataDeallocator deallocator(resultData, resultLength);
478
479    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
480    if (!hostProxy)
481        return KERN_FAILURE;
482
483    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
484    if (!instanceProxy)
485        return KERN_FAILURE;
486
487    RetainPtr<CFDataRef> result(AdoptCF, CFDataCreate(0, reinterpret_cast<UInt8*>(resultData), resultLength));
488    instanceProxy->setCurrentReply(requestID, new NetscapePluginInstanceProxy::BooleanAndDataReply(returnValue, result));
489
490    return KERN_SUCCESS;
491}
492
493kern_return_t WKPCInstantiatePluginReply(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, kern_return_t result, uint32_t renderContextID, uint32_t rendererType)
494{
495    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
496    if (!hostProxy)
497        return KERN_FAILURE;
498
499    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
500    if (!instanceProxy)
501        return KERN_FAILURE;
502
503    instanceProxy->setCurrentReply(requestID, new NetscapePluginInstanceProxy::InstantiatePluginReply(result, renderContextID, static_cast<RendererType>(rendererType)));
504    return KERN_SUCCESS;
505}
506
507kern_return_t WKPCGetWindowNPObject(mach_port_t clientPort, uint32_t pluginID, uint32_t* outObjectID)
508{
509    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
510    if (!hostProxy)
511        return KERN_FAILURE;
512
513    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
514    if (!instanceProxy)
515        return KERN_FAILURE;
516
517    uint32_t objectID;
518    if (!instanceProxy->getWindowNPObject(objectID))
519        return KERN_FAILURE;
520
521    *outObjectID = objectID;
522    return KERN_SUCCESS;
523}
524
525kern_return_t WKPCGetPluginElementNPObject(mach_port_t clientPort, uint32_t pluginID, uint32_t* outObjectID)
526{
527    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
528    if (!hostProxy)
529        return KERN_FAILURE;
530
531    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
532    if (!instanceProxy)
533        return KERN_FAILURE;
534
535    uint32_t objectID;
536    if (!instanceProxy->getPluginElementNPObject(objectID))
537        return KERN_FAILURE;
538
539    *outObjectID = objectID;
540    return KERN_SUCCESS;
541}
542
543kern_return_t WKPCForgetBrowserObject(mach_port_t clientPort, uint32_t pluginID, uint32_t objectID)
544{
545    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
546    if (!hostProxy)
547        return KERN_FAILURE;
548
549    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
550    if (!instanceProxy)
551        return KERN_FAILURE;
552
553    return instanceProxy->forgetBrowserObjectID(objectID) ? KERN_SUCCESS : KERN_FAILURE;
554}
555
556kern_return_t WKPCEvaluate(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, data_t scriptData, mach_msg_type_number_t scriptLength, boolean_t allowPopups)
557{
558    DataDeallocator deallocator(scriptData, scriptLength);
559
560    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
561    if (!hostProxy)
562        return KERN_FAILURE;
563
564    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
565    if (!instanceProxy)
566        return KERN_FAILURE;
567
568    PluginDestroyDeferrer deferrer(instanceProxy);
569
570    String script = String::fromUTF8WithLatin1Fallback(scriptData, scriptLength);
571
572    data_t resultData = 0;
573    mach_msg_type_number_t resultLength = 0;
574    boolean_t returnValue = instanceProxy->evaluate(objectID, script, resultData, resultLength, allowPopups);
575
576    hostProxy = instanceProxy->hostProxy();
577    if (!hostProxy)
578        return KERN_FAILURE;
579
580    _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength);
581    if (resultData)
582        mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength);
583
584    return KERN_SUCCESS;
585}
586
587kern_return_t WKPCGetStringIdentifier(mach_port_t clientPort, data_t name, mach_msg_type_number_t nameCnt, uint64_t* identifier)
588{
589    DataDeallocator deallocator(name, nameCnt);
590
591    COMPILE_ASSERT(sizeof(*identifier) == sizeof(IdentifierRep*), identifier_sizes);
592
593    *identifier = reinterpret_cast<uint64_t>(IdentifierRep::get(name));
594    return KERN_SUCCESS;
595}
596
597kern_return_t WKPCGetIntIdentifier(mach_port_t clientPort, int32_t value, uint64_t* identifier)
598{
599    COMPILE_ASSERT(sizeof(*identifier) == sizeof(NPIdentifier), identifier_sizes);
600
601    *identifier = reinterpret_cast<uint64_t>(IdentifierRep::get(value));
602    return KERN_SUCCESS;
603}
604
605static Identifier identifierFromIdentifierRep(IdentifierRep* identifier)
606{
607    ASSERT(IdentifierRep::isValid(identifier));
608    ASSERT(identifier->isString());
609
610    const char* str = identifier->string();
611    return Identifier(JSDOMWindow::commonJSGlobalData(), stringToUString(String::fromUTF8WithLatin1Fallback(str, strlen(str))));
612}
613
614kern_return_t WKPCInvoke(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier,
615                         data_t argumentsData, mach_msg_type_number_t argumentsLength)
616{
617    DataDeallocator deallocator(argumentsData, argumentsLength);
618
619    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
620    if (!hostProxy)
621        return KERN_FAILURE;
622
623    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
624    if (!instanceProxy)
625        return KERN_FAILURE;
626
627    PluginDestroyDeferrer deferrer(instanceProxy);
628
629    IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
630    if (!IdentifierRep::isValid(identifier))
631        return KERN_FAILURE;
632
633    Identifier methodNameIdentifier = identifierFromIdentifierRep(identifier);
634
635    data_t resultData = 0;
636    mach_msg_type_number_t resultLength = 0;
637    boolean_t returnValue = instanceProxy->invoke(objectID, methodNameIdentifier, argumentsData, argumentsLength, resultData, resultLength);
638
639    hostProxy = instanceProxy->hostProxy();
640    if (!hostProxy)
641        return KERN_FAILURE;
642
643    _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength);
644    if (resultData)
645        mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength);
646
647    return KERN_SUCCESS;
648}
649
650kern_return_t WKPCInvokeDefault(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID,
651                                data_t argumentsData, mach_msg_type_number_t argumentsLength)
652{
653    DataDeallocator deallocator(argumentsData, argumentsLength);
654
655    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
656    if (!hostProxy)
657        return KERN_FAILURE;
658
659    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
660    if (!instanceProxy)
661        return KERN_FAILURE;
662
663    PluginDestroyDeferrer deferrer(instanceProxy);
664
665    data_t resultData = 0;
666    mach_msg_type_number_t resultLength = 0;
667    boolean_t returnValue = instanceProxy->invokeDefault(objectID, argumentsData, argumentsLength, resultData, resultLength);
668
669    hostProxy = instanceProxy->hostProxy();
670    if (!hostProxy)
671        return KERN_FAILURE;
672
673    _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength);
674    if (resultData)
675        mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength);
676
677    return KERN_SUCCESS;
678}
679
680kern_return_t WKPCConstruct(mach_port_t clientPort, uint32_t pluginID, uint32_t objectID,
681                            data_t argumentsData, mach_msg_type_number_t argumentsLength,
682                            boolean_t* returnValue, data_t* resultData, mach_msg_type_number_t* resultLength)
683{
684    DataDeallocator deallocator(argumentsData, argumentsLength);
685
686    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
687    if (!hostProxy)
688        return KERN_FAILURE;
689
690    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
691    if (!instanceProxy)
692        return KERN_FAILURE;
693
694    PluginDestroyDeferrer deferrer(instanceProxy);
695
696    *returnValue = instanceProxy->construct(objectID, argumentsData, argumentsLength, *resultData, *resultLength);
697
698    return KERN_SUCCESS;
699}
700
701kern_return_t WKPCGetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier)
702{
703    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
704    if (!hostProxy)
705        return KERN_FAILURE;
706
707    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
708    if (!instanceProxy)
709        return KERN_FAILURE;
710
711    IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
712    if (!IdentifierRep::isValid(identifier))
713        return KERN_FAILURE;
714
715    PluginDestroyDeferrer deferrer(instanceProxy);
716
717    data_t resultData = 0;
718    mach_msg_type_number_t resultLength = 0;
719    boolean_t returnValue;
720
721    if (identifier->isString()) {
722        Identifier propertyNameIdentifier = identifierFromIdentifierRep(identifier);
723        returnValue = instanceProxy->getProperty(objectID, propertyNameIdentifier, resultData, resultLength);
724    } else
725        returnValue = instanceProxy->setProperty(objectID, identifier->number(), resultData, resultLength);
726
727    hostProxy = instanceProxy->hostProxy();
728    if (!hostProxy)
729        return KERN_FAILURE;
730
731    _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength);
732    if (resultData)
733        mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength);
734
735    return KERN_SUCCESS;
736}
737
738kern_return_t WKPCSetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier, data_t valueData, mach_msg_type_number_t valueLength)
739{
740    DataDeallocator deallocator(valueData, valueLength);
741
742    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
743    if (!hostProxy)
744        return KERN_FAILURE;
745
746    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
747    if (!instanceProxy)
748        return KERN_FAILURE;
749
750    PluginDestroyDeferrer deferrer(instanceProxy);
751
752    IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
753    if (!IdentifierRep::isValid(identifier))
754        return KERN_FAILURE;
755
756    bool result;
757    if (identifier->isString()) {
758        Identifier propertyNameIdentifier = identifierFromIdentifierRep(identifier);
759        result = instanceProxy->setProperty(objectID, propertyNameIdentifier, valueData, valueLength);
760    } else
761        result = instanceProxy->setProperty(objectID, identifier->number(), valueData, valueLength);
762
763    hostProxy = instanceProxy->hostProxy();
764    if (!hostProxy)
765        return KERN_FAILURE;
766
767    _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, result);
768
769    return KERN_SUCCESS;
770}
771
772kern_return_t WKPCRemoveProperty(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier)
773{
774    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
775    if (!hostProxy)
776        return KERN_FAILURE;
777
778    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
779    if (!instanceProxy)
780        return KERN_FAILURE;
781
782    PluginDestroyDeferrer deferrer(instanceProxy);
783
784    IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
785    if (!IdentifierRep::isValid(identifier))
786        return KERN_FAILURE;
787
788    bool result;
789    if (identifier->isString()) {
790        Identifier propertyNameIdentifier = identifierFromIdentifierRep(identifier);
791        result = instanceProxy->removeProperty(objectID, propertyNameIdentifier);
792    } else
793        result = instanceProxy->removeProperty(objectID, identifier->number());
794
795    hostProxy = instanceProxy->hostProxy();
796    if (!hostProxy)
797        return KERN_FAILURE;
798
799    _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, result);
800
801    return KERN_SUCCESS;
802}
803
804kern_return_t WKPCHasProperty(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier)
805{
806    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
807    if (!hostProxy)
808        return KERN_FAILURE;
809
810    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
811    if (!instanceProxy)
812        return KERN_FAILURE;
813
814    PluginDestroyDeferrer deferrer(instanceProxy);
815
816    IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
817    if (!IdentifierRep::isValid(identifier))
818        return KERN_FAILURE;
819
820    boolean_t returnValue;
821    if (identifier->isString()) {
822        Identifier propertyNameIdentifier = identifierFromIdentifierRep(identifier);
823        returnValue = instanceProxy->hasProperty(objectID, propertyNameIdentifier);
824    } else
825        returnValue = instanceProxy->hasProperty(objectID, identifier->number());
826
827    hostProxy = instanceProxy->hostProxy();
828    if (!hostProxy)
829        return KERN_FAILURE;
830
831    _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue);
832
833    return KERN_SUCCESS;
834}
835
836kern_return_t WKPCHasMethod(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier)
837{
838    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
839    if (!hostProxy)
840        return KERN_FAILURE;
841
842    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
843    if (!instanceProxy)
844        return KERN_FAILURE;
845
846    PluginDestroyDeferrer deferrer(instanceProxy);
847
848    IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
849    if (!IdentifierRep::isValid(identifier))
850        return KERN_FAILURE;
851
852    Identifier methodNameIdentifier = identifierFromIdentifierRep(identifier);
853    boolean_t returnValue = instanceProxy->hasMethod(objectID, methodNameIdentifier);
854
855    hostProxy = instanceProxy->hostProxy();
856    if (!hostProxy)
857        return KERN_FAILURE;
858
859    _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue);
860
861    return KERN_SUCCESS;
862}
863
864kern_return_t WKPCIdentifierInfo(mach_port_t clientPort, uint64_t serverIdentifier, data_t* infoData, mach_msg_type_number_t* infoLength)
865{
866    IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier);
867    if (!IdentifierRep::isValid(identifier))
868        return KERN_FAILURE;
869
870    id info;
871    if (identifier->isString()) {
872        const char* str = identifier->string();
873        info = [NSData dataWithBytesNoCopy:(void*)str length:strlen(str) freeWhenDone:NO];
874    } else
875        info = [NSNumber numberWithInt:identifier->number()];
876
877    RetainPtr<NSData*> data = [NSPropertyListSerialization dataFromPropertyList:info format:NSPropertyListBinaryFormat_v1_0 errorDescription:0];
878    ASSERT(data);
879
880    *infoLength = [data.get() length];
881    mig_allocate(reinterpret_cast<vm_address_t*>(infoData), *infoLength);
882
883    memcpy(*infoData, [data.get() bytes], *infoLength);
884
885    return KERN_SUCCESS;
886}
887
888kern_return_t WKPCEnumerate(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID)
889{
890    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
891    if (!hostProxy)
892        return KERN_FAILURE;
893
894    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
895    if (!instanceProxy)
896        return KERN_FAILURE;
897
898    data_t resultData = 0;
899    mach_msg_type_number_t resultLength = 0;
900    boolean_t returnValue = instanceProxy->enumerate(objectID, resultData, resultLength);
901
902    hostProxy = instanceProxy->hostProxy();
903    if (!hostProxy)
904        return KERN_FAILURE;
905
906    _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength);
907
908    if (resultData)
909        mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength);
910
911    return KERN_SUCCESS;
912}
913
914kern_return_t WKPCSetMenuBarVisible(mach_port_t clientPort, boolean_t menuBarVisible)
915{
916    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
917    if (!hostProxy)
918        return KERN_FAILURE;
919
920    hostProxy->setMenuBarVisible(menuBarVisible);
921
922    return KERN_SUCCESS;
923}
924
925kern_return_t WKPCSetFullscreenWindowIsShowing(mach_port_t clientPort, boolean_t fullscreenWindowIsShowing)
926{
927    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
928    if (!hostProxy)
929        return KERN_FAILURE;
930
931    hostProxy->setFullscreenWindowIsShowing(fullscreenWindowIsShowing);
932
933    return KERN_SUCCESS;
934}
935
936kern_return_t WKPCSetModal(mach_port_t clientPort, boolean_t modal)
937{
938    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
939    if (!hostProxy)
940        return KERN_FAILURE;
941
942    if (!hostProxy->isProcessingRequests()) {
943        hostProxy->setModal(modal);
944        return KERN_SUCCESS;
945    }
946
947    // Defer the work
948    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{
949        if (NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort))
950            hostProxy->setModal(modal);
951    });
952
953    return KERN_SUCCESS;
954}
955
956kern_return_t WKPCGetCookies(mach_port_t clientPort, uint32_t pluginID,
957                             data_t urlData, mach_msg_type_number_t urlLength,
958                             boolean_t* returnValue, data_t* cookiesData, mach_msg_type_number_t* cookiesLength)
959{
960    *cookiesData = 0;
961    *cookiesLength = 0;
962
963    DataDeallocator deallocator(urlData, urlLength);
964
965    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
966    if (!hostProxy)
967        return KERN_FAILURE;
968
969    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
970    if (!instanceProxy)
971        return KERN_FAILURE;
972
973    *returnValue = instanceProxy->getCookies(urlData, urlLength, *cookiesData, *cookiesLength);
974
975    return KERN_SUCCESS;
976}
977
978kern_return_t WKPCGetProxy(mach_port_t clientPort, uint32_t pluginID,
979                           data_t urlData, mach_msg_type_number_t urlLength,
980                           boolean_t* returnValue, data_t* proxyData, mach_msg_type_number_t* proxyLength)
981{
982    *proxyData = 0;
983    *proxyLength = 0;
984
985    DataDeallocator deallocator(urlData, urlLength);
986
987    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
988    if (!hostProxy)
989        return KERN_FAILURE;
990
991    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
992    if (!instanceProxy)
993        return KERN_FAILURE;
994
995    *returnValue = instanceProxy->getProxy(urlData, urlLength, *proxyData, *proxyLength);
996
997    return KERN_SUCCESS;
998}
999
1000kern_return_t WKPCSetCookies(mach_port_t clientPort, uint32_t pluginID,
1001                             data_t urlData, mach_msg_type_number_t urlLength,
1002                             data_t cookiesData, mach_msg_type_number_t cookiesLength,
1003                             boolean_t* returnValue)
1004{
1005    DataDeallocator urlDeallocator(urlData, urlLength);
1006    DataDeallocator cookiesDeallocator(cookiesData, cookiesLength);
1007
1008    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
1009    if (!hostProxy)
1010        return KERN_FAILURE;
1011
1012    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
1013    if (!instanceProxy)
1014        return KERN_FAILURE;
1015
1016    *returnValue = instanceProxy->setCookies(urlData, urlLength, cookiesData, cookiesLength);
1017    return KERN_SUCCESS;
1018}
1019
1020kern_return_t WKPCGetAuthenticationInfo(mach_port_t clientPort, uint32_t pluginID,
1021                                        data_t protocolData, mach_msg_type_number_t protocolLength,
1022                                        data_t hostData, mach_msg_type_number_t hostLength,
1023                                        uint32_t port,
1024                                        data_t schemeData, mach_msg_type_number_t schemeLength,
1025                                        data_t realmData, mach_msg_type_number_t realmLength,
1026                                        boolean_t* returnValue,
1027                                        data_t* usernameData, mach_msg_type_number_t *usernameLength,
1028                                        data_t* passwordData, mach_msg_type_number_t *passwordLength)
1029{
1030    DataDeallocator protocolDeallocator(protocolData, protocolLength);
1031    DataDeallocator hostDeallocator(hostData, hostLength);
1032    DataDeallocator schemeDeallocator(schemeData, schemeLength);
1033    DataDeallocator realmDeallocator(realmData, realmLength);
1034
1035    *usernameData = 0;
1036    *usernameLength = 0;
1037    *passwordData = 0;
1038    *passwordLength = 0;
1039
1040    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
1041    if (!hostProxy)
1042        return KERN_FAILURE;
1043
1044    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
1045    if (!instanceProxy)
1046        return KERN_FAILURE;
1047
1048    *returnValue = instanceProxy->getAuthenticationInfo(protocolData, hostData, port, schemeData, realmData, *usernameData, *usernameLength, *passwordData, *passwordLength);
1049
1050    return KERN_SUCCESS;
1051}
1052
1053kern_return_t WKPCConvertPoint(mach_port_t clientPort, uint32_t pluginID,
1054                               double sourceX, double sourceY, uint32_t sourceSpace,
1055                               uint32_t destSpace, boolean_t *returnValue, double *destX, double *destY)
1056{
1057    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
1058    if (!hostProxy)
1059        return KERN_FAILURE;
1060
1061    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
1062    if (!instanceProxy)
1063        return KERN_FAILURE;
1064
1065    *returnValue = instanceProxy->convertPoint(sourceX, sourceY, static_cast<NPCoordinateSpace>(sourceSpace),
1066                                               *destX, *destY, static_cast<NPCoordinateSpace>(destSpace));
1067    return KERN_SUCCESS;
1068}
1069
1070kern_return_t WKPCCheckIfAllowedToLoadURL(mach_port_t clientPort, uint32_t pluginID, data_t urlData, mach_msg_type_number_t urlLength,
1071                                          data_t targetData, mach_msg_type_number_t targetLength, uint32_t *checkID)
1072{
1073    DataDeallocator urlDeallocator(urlData, urlLength);
1074    DataDeallocator targetDeallocator(targetData, targetLength);
1075
1076    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
1077    if (!hostProxy)
1078        return KERN_FAILURE;
1079
1080    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
1081    if (!instanceProxy)
1082        return KERN_FAILURE;
1083
1084    *checkID = instanceProxy->checkIfAllowedToLoadURL(urlData, targetData);
1085    return KERN_SUCCESS;
1086}
1087
1088kern_return_t WKPCCancelCheckIfAllowedToLoadURL(mach_port_t clientPort, uint32_t pluginID, uint32_t checkID)
1089{
1090    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
1091    if (!hostProxy)
1092        return KERN_FAILURE;
1093
1094    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
1095    if (!instanceProxy)
1096        return KERN_FAILURE;
1097
1098    instanceProxy->cancelCheckIfAllowedToLoadURL(checkID);
1099    return KERN_SUCCESS;
1100}
1101
1102kern_return_t WKPCResolveURL(mach_port_t clientPort, uint32_t pluginID, data_t urlData, mach_msg_type_number_t urlLength,
1103                             data_t targetData, mach_msg_type_number_t targetLength,
1104                             data_t *resolvedURLData, mach_msg_type_number_t *resolvedURLLength)
1105{
1106    DataDeallocator urlDeallocator(urlData, urlLength);
1107    DataDeallocator targetDeallocator(targetData, targetLength);
1108
1109    *resolvedURLData = 0;
1110    *resolvedURLLength = 0;
1111
1112    NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort);
1113    if (!hostProxy)
1114        return KERN_FAILURE;
1115
1116    NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID);
1117    if (!instanceProxy)
1118        return KERN_FAILURE;
1119
1120    instanceProxy->resolveURL(urlData, targetData, *resolvedURLData, *resolvedURLLength);
1121    return KERN_SUCCESS;
1122}
1123
1124kern_return_t WKPCSetException(mach_port_t clientPort, data_t message, mach_msg_type_number_t messageCnt)
1125{
1126    DataDeallocator deallocator(message, messageCnt);
1127
1128    string str(message, messageCnt);
1129    NetscapePluginInstanceProxy::setGlobalException(str.c_str());
1130
1131    return KERN_SUCCESS;
1132}
1133
1134#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
1135