• 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 "NetscapePluginInstanceProxy.h"
29
30#import "HostedNetscapePluginStream.h"
31#import "NetscapePluginHostProxy.h"
32#import "ProxyInstance.h"
33#import "WebDataSourceInternal.h"
34#import "WebFrameInternal.h"
35#import "WebHostedNetscapePluginView.h"
36#import "WebNSDataExtras.h"
37#import "WebNSURLExtras.h"
38#import "WebKitNSStringExtras.h"
39#import "WebPluginRequest.h"
40#import "WebViewInternal.h"
41#import "WebUIDelegate.h"
42#import "WebUIDelegatePrivate.h"
43
44#import <mach/mach.h>
45#import <WebCore/CookieJar.h>
46#import <WebCore/CString.h>
47#import <WebCore/DocumentLoader.h>
48#import <WebCore/Frame.h>
49#import <WebCore/FrameLoader.h>
50#import <WebCore/FrameTree.h>
51#import <WebCore/KURL.h>
52#import <WebCore/npruntime_impl.h>
53#import <WebCore/runtime_object.h>
54#import <WebCore/ScriptController.h>
55#import <WebCore/ScriptValue.h>
56#import <WebKitSystemInterface.h>
57#import <runtime/JSLock.h>
58#import <runtime/PropertyNameArray.h>
59#import <utility>
60
61extern "C" {
62#import "WebKitPluginClientServer.h"
63#import "WebKitPluginHost.h"
64}
65
66using namespace JSC;
67using namespace JSC::Bindings;
68using namespace std;
69using namespace WebCore;
70
71namespace WebKit {
72
73class NetscapePluginInstanceProxy::PluginRequest {
74public:
75    PluginRequest(uint32_t requestID, NSURLRequest *request, NSString *frameName, bool allowPopups)
76        : m_requestID(requestID)
77        , m_request(request)
78        , m_frameName(frameName)
79        , m_allowPopups(allowPopups)
80    {
81    }
82
83    uint32_t requestID() const { return m_requestID; }
84    NSURLRequest *request() const { return m_request.get(); }
85    NSString *frameName() const { return m_frameName.get(); }
86    bool allowPopups() const { return m_allowPopups; }
87
88private:
89    uint32_t m_requestID;
90    RetainPtr<NSURLRequest *> m_request;
91    RetainPtr<NSString *> m_frameName;
92    bool m_allowPopups;
93};
94
95static uint32_t pluginIDCounter;
96
97NetscapePluginInstanceProxy::NetscapePluginInstanceProxy(NetscapePluginHostProxy* pluginHostProxy, WebHostedNetscapePluginView *pluginView, bool fullFramePlugin)
98    : m_pluginHostProxy(pluginHostProxy)
99    , m_pluginView(pluginView)
100    , m_requestTimer(this, &NetscapePluginInstanceProxy::requestTimerFired)
101    , m_currentURLRequestID(0)
102    , m_renderContextID(0)
103    , m_useSoftwareRenderer(false)
104    , m_waitingForReply(false)
105    , m_objectIDCounter(0)
106    , m_urlCheckCounter(0)
107    , m_pluginFunctionCallDepth(0)
108    , m_shouldStopSoon(false)
109    , m_currentRequestID(0)
110    , m_inDestroy(false)
111{
112    ASSERT(m_pluginView);
113
114    if (fullFramePlugin) {
115        // For full frame plug-ins, the first requestID will always be the one for the already
116        // open stream.
117        ++m_currentRequestID;
118    }
119
120    // Assign a plug-in ID.
121    do {
122        m_pluginID = ++pluginIDCounter;
123    } while (pluginHostProxy->pluginInstance(m_pluginID) || !m_pluginID);
124
125    pluginHostProxy->addPluginInstance(this);
126}
127
128NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy()
129{
130    ASSERT(!m_pluginHostProxy);
131
132    m_pluginID = 0;
133    deleteAllValues(m_replies);
134}
135
136void NetscapePluginInstanceProxy::resize(NSRect size, NSRect clipRect, bool sync)
137{
138    uint32_t requestID = 0;
139
140    if (sync)
141        requestID = nextRequestID();
142
143    _WKPHResizePluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID,
144                              size.origin.x, size.origin.y, size.size.width, size.size.height,
145                              clipRect.origin.x, clipRect.origin.y, clipRect.size.width, clipRect.size.height);
146
147    if (sync)
148        waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
149}
150
151void NetscapePluginInstanceProxy::stopAllStreams()
152{
153    Vector<RefPtr<HostedNetscapePluginStream> > streamsCopy;
154    copyValuesToVector(m_streams, streamsCopy);
155    for (size_t i = 0; i < streamsCopy.size(); i++)
156        streamsCopy[i]->stop();
157}
158
159void NetscapePluginInstanceProxy::cleanup()
160{
161    stopAllStreams();
162
163    m_requestTimer.stop();
164
165    // Clear the object map, this will cause any outstanding JS objects that the plug-in had a reference to
166    // to go away when the next garbage collection takes place.
167    m_objects.clear();
168
169    if (Frame* frame = core([m_pluginView webFrame]))
170        frame->script()->cleanupScriptObjectsForPlugin(m_pluginView);
171
172    ProxyInstanceSet instances;
173    instances.swap(m_instances);
174
175    // Invalidate all proxy instances.
176    ProxyInstanceSet::const_iterator end = instances.end();
177    for (ProxyInstanceSet::const_iterator it = instances.begin(); it != end; ++it)
178        (*it)->invalidate();
179
180    m_pluginView = nil;
181}
182
183void NetscapePluginInstanceProxy::invalidate()
184{
185    // If the plug-in host has died, the proxy will be null.
186    if (!m_pluginHostProxy)
187        return;
188
189    m_pluginHostProxy->removePluginInstance(this);
190    m_pluginHostProxy = 0;
191}
192
193void NetscapePluginInstanceProxy::destroy()
194{
195    uint32_t requestID = nextRequestID();
196
197    m_inDestroy = true;
198
199    _WKPHDestroyPluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID);
200
201    // If the plug-in host crashes while we're waiting for a reply, the last reference to the instance proxy
202    // will go away. Prevent this by protecting it here.
203    RefPtr<NetscapePluginInstanceProxy> protect(this);
204
205    // We don't care about the reply here - we just want to block until the plug-in instance has been torn down.
206    waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
207
208    m_inDestroy = false;
209
210    cleanup();
211    invalidate();
212}
213
214void NetscapePluginInstanceProxy::setManualStream(PassRefPtr<HostedNetscapePluginStream> manualStream)
215{
216    ASSERT(!m_manualStream);
217
218    m_manualStream = manualStream;
219}
220
221bool NetscapePluginInstanceProxy::cancelStreamLoad(uint32_t streamID, NPReason reason)
222{
223    HostedNetscapePluginStream* stream = 0;
224
225    if (m_manualStream && streamID == 1)
226        stream = m_manualStream.get();
227    else
228        stream = m_streams.get(streamID).get();
229
230    if (!stream)
231        return false;
232
233    stream->cancelLoad(reason);
234    return true;
235}
236
237void NetscapePluginInstanceProxy::disconnectStream(HostedNetscapePluginStream* stream)
238{
239    m_streams.remove(stream->streamID());
240}
241
242void NetscapePluginInstanceProxy::pluginHostDied()
243{
244    m_pluginHostProxy = 0;
245
246    [m_pluginView pluginHostDied];
247
248    cleanup();
249}
250
251void NetscapePluginInstanceProxy::focusChanged(bool hasFocus)
252{
253    _WKPHPluginInstanceFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus);
254}
255
256void NetscapePluginInstanceProxy::windowFocusChanged(bool hasFocus)
257{
258    _WKPHPluginInstanceWindowFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus);
259}
260
261void NetscapePluginInstanceProxy::windowFrameChanged(NSRect frame)
262{
263    _WKPHPluginInstanceWindowFrameChanged(m_pluginHostProxy->port(), m_pluginID, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height,
264                                          NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]));
265}
266
267void NetscapePluginInstanceProxy::startTimers(bool throttleTimers)
268{
269    _WKPHPluginInstanceStartTimers(m_pluginHostProxy->port(), m_pluginID, throttleTimers);
270}
271
272void NetscapePluginInstanceProxy::mouseEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type)
273{
274    NSPoint screenPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
275    NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil];
276
277    int clickCount;
278    if (type == NPCocoaEventMouseEntered || type == NPCocoaEventMouseExited)
279        clickCount = 0;
280    else
281        clickCount = [event clickCount];
282
283
284    _WKPHPluginInstanceMouseEvent(m_pluginHostProxy->port(), m_pluginID,
285                                  [event timestamp],
286                                  type, [event modifierFlags],
287                                  pluginPoint.x, pluginPoint.y,
288                                  screenPoint.x, screenPoint.y,
289                                  NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]),
290                                  [event buttonNumber], clickCount,
291                                  [event deltaX], [event deltaY], [event deltaZ]);
292}
293
294void NetscapePluginInstanceProxy::keyEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type)
295{
296    NSData *charactersData = [[event characters] dataUsingEncoding:NSUTF8StringEncoding];
297    NSData *charactersIgnoringModifiersData = [[event charactersIgnoringModifiers] dataUsingEncoding:NSUTF8StringEncoding];
298
299    _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID,
300                                     [event timestamp],
301                                     type, [event modifierFlags],
302                                     const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length],
303                                     const_cast<char*>(reinterpret_cast<const char*>([charactersIgnoringModifiersData bytes])), [charactersIgnoringModifiersData length],
304                                     [event isARepeat], [event keyCode], WKGetNSEventKeyChar(event));
305}
306
307void NetscapePluginInstanceProxy::syntheticKeyDownWithCommandModifier(int keyCode, char character)
308{
309    NSData *charactersData = [NSData dataWithBytes:&character length:1];
310
311    _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID,
312                                     [NSDate timeIntervalSinceReferenceDate],
313                                     NPCocoaEventKeyDown, NSCommandKeyMask,
314                                     const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length],
315                                     const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length],
316                                     false, keyCode, character);
317}
318
319void NetscapePluginInstanceProxy::flagsChanged(NSEvent *event)
320{
321    _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID,
322                                     [event timestamp], NPCocoaEventFlagsChanged,
323                                     [event modifierFlags], 0, 0, 0, 0, false, [event keyCode], 0);
324}
325
326void NetscapePluginInstanceProxy::insertText(NSString *text)
327{
328    NSData *textData = [text dataUsingEncoding:NSUTF8StringEncoding];
329
330    _WKPHPluginInstanceInsertText(m_pluginHostProxy->port(), m_pluginID,
331                                  const_cast<char*>(reinterpret_cast<const char*>([textData bytes])), [textData length]);
332}
333
334bool NetscapePluginInstanceProxy::wheelEvent(NSView *pluginView, NSEvent *event)
335{
336    NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil];
337
338    uint32_t requestID = nextRequestID();
339    _WKPHPluginInstanceWheelEvent(m_pluginHostProxy->port(), m_pluginID, requestID,
340                                  [event timestamp], [event modifierFlags],
341                                  pluginPoint.x, pluginPoint.y, [event buttonNumber],
342                                  [event deltaX], [event deltaY], [event deltaZ]);
343
344    // Protect ourselves in case waiting for the reply causes us to be deleted.
345    RefPtr<NetscapePluginInstanceProxy> protect(this);
346
347    auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
348    if (!reply.get() || !reply->m_result)
349        return false;
350
351    return true;
352}
353
354void NetscapePluginInstanceProxy::print(CGContextRef context, unsigned width, unsigned height)
355{
356    uint32_t requestID = nextRequestID();
357    _WKPHPluginInstancePrint(m_pluginHostProxy->port(), m_pluginID, requestID, width, height);
358
359    auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID);
360    if (!reply.get() || !reply->m_returnValue)
361        return;
362
363    RetainPtr<CGDataProvider> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(reply->m_result.get()));
364    RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
365    RetainPtr<CGImageRef> image(AdoptCF, CGImageCreate(width, height, 8, 32, width * 4, colorSpace.get(), kCGImageAlphaFirst, dataProvider.get(), 0, false, kCGRenderingIntentDefault));
366
367    // Flip the context and draw the image.
368    CGContextSaveGState(context);
369    CGContextTranslateCTM(context, 0.0, height);
370    CGContextScaleCTM(context, 1.0, -1.0);
371
372    CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.get());
373
374    CGContextRestoreGState(context);
375}
376
377void NetscapePluginInstanceProxy::stopTimers()
378{
379    _WKPHPluginInstanceStopTimers(m_pluginHostProxy->port(), m_pluginID);
380}
381
382void NetscapePluginInstanceProxy::status(const char* message)
383{
384    RetainPtr<CFStringRef> status(AdoptCF, CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8));
385
386    if (!status)
387        return;
388
389    WebView *wv = [m_pluginView webView];
390    [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status.get()];
391}
392
393NPError NetscapePluginInstanceProxy::loadURL(const char* url, const char* target, const char* postData, uint32_t postLen, LoadURLFlags flags, uint32_t& streamID)
394{
395    if (!url)
396        return NPERR_INVALID_PARAM;
397
398    NSMutableURLRequest *request = [m_pluginView requestWithURLCString:url];
399
400    if (flags & IsPost) {
401        NSData *httpBody = nil;
402
403        if (flags & PostDataIsFile) {
404            // If we're posting a file, buf is either a file URL or a path to the file.
405            RetainPtr<CFStringRef> bufString(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, postData, kCFStringEncodingWindowsLatin1));
406            if (!bufString)
407                return NPERR_INVALID_PARAM;
408
409            NSURL *fileURL = [NSURL _web_URLWithDataAsString:(NSString *)bufString.get()];
410            NSString *path;
411            if ([fileURL isFileURL])
412                path = [fileURL path];
413            else
414                path = (NSString *)bufString.get();
415            httpBody = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
416            if (!httpBody)
417                return NPERR_FILE_NOT_FOUND;
418        } else
419            httpBody = [NSData dataWithBytes:postData length:postLen];
420
421        if (![httpBody length])
422            return NPERR_INVALID_PARAM;
423
424        [request setHTTPMethod:@"POST"];
425
426        if (flags & AllowHeadersInPostData) {
427            if ([httpBody _web_startsWithBlankLine])
428                httpBody = [httpBody subdataWithRange:NSMakeRange(1, [httpBody length] - 1)];
429            else {
430                NSInteger location = [httpBody _web_locationAfterFirstBlankLine];
431                if (location != NSNotFound) {
432                    // If the blank line is somewhere in the middle of postData, everything before is the header.
433                    NSData *headerData = [httpBody subdataWithRange:NSMakeRange(0, location)];
434                    NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
435                    unsigned dataLength = [httpBody length] - location;
436
437                    // Sometimes plugins like to set Content-Length themselves when they post,
438                    // but CFNetwork does not like that. So we will remove the header
439                    // and instead truncate the data to the requested length.
440                    NSString *contentLength = [header objectForKey:@"Content-Length"];
441
442                    if (contentLength)
443                        dataLength = min(static_cast<unsigned>([contentLength intValue]), dataLength);
444                    [header removeObjectForKey:@"Content-Length"];
445
446                    if ([header count] > 0)
447                        [request setAllHTTPHeaderFields:header];
448
449                    // Everything after the blank line is the actual content of the POST.
450                    httpBody = [httpBody subdataWithRange:NSMakeRange(location, dataLength)];
451                }
452            }
453        }
454
455        if (![httpBody length])
456            return NPERR_INVALID_PARAM;
457
458        // Plug-ins expect to receive uncached data when doing a POST (3347134).
459        [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
460        [request setHTTPBody:httpBody];
461    }
462
463    return loadRequest(request, target, flags & AllowPopups, streamID);
464}
465
466void NetscapePluginInstanceProxy::performRequest(PluginRequest* pluginRequest)
467{
468    ASSERT(m_pluginView);
469
470    NSURLRequest *request = pluginRequest->request();
471    NSString *frameName = pluginRequest->frameName();
472    WebFrame *frame = nil;
473
474    NSURL *URL = [request URL];
475    NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
476
477    ASSERT(frameName || JSString);
478    if (frameName) {
479        // FIXME - need to get rid of this window creation which
480        // bypasses normal targeted link handling
481        frame = kit(core([m_pluginView webFrame])->loader()->findFrameForNavigation(frameName));
482        if (!frame) {
483            WebView *currentWebView = [m_pluginView webView];
484            NSDictionary *features = [[NSDictionary alloc] init];
485            WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
486                                                        createWebViewWithRequest:nil
487                                                                  windowFeatures:features];
488            [features release];
489
490            if (!newWebView) {
491                _WKPHLoadURLNotify(m_pluginHostProxy->port(), m_pluginID, pluginRequest->requestID(), NPERR_GENERIC_ERROR);
492                return;
493            }
494
495            frame = [newWebView mainFrame];
496            core(frame)->tree()->setName(frameName);
497            [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
498        }
499    }
500
501    if (JSString) {
502        ASSERT(!frame || [m_pluginView webFrame] == frame);
503        evaluateJavaScript(pluginRequest);
504    } else
505        [frame loadRequest:request];
506}
507
508void NetscapePluginInstanceProxy::evaluateJavaScript(PluginRequest* pluginRequest)
509{
510    NSURL *URL = [pluginRequest->request() URL];
511    NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
512    ASSERT(JSString);
513
514    NSString *result = [[m_pluginView webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:pluginRequest->allowPopups()];
515
516    // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
517    if (!m_pluginHostProxy)
518        return;
519
520    if (pluginRequest->frameName() != nil)
521        return;
522
523    if ([result length] > 0) {
524        // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
525        NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
526
527        RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, pluginRequest->requestID(), pluginRequest->request());
528
529        RetainPtr<NSURLResponse> response(AdoptNS, [[NSURLResponse alloc] initWithURL:URL
530                                                                             MIMEType:@"text/plain"
531                                                                expectedContentLength:[JSData length]
532                                                                     textEncodingName:nil]);
533        stream->startStreamWithResponse(response.get());
534        stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]);
535        stream->didFinishLoading(0);
536    }
537}
538
539void NetscapePluginInstanceProxy::requestTimerFired(Timer<NetscapePluginInstanceProxy>*)
540{
541    ASSERT(!m_pluginRequests.isEmpty());
542    ASSERT(m_pluginView);
543
544    PluginRequest* request = m_pluginRequests.first();
545    m_pluginRequests.removeFirst();
546
547    if (!m_pluginRequests.isEmpty())
548        m_requestTimer.startOneShot(0);
549
550    performRequest(request);
551    delete request;
552}
553
554NPError NetscapePluginInstanceProxy::loadRequest(NSURLRequest *request, const char* cTarget, bool allowPopups, uint32_t& requestID)
555{
556    NSURL *URL = [request URL];
557
558    if (!URL)
559        return NPERR_INVALID_URL;
560
561    // Don't allow requests to be loaded when the document loader is stopping all loaders.
562    if ([[m_pluginView dataSource] _documentLoader]->isStopping())
563        return NPERR_GENERIC_ERROR;
564
565    NSString *target = nil;
566    if (cTarget) {
567        // Find the frame given the target string.
568        target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding];
569    }
570    WebFrame *frame = [m_pluginView webFrame];
571
572    // don't let a plugin start any loads if it is no longer part of a document that is being
573    // displayed unless the loads are in the same frame as the plugin.
574    if ([[m_pluginView dataSource] _documentLoader] != core([m_pluginView webFrame])->loader()->activeDocumentLoader() &&
575        (!cTarget || [frame findFrameNamed:target] != frame)) {
576        return NPERR_GENERIC_ERROR;
577    }
578
579    NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
580    if (JSString != nil) {
581        if (![[[m_pluginView webView] preferences] isJavaScriptEnabled]) {
582            // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
583            return NPERR_GENERIC_ERROR;
584        }
585    } else {
586        if (!FrameLoader::canLoad(URL, String(), core([m_pluginView webFrame])->document()))
587            return NPERR_GENERIC_ERROR;
588    }
589
590    // FIXME: Handle wraparound
591    requestID = ++m_currentURLRequestID;
592
593    if (cTarget || JSString) {
594        // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
595        // want to potentially kill the plug-in inside of its URL request.
596
597        if (JSString && target && [frame findFrameNamed:target] != frame) {
598            // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
599            return NPERR_INVALID_PARAM;
600        }
601
602        PluginRequest* pluginRequest = new PluginRequest(requestID, request, target, allowPopups);
603        m_pluginRequests.append(pluginRequest);
604        m_requestTimer.startOneShot(0);
605    } else {
606        RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, requestID, request);
607
608        m_streams.add(requestID, stream);
609        stream->start();
610    }
611
612    return NPERR_NO_ERROR;
613}
614
615NetscapePluginInstanceProxy::Reply* NetscapePluginInstanceProxy::processRequestsAndWaitForReply(uint32_t requestID)
616{
617    Reply* reply = 0;
618
619    while (!(reply = m_replies.take(requestID))) {
620        if (!m_pluginHostProxy->processRequests())
621            return 0;
622    }
623
624    ASSERT(reply);
625    return reply;
626}
627
628uint32_t NetscapePluginInstanceProxy::idForObject(JSObject* object)
629{
630    uint32_t objectID = 0;
631
632    // Assign an object ID.
633    do {
634        objectID = ++m_objectIDCounter;
635    } while (!m_objectIDCounter || m_objectIDCounter == static_cast<uint32_t>(-1) || m_objects.contains(objectID));
636
637    m_objects.set(objectID, object);
638
639    return objectID;
640}
641
642// NPRuntime support
643bool NetscapePluginInstanceProxy::getWindowNPObject(uint32_t& objectID)
644{
645    Frame* frame = core([m_pluginView webFrame]);
646    if (!frame)
647        return false;
648
649    if (!frame->script()->isEnabled())
650        objectID = 0;
651    else
652        objectID = idForObject(frame->script()->windowShell()->window());
653
654    return true;
655}
656
657bool NetscapePluginInstanceProxy::getPluginElementNPObject(uint32_t& objectID)
658{
659    Frame* frame = core([m_pluginView webFrame]);
660    if (!frame)
661        return false;
662
663    if (JSObject* object = frame->script()->jsObjectForPluginElement([m_pluginView element]))
664        objectID = idForObject(object);
665    else
666        objectID = 0;
667
668    return true;
669}
670
671void NetscapePluginInstanceProxy::releaseObject(uint32_t objectID)
672{
673    m_objects.remove(objectID);
674}
675
676bool NetscapePluginInstanceProxy::evaluate(uint32_t objectID, const String& script, data_t& resultData, mach_msg_type_number_t& resultLength, bool allowPopups)
677{
678    resultData = 0;
679    resultLength = 0;
680
681    if (!m_objects.contains(objectID))
682        return false;
683
684    Frame* frame = core([m_pluginView webFrame]);
685    if (!frame)
686        return false;
687
688    JSLock lock(SilenceAssertionsOnly);
689
690    ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject();
691    ExecState* exec = globalObject->globalExec();
692
693    bool oldAllowPopups = frame->script()->allowPopupsFromPlugin();
694    frame->script()->setAllowPopupsFromPlugin(allowPopups);
695
696    globalObject->globalData()->timeoutChecker.start();
697    Completion completion = JSC::evaluate(exec, globalObject->globalScopeChain(), makeSource(script));
698    globalObject->globalData()->timeoutChecker.stop();
699    ComplType type = completion.complType();
700
701    frame->script()->setAllowPopupsFromPlugin(oldAllowPopups);
702
703    JSValue result;
704    if (type == Normal)
705        result = completion.value();
706
707    if (!result)
708        result = jsUndefined();
709
710    marshalValue(exec, result, resultData, resultLength);
711    exec->clearException();
712    return true;
713}
714
715bool NetscapePluginInstanceProxy::invoke(uint32_t objectID, const Identifier& methodName, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength)
716{
717    resultData = 0;
718    resultLength = 0;
719
720    if (m_inDestroy)
721        return false;
722
723    JSObject* object = m_objects.get(objectID);
724    if (!object)
725        return false;
726
727    Frame* frame = core([m_pluginView webFrame]);
728    if (!frame)
729        return false;
730
731    ExecState* exec = frame->script()->globalObject()->globalExec();
732    JSLock lock(SilenceAssertionsOnly);
733    JSValue function = object->get(exec, methodName);
734    CallData callData;
735    CallType callType = function.getCallData(callData);
736    if (callType == CallTypeNone)
737        return false;
738
739    MarkedArgumentBuffer argList;
740    demarshalValues(exec, argumentsData, argumentsLength, argList);
741
742    ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject();
743    globalObject->globalData()->timeoutChecker.start();
744    JSValue value = call(exec, function, callType, callData, object, argList);
745    globalObject->globalData()->timeoutChecker.stop();
746
747    marshalValue(exec, value, resultData, resultLength);
748    exec->clearException();
749    return true;
750}
751
752bool NetscapePluginInstanceProxy::invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength)
753{
754    if (m_inDestroy)
755        return false;
756
757    JSObject* object = m_objects.get(objectID);
758    if (!object)
759        return false;
760
761    Frame* frame = core([m_pluginView webFrame]);
762    if (!frame)
763        return false;
764
765    ExecState* exec = frame->script()->globalObject()->globalExec();
766    JSLock lock(SilenceAssertionsOnly);
767    CallData callData;
768    CallType callType = object->getCallData(callData);
769    if (callType == CallTypeNone)
770        return false;
771
772    MarkedArgumentBuffer argList;
773    demarshalValues(exec, argumentsData, argumentsLength, argList);
774
775    ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject();
776    globalObject->globalData()->timeoutChecker.start();
777    JSValue value = call(exec, object, callType, callData, object, argList);
778    globalObject->globalData()->timeoutChecker.stop();
779
780    marshalValue(exec, value, resultData, resultLength);
781    exec->clearException();
782    return true;
783}
784
785bool NetscapePluginInstanceProxy::construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength)
786{
787    if (m_inDestroy)
788        return false;
789
790    JSObject* object = m_objects.get(objectID);
791    if (!object)
792        return false;
793
794    Frame* frame = core([m_pluginView webFrame]);
795    if (!frame)
796        return false;
797
798    ExecState* exec = frame->script()->globalObject()->globalExec();
799    JSLock lock(SilenceAssertionsOnly);
800
801    ConstructData constructData;
802    ConstructType constructType = object->getConstructData(constructData);
803    if (constructType == ConstructTypeNone)
804        return false;
805
806    MarkedArgumentBuffer argList;
807    demarshalValues(exec, argumentsData, argumentsLength, argList);
808
809    ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject();
810    globalObject->globalData()->timeoutChecker.start();
811    JSValue value = JSC::construct(exec, object, constructType, constructData, argList);
812    globalObject->globalData()->timeoutChecker.stop();
813
814    marshalValue(exec, value, resultData, resultLength);
815    exec->clearException();
816    return true;
817}
818
819bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, const Identifier& propertyName, data_t& resultData, mach_msg_type_number_t& resultLength)
820{
821    if (m_inDestroy)
822        return false;
823
824    JSObject* object = m_objects.get(objectID);
825    if (!object)
826        return false;
827
828    Frame* frame = core([m_pluginView webFrame]);
829    if (!frame)
830        return false;
831
832    ExecState* exec = frame->script()->globalObject()->globalExec();
833    JSLock lock(SilenceAssertionsOnly);
834    JSValue value = object->get(exec, propertyName);
835
836    marshalValue(exec, value, resultData, resultLength);
837    exec->clearException();
838    return true;
839}
840
841bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, unsigned propertyName, data_t& resultData, mach_msg_type_number_t& resultLength)
842{
843    JSObject* object = m_objects.get(objectID);
844    if (!object)
845        return false;
846
847    Frame* frame = core([m_pluginView webFrame]);
848    if (!frame)
849        return false;
850
851    ExecState* exec = frame->script()->globalObject()->globalExec();
852    JSLock lock(SilenceAssertionsOnly);
853    JSValue value = object->get(exec, propertyName);
854
855    marshalValue(exec, value, resultData, resultLength);
856    exec->clearException();
857    return true;
858}
859
860bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, const Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength)
861{
862    if (m_inDestroy)
863        return false;
864
865    JSObject* object = m_objects.get(objectID);
866    if (!object)
867        return false;
868
869    Frame* frame = core([m_pluginView webFrame]);
870    if (!frame)
871        return false;
872
873    ExecState* exec = frame->script()->globalObject()->globalExec();
874    JSLock lock(SilenceAssertionsOnly);
875
876    JSValue value = demarshalValue(exec, valueData, valueLength);
877    PutPropertySlot slot;
878    object->put(exec, propertyName, value, slot);
879
880    exec->clearException();
881    return true;
882}
883
884bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength)
885{
886    if (m_inDestroy)
887        return false;
888
889    JSObject* object = m_objects.get(objectID);
890    if (!object)
891        return false;
892
893    Frame* frame = core([m_pluginView webFrame]);
894    if (!frame)
895        return false;
896
897    ExecState* exec = frame->script()->globalObject()->globalExec();
898    JSLock lock(SilenceAssertionsOnly);
899
900    JSValue value = demarshalValue(exec, valueData, valueLength);
901    object->put(exec, propertyName, value);
902
903    exec->clearException();
904    return true;
905}
906
907bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, const Identifier& propertyName)
908{
909    if (m_inDestroy)
910        return false;
911
912    JSObject* object = m_objects.get(objectID);
913    if (!object)
914        return false;
915
916    Frame* frame = core([m_pluginView webFrame]);
917    if (!frame)
918        return false;
919
920    ExecState* exec = frame->script()->globalObject()->globalExec();
921    if (!object->hasProperty(exec, propertyName)) {
922        exec->clearException();
923        return false;
924    }
925
926    JSLock lock(SilenceAssertionsOnly);
927    object->deleteProperty(exec, propertyName);
928    exec->clearException();
929    return true;
930}
931
932bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, unsigned propertyName)
933{
934    if (m_inDestroy)
935        return false;
936
937    JSObject* object = m_objects.get(objectID);
938    if (!object)
939        return false;
940
941    Frame* frame = core([m_pluginView webFrame]);
942    if (!frame)
943        return false;
944
945    ExecState* exec = frame->script()->globalObject()->globalExec();
946    if (!object->hasProperty(exec, propertyName)) {
947        exec->clearException();
948        return false;
949    }
950
951    JSLock lock(SilenceAssertionsOnly);
952    object->deleteProperty(exec, propertyName);
953    exec->clearException();
954    return true;
955}
956
957bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, const Identifier& propertyName)
958{
959    if (m_inDestroy)
960        return false;
961
962    JSObject* object = m_objects.get(objectID);
963    if (!object)
964        return false;
965
966    Frame* frame = core([m_pluginView webFrame]);
967    if (!frame)
968        return false;
969
970    ExecState* exec = frame->script()->globalObject()->globalExec();
971    bool result = object->hasProperty(exec, propertyName);
972    exec->clearException();
973
974    return result;
975}
976
977bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, unsigned propertyName)
978{
979    if (m_inDestroy)
980        return false;
981
982    JSObject* object = m_objects.get(objectID);
983    if (!object)
984        return false;
985
986    Frame* frame = core([m_pluginView webFrame]);
987    if (!frame)
988        return false;
989
990    ExecState* exec = frame->script()->globalObject()->globalExec();
991    bool result = object->hasProperty(exec, propertyName);
992    exec->clearException();
993
994    return result;
995}
996
997bool NetscapePluginInstanceProxy::hasMethod(uint32_t objectID, const Identifier& methodName)
998{
999    if (m_inDestroy)
1000        return false;
1001
1002    JSObject* object = m_objects.get(objectID);
1003    if (!object)
1004        return false;
1005
1006    Frame* frame = core([m_pluginView webFrame]);
1007    if (!frame)
1008        return false;
1009
1010    ExecState* exec = frame->script()->globalObject()->globalExec();
1011    JSLock lock(SilenceAssertionsOnly);
1012    JSValue func = object->get(exec, methodName);
1013    exec->clearException();
1014    return !func.isUndefined();
1015}
1016
1017bool NetscapePluginInstanceProxy::enumerate(uint32_t objectID, data_t& resultData, mach_msg_type_number_t& resultLength)
1018{
1019    if (m_inDestroy)
1020        return false;
1021
1022    JSObject* object = m_objects.get(objectID);
1023    if (!object)
1024        return false;
1025
1026    Frame* frame = core([m_pluginView webFrame]);
1027    if (!frame)
1028        return false;
1029
1030    ExecState* exec = frame->script()->globalObject()->globalExec();
1031    JSLock lock(SilenceAssertionsOnly);
1032
1033    PropertyNameArray propertyNames(exec);
1034    object->getPropertyNames(exec, propertyNames);
1035
1036    NSMutableArray *array = [[NSMutableArray alloc] init];
1037    for (unsigned i = 0; i < propertyNames.size(); i++) {
1038        uint64_t methodName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().c_str()));
1039
1040        [array addObject:[NSNumber numberWithLongLong:methodName]];
1041    }
1042
1043    NSData *data = [NSPropertyListSerialization dataFromPropertyList:array format:NSPropertyListBinaryFormat_v1_0 errorDescription:0];
1044    ASSERT(data);
1045
1046    resultLength = [data length];
1047    mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength);
1048
1049    memcpy(resultData, [data bytes], resultLength);
1050
1051    exec->clearException();
1052
1053    return true;
1054}
1055
1056void NetscapePluginInstanceProxy::addValueToArray(NSMutableArray *array, ExecState* exec, JSValue value)
1057{
1058    JSLock lock(SilenceAssertionsOnly);
1059
1060    if (value.isString()) {
1061        [array addObject:[NSNumber numberWithInt:StringValueType]];
1062        [array addObject:String(value.toString(exec))];
1063    } else if (value.isNumber()) {
1064        [array addObject:[NSNumber numberWithInt:DoubleValueType]];
1065        [array addObject:[NSNumber numberWithDouble:value.toNumber(exec)]];
1066    } else if (value.isBoolean()) {
1067        [array addObject:[NSNumber numberWithInt:BoolValueType]];
1068        [array addObject:[NSNumber numberWithBool:value.toBoolean(exec)]];
1069    } else if (value.isNull())
1070        [array addObject:[NSNumber numberWithInt:NullValueType]];
1071    else if (value.isObject()) {
1072        JSObject* object = asObject(value);
1073        if (object->classInfo() == &RuntimeObjectImp::s_info) {
1074            RuntimeObjectImp* imp = static_cast<RuntimeObjectImp*>(object);
1075            if (ProxyInstance* instance = static_cast<ProxyInstance*>(imp->getInternalInstance())) {
1076                [array addObject:[NSNumber numberWithInt:NPObjectValueType]];
1077                [array addObject:[NSNumber numberWithInt:instance->objectID()]];
1078            }
1079        } else {
1080            [array addObject:[NSNumber numberWithInt:JSObjectValueType]];
1081            [array addObject:[NSNumber numberWithInt:idForObject(object)]];
1082        }
1083    } else
1084        [array addObject:[NSNumber numberWithInt:VoidValueType]];
1085}
1086
1087void NetscapePluginInstanceProxy::marshalValue(ExecState* exec, JSValue value, data_t& resultData, mach_msg_type_number_t& resultLength)
1088{
1089    RetainPtr<NSMutableArray*> array(AdoptNS, [[NSMutableArray alloc] init]);
1090
1091    addValueToArray(array.get(), exec, value);
1092
1093    RetainPtr<NSData *> data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0];
1094    ASSERT(data);
1095
1096    resultLength = [data.get() length];
1097    mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength);
1098
1099    memcpy(resultData, [data.get() bytes], resultLength);
1100}
1101
1102RetainPtr<NSData *> NetscapePluginInstanceProxy::marshalValues(ExecState* exec, const ArgList& args)
1103{
1104    RetainPtr<NSMutableArray*> array(AdoptNS, [[NSMutableArray alloc] init]);
1105
1106    for (unsigned i = 0; i < args.size(); i++)
1107        addValueToArray(array.get(), exec, args.at(i));
1108
1109    RetainPtr<NSData *> data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0];
1110    ASSERT(data);
1111
1112    return data;
1113}
1114
1115bool NetscapePluginInstanceProxy::demarshalValueFromArray(ExecState* exec, NSArray *array, NSUInteger& index, JSValue& result)
1116{
1117    if (index == [array count])
1118        return false;
1119
1120    int type = [[array objectAtIndex:index++] intValue];
1121    switch (type) {
1122        case VoidValueType:
1123            result = jsUndefined();
1124            return true;
1125        case NullValueType:
1126            result = jsNull();
1127            return true;
1128        case BoolValueType:
1129            result = jsBoolean([[array objectAtIndex:index++] boolValue]);
1130            return true;
1131        case DoubleValueType:
1132            result = jsNumber(exec, [[array objectAtIndex:index++] doubleValue]);
1133            return true;
1134        case StringValueType: {
1135            NSString *string = [array objectAtIndex:index++];
1136
1137            result = jsString(exec, String(string));
1138            return true;
1139        }
1140        case JSObjectValueType: {
1141            uint32_t objectID = [[array objectAtIndex:index++] intValue];
1142
1143            result = m_objects.get(objectID);
1144            ASSERT(result);
1145            return true;
1146        }
1147        case NPObjectValueType: {
1148            uint32_t objectID = [[array objectAtIndex:index++] intValue];
1149
1150            Frame* frame = core([m_pluginView webFrame]);
1151            if (!frame)
1152                return false;
1153
1154            if (!frame->script()->isEnabled())
1155                return false;
1156
1157            RefPtr<RootObject> rootObject = frame->script()->createRootObject(m_pluginView);
1158            if (!rootObject)
1159                return false;
1160
1161            result = ProxyInstance::create(rootObject.release(), this, objectID)->createRuntimeObject(exec);
1162            return true;
1163        }
1164        default:
1165            ASSERT_NOT_REACHED();
1166            return false;
1167    }
1168}
1169
1170JSValue NetscapePluginInstanceProxy::demarshalValue(ExecState* exec, const char* valueData, mach_msg_type_number_t valueLength)
1171{
1172    RetainPtr<NSData*> data(AdoptNS, [[NSData alloc] initWithBytesNoCopy:(void*)valueData length:valueLength freeWhenDone:NO]);
1173
1174    RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:data.get()
1175                                                                 mutabilityOption:NSPropertyListImmutable
1176                                                                           format:0
1177                                                                 errorDescription:0];
1178    NSUInteger position = 0;
1179    JSValue value;
1180    bool result = demarshalValueFromArray(exec, array.get(), position, value);
1181    ASSERT_UNUSED(result, result);
1182
1183    return value;
1184}
1185
1186void NetscapePluginInstanceProxy::demarshalValues(ExecState* exec, data_t valuesData, mach_msg_type_number_t valuesLength, MarkedArgumentBuffer& result)
1187{
1188    RetainPtr<NSData*> data(AdoptNS, [[NSData alloc] initWithBytesNoCopy:valuesData length:valuesLength freeWhenDone:NO]);
1189
1190    RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:data.get()
1191                                                                 mutabilityOption:NSPropertyListImmutable
1192                                                                           format:0
1193                                                                 errorDescription:0];
1194    NSUInteger position = 0;
1195    JSValue value;
1196    while (demarshalValueFromArray(exec, array.get(), position, value))
1197        result.append(value);
1198}
1199
1200PassRefPtr<Instance> NetscapePluginInstanceProxy::createBindingsInstance(PassRefPtr<RootObject> rootObject)
1201{
1202    uint32_t requestID = nextRequestID();
1203
1204    if (_WKPHGetScriptableNPObject(m_pluginHostProxy->port(), m_pluginID, requestID) != KERN_SUCCESS)
1205        return 0;
1206
1207    auto_ptr<GetScriptableNPObjectReply> reply = waitForReply<GetScriptableNPObjectReply>(requestID);
1208    if (!reply.get())
1209        return 0;
1210
1211    if (!reply->m_objectID)
1212        return 0;
1213
1214    return ProxyInstance::create(rootObject, this, reply->m_objectID);
1215}
1216
1217void NetscapePluginInstanceProxy::addInstance(ProxyInstance* instance)
1218{
1219    ASSERT(!m_instances.contains(instance));
1220
1221    m_instances.add(instance);
1222}
1223
1224void NetscapePluginInstanceProxy::removeInstance(ProxyInstance* instance)
1225{
1226    ASSERT(m_instances.contains(instance));
1227
1228    m_instances.remove(instance);
1229}
1230
1231void NetscapePluginInstanceProxy::willCallPluginFunction()
1232{
1233    m_pluginFunctionCallDepth++;
1234}
1235
1236void NetscapePluginInstanceProxy::didCallPluginFunction()
1237{
1238    ASSERT(m_pluginFunctionCallDepth > 0);
1239    m_pluginFunctionCallDepth--;
1240
1241    // If -stop was called while we were calling into a plug-in function, and we're no longer
1242    // inside a plug-in function, stop now.
1243    if (!m_pluginFunctionCallDepth && m_shouldStopSoon) {
1244        m_shouldStopSoon = false;
1245        [m_pluginView stop];
1246    }
1247}
1248
1249bool NetscapePluginInstanceProxy::shouldStop()
1250{
1251    if (m_pluginFunctionCallDepth) {
1252        m_shouldStopSoon = true;
1253        return false;
1254    }
1255
1256    return true;
1257}
1258
1259uint32_t NetscapePluginInstanceProxy::nextRequestID()
1260{
1261    uint32_t requestID = ++m_currentRequestID;
1262
1263    // We don't want to return the HashMap empty/deleted "special keys"
1264    if (requestID == 0 || requestID == static_cast<uint32_t>(-1))
1265        return nextRequestID();
1266
1267    return requestID;
1268}
1269
1270void NetscapePluginInstanceProxy::invalidateRect(double x, double y, double width, double height)
1271{
1272    ASSERT(m_pluginView);
1273
1274    [m_pluginView invalidatePluginContentRect:NSMakeRect(x, y, width, height)];
1275}
1276
1277bool NetscapePluginInstanceProxy::getCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t& cookiesData, mach_msg_type_number_t& cookiesLength)
1278{
1279    ASSERT(m_pluginView);
1280
1281    NSURL *url = [m_pluginView URLWithCString:urlData];
1282    if (!url)
1283        return false;
1284
1285    if (Frame* frame = core([m_pluginView webFrame])) {
1286        String cookieString = cookies(frame->document(), url);
1287        WebCore::CString cookieStringUTF8 = cookieString.utf8();
1288        if (cookieStringUTF8.isNull())
1289            return false;
1290
1291        cookiesLength = cookieStringUTF8.length();
1292        mig_allocate(reinterpret_cast<vm_address_t*>(&cookiesData), cookiesLength);
1293        memcpy(cookiesData, cookieStringUTF8.data(), cookiesLength);
1294
1295        return true;
1296    }
1297
1298    return false;
1299}
1300
1301bool NetscapePluginInstanceProxy::setCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t cookiesData, mach_msg_type_number_t cookiesLength)
1302{
1303    ASSERT(m_pluginView);
1304
1305    NSURL *url = [m_pluginView URLWithCString:urlData];
1306    if (!url)
1307        return false;
1308
1309    if (Frame* frame = core([m_pluginView webFrame])) {
1310        String cookieString = String::fromUTF8(cookiesData, cookiesLength);
1311        if (!cookieString)
1312            return false;
1313
1314        WebCore::setCookies(frame->document(), url, cookieString);
1315        return true;
1316    }
1317
1318    return false;
1319}
1320
1321bool NetscapePluginInstanceProxy::getProxy(data_t urlData, mach_msg_type_number_t urlLength, data_t& proxyData, mach_msg_type_number_t& proxyLength)
1322{
1323    ASSERT(m_pluginView);
1324
1325    NSURL *url = [m_pluginView URLWithCString:urlData];
1326    if (!url)
1327        return false;
1328
1329    WebCore::CString proxyStringUTF8 = proxiesForURL(url);
1330
1331    proxyLength = proxyStringUTF8.length();
1332    mig_allocate(reinterpret_cast<vm_address_t*>(&proxyData), proxyLength);
1333    memcpy(proxyData, proxyStringUTF8.data(), proxyLength);
1334
1335    return true;
1336}
1337
1338bool NetscapePluginInstanceProxy::getAuthenticationInfo(data_t protocolData, data_t hostData, uint32_t port, data_t schemeData, data_t realmData,
1339                                                        data_t& usernameData, mach_msg_type_number_t& usernameLength, data_t& passwordData, mach_msg_type_number_t& passwordLength)
1340{
1341    WebCore::CString username;
1342    WebCore::CString password;
1343
1344    if (!WebKit::getAuthenticationInfo(protocolData, hostData, port, schemeData, realmData, username, password))
1345        return false;
1346
1347    usernameLength = username.length();
1348    mig_allocate(reinterpret_cast<vm_address_t*>(&usernameData), usernameLength);
1349    memcpy(usernameData, username.data(), usernameLength);
1350
1351    passwordLength = password.length();
1352    mig_allocate(reinterpret_cast<vm_address_t*>(&passwordData), passwordLength);
1353    memcpy(passwordData, password.data(), passwordLength);
1354
1355    return true;
1356}
1357
1358bool NetscapePluginInstanceProxy::convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
1359                                               double& destX, double& destY, NPCoordinateSpace destSpace)
1360{
1361    ASSERT(m_pluginView);
1362
1363    return [m_pluginView convertFromX:sourceX andY:sourceY space:sourceSpace toX:&destX andY:&destY space:destSpace];
1364}
1365
1366uint32_t NetscapePluginInstanceProxy::checkIfAllowedToLoadURL(const char* url, const char* target)
1367{
1368    uint32_t checkID;
1369
1370    // Assign a check ID
1371    do {
1372        checkID = ++m_urlCheckCounter;
1373    } while (m_urlChecks.contains(checkID) || !m_urlCheckCounter);
1374
1375    NSString *frameName = target ? [NSString stringWithCString:target encoding:NSISOLatin1StringEncoding] : nil;
1376
1377    NSNumber *contextInfo = [[NSNumber alloc] initWithUnsignedInt:checkID];
1378    WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[m_pluginView requestWithURLCString:url]
1379                                                                        target:frameName
1380                                                                  resultObject:m_pluginView
1381                                                                      selector:@selector(_containerCheckResult:contextInfo:)
1382                                                                    controller:m_pluginView
1383                                                                   contextInfo:contextInfo];
1384
1385    [contextInfo release];
1386    m_urlChecks.set(checkID, check);
1387    [check start];
1388
1389    return checkID;
1390}
1391
1392void NetscapePluginInstanceProxy::cancelCheckIfAllowedToLoadURL(uint32_t checkID)
1393{
1394    URLCheckMap::iterator it = m_urlChecks.find(checkID);
1395    if (it == m_urlChecks.end())
1396        return;
1397
1398    WebPluginContainerCheck *check = it->second.get();
1399    [check cancel];
1400    m_urlChecks.remove(it);
1401}
1402
1403void NetscapePluginInstanceProxy::checkIfAllowedToLoadURLResult(uint32_t checkID, bool allowed)
1404{
1405    _WKPHCheckIfAllowedToLoadURLResult(m_pluginHostProxy->port(), m_pluginID, checkID, allowed);
1406}
1407
1408void NetscapePluginInstanceProxy::resolveURL(const char* url, const char* target, data_t& resolvedURLData, mach_msg_type_number_t& resolvedURLLength)
1409{
1410    ASSERT(m_pluginView);
1411
1412    WebCore::CString resolvedURL = [m_pluginView resolvedURLStringForURL:url target:target];
1413
1414    resolvedURLLength = resolvedURL.length();
1415    mig_allocate(reinterpret_cast<vm_address_t*>(&resolvedURLData), resolvedURLLength);
1416    memcpy(resolvedURLData, resolvedURL.data(), resolvedURLLength);
1417}
1418
1419} // namespace WebKit
1420
1421#endif // USE(PLUGIN_HOST_PROCESS)
1422