<https://webkit.org/b/119852> Frame::scriptController() should return a reference
[WebKit-https.git] / Source / WebKit / mac / Plugins / Hosted / NetscapePluginInstanceProxy.mm
1 /*
2  * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 "NetscapePluginInstanceProxy.h"
29
30 #import "HostedNetscapePluginStream.h"
31 #import "NetscapePluginHostProxy.h"
32 #import "ProxyInstance.h"
33 #import "ProxyRuntimeObject.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebFrameInternal.h"
36 #import "WebHostedNetscapePluginView.h"
37 #import "WebKitNSStringExtras.h"
38 #import "WebNSDataExtras.h"
39 #import "WebNSURLExtras.h"
40 #import "WebPluginRequest.h"
41 #import "WebUIDelegate.h"
42 #import "WebUIDelegatePrivate.h"
43 #import "WebViewInternal.h"
44 #import <JavaScriptCore/Completion.h>
45 #import <JavaScriptCore/Error.h>
46 #import <JavaScriptCore/JSLock.h>
47 #import <JavaScriptCore/PropertyNameArray.h>
48 #import <JavaScriptCore/SourceCode.h>
49 #import <JavaScriptCore/StrongInlines.h>
50 #import <WebCore/CookieJar.h>
51 #import <WebCore/DocumentLoader.h>
52 #import <WebCore/Frame.h>
53 #import <WebCore/FrameLoader.h>
54 #import <WebCore/FrameTree.h>
55 #import <WebCore/KURL.h>
56 #import <WebCore/ProxyServer.h>
57 #import <WebCore/SecurityOrigin.h>
58 #import <WebCore/ScriptController.h>
59 #import <WebCore/ScriptValue.h>
60 #import <WebCore/UserGestureIndicator.h>
61 #import <WebCore/npruntime_impl.h>
62 #import <WebCore/runtime_object.h>
63 #import <WebKitSystemInterface.h>
64 #import <mach/mach.h>
65 #import <utility>
66 #import <wtf/RefCountedLeakCounter.h>
67 #import <wtf/text/CString.h>
68
69 extern "C" {
70 #import "WebKitPluginClientServer.h"
71 #import "WebKitPluginHost.h"
72 }
73
74 using namespace JSC;
75 using namespace JSC::Bindings;
76 using namespace WebCore;
77
78 namespace WebKit {
79
80 class NetscapePluginInstanceProxy::PluginRequest : public RefCounted<NetscapePluginInstanceProxy::PluginRequest> {
81 public:
82     static PassRefPtr<PluginRequest> create(uint32_t requestID, NSURLRequest* request, NSString* frameName, bool allowPopups)
83     {
84         return adoptRef(new PluginRequest(requestID, request, frameName, allowPopups));
85     }
86
87     uint32_t requestID() const { return m_requestID; }
88     NSURLRequest* request() const { return m_request.get(); }
89     NSString* frameName() const { return m_frameName.get(); }
90     bool allowPopups() const { return m_allowPopups; }
91     
92 private:
93     PluginRequest(uint32_t requestID, NSURLRequest* request, NSString* frameName, bool allowPopups)
94         : m_requestID(requestID)
95         , m_request(request)
96         , m_frameName(frameName)
97         , m_allowPopups(allowPopups)
98     {
99     }
100     
101     uint32_t m_requestID;
102     RetainPtr<NSURLRequest*> m_request;
103     RetainPtr<NSString*> m_frameName;
104     bool m_allowPopups;
105 };
106
107 NetscapePluginInstanceProxy::LocalObjectMap::LocalObjectMap()
108     : m_objectIDCounter(0)
109 {
110 }
111
112 NetscapePluginInstanceProxy::LocalObjectMap::~LocalObjectMap()
113 {
114 }
115
116 inline bool NetscapePluginInstanceProxy::LocalObjectMap::contains(uint32_t objectID) const
117 {
118     return m_idToJSObjectMap.contains(objectID);
119 }
120
121 inline JSC::JSObject* NetscapePluginInstanceProxy::LocalObjectMap::get(uint32_t objectID) const
122 {
123     if (objectID == HashTraits<uint32_t>::emptyValue() || HashTraits<uint32_t>::isDeletedValue(objectID))
124         return 0;
125
126     return m_idToJSObjectMap.get(objectID).get();
127 }
128
129 uint32_t NetscapePluginInstanceProxy::LocalObjectMap::idForObject(VM& vm, JSObject* object)
130 {
131     // This method creates objects with refcount of 1, but doesn't increase refcount when returning
132     // found objects. This extra count accounts for the main "reference" kept by plugin process.
133
134     // To avoid excessive IPC, plugin process doesn't send each NPObject release/retain call to
135     // Safari. It only sends one when the last reference is removed, and it can destroy the proxy
136     // NPObject.
137
138     // However, the browser may be sending the same object out to plug-in as a function call
139     // argument at the same time - neither side can know what the other one is doing. So,
140     // is to make PCForgetBrowserObject call return a boolean result, making it possible for 
141     // the browser to make plugin host keep the proxy with zero refcount for a little longer.
142
143     uint32_t objectID = 0;
144     
145     HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> >::iterator iter = m_jsObjectToIDMap.find(object);
146     if (iter != m_jsObjectToIDMap.end())
147         return iter->value.first;
148     
149     do {
150         objectID = ++m_objectIDCounter;
151     } while (!m_objectIDCounter || m_objectIDCounter == static_cast<uint32_t>(-1) || m_idToJSObjectMap.contains(objectID));
152
153     m_idToJSObjectMap.set(objectID, Strong<JSObject>(vm, object));
154     m_jsObjectToIDMap.set(object, std::make_pair(objectID, 1));
155
156     return objectID;
157 }
158
159 void NetscapePluginInstanceProxy::LocalObjectMap::retain(JSC::JSObject* object)
160 {
161     HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> >::iterator iter = m_jsObjectToIDMap.find(object);
162     ASSERT(iter != m_jsObjectToIDMap.end());
163
164     iter->value.second = iter->value.second + 1;
165 }
166
167 void NetscapePluginInstanceProxy::LocalObjectMap::release(JSC::JSObject* object)
168 {
169     HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> >::iterator iter = m_jsObjectToIDMap.find(object);
170     ASSERT(iter != m_jsObjectToIDMap.end());
171
172     ASSERT(iter->value.second > 0);
173     iter->value.second = iter->value.second - 1;
174     if (!iter->value.second) {
175         m_idToJSObjectMap.remove(iter->value.first);
176         m_jsObjectToIDMap.remove(iter);
177     }
178 }
179
180 void NetscapePluginInstanceProxy::LocalObjectMap::clear()
181 {
182     m_idToJSObjectMap.clear();
183     m_jsObjectToIDMap.clear();
184 }
185
186 bool NetscapePluginInstanceProxy::LocalObjectMap::forget(uint32_t objectID)
187 {
188     if (objectID == HashTraits<uint32_t>::emptyValue() || HashTraits<uint32_t>::isDeletedValue(objectID)) {
189         LOG_ERROR("NetscapePluginInstanceProxy::LocalObjectMap::forget: local object id %u is not valid.", objectID);
190         return true;
191     }
192
193     HashMap<uint32_t, JSC::Strong<JSC::JSObject> >::iterator iter = m_idToJSObjectMap.find(objectID);
194     if (iter == m_idToJSObjectMap.end()) {
195         LOG_ERROR("NetscapePluginInstanceProxy::LocalObjectMap::forget: local object %u doesn't exist.", objectID);
196         return true;
197     }
198
199     HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> >::iterator rIter = m_jsObjectToIDMap.find(iter->value.get());
200
201     // If the object is being sent to plug-in right now, then it's not the time to forget.
202     if (rIter->value.second != 1)
203         return false;
204
205     m_jsObjectToIDMap.remove(rIter);
206     m_idToJSObjectMap.remove(iter);
207     return true;
208 }
209
210 static uint32_t pluginIDCounter;
211
212 bool NetscapePluginInstanceProxy::m_inDestroy;
213
214 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, netscapePluginInstanceProxyCounter, ("NetscapePluginInstanceProxy"));
215
216 NetscapePluginInstanceProxy::NetscapePluginInstanceProxy(NetscapePluginHostProxy* pluginHostProxy, WebHostedNetscapePluginView *pluginView, bool fullFramePlugin)
217     : m_pluginHostProxy(pluginHostProxy)
218     , m_pluginView(pluginView)
219     , m_requestTimer(this, &NetscapePluginInstanceProxy::requestTimerFired)
220     , m_currentURLRequestID(0)
221     , m_renderContextID(0)
222     , m_rendererType(UseSoftwareRenderer)
223     , m_waitingForReply(false)
224     , m_urlCheckCounter(0)
225     , m_pluginFunctionCallDepth(0)
226     , m_shouldStopSoon(false)
227     , m_currentRequestID(0)
228     , m_pluginIsWaitingForDraw(false)
229 {
230     ASSERT(m_pluginView);
231     
232     if (fullFramePlugin) {
233         // For full frame plug-ins, the first requestID will always be the one for the already
234         // open stream.
235         ++m_currentURLRequestID;
236     }
237     
238     // Assign a plug-in ID.
239     do {
240         m_pluginID = ++pluginIDCounter;
241     } while (pluginHostProxy->pluginInstance(m_pluginID) || !m_pluginID);
242
243 #ifndef NDEBUG
244     netscapePluginInstanceProxyCounter.increment();
245 #endif
246 }
247
248 PassRefPtr<NetscapePluginInstanceProxy> NetscapePluginInstanceProxy::create(NetscapePluginHostProxy* pluginHostProxy, WebHostedNetscapePluginView *pluginView, bool fullFramePlugin)
249 {
250     RefPtr<NetscapePluginInstanceProxy> proxy = adoptRef(new NetscapePluginInstanceProxy(pluginHostProxy, pluginView, fullFramePlugin));
251     pluginHostProxy->addPluginInstance(proxy.get());
252     return proxy.release();
253 }
254
255 NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy()
256 {
257     ASSERT(!m_pluginHostProxy);
258     
259     m_pluginID = 0;
260     deleteAllValues(m_replies);
261
262 #ifndef NDEBUG
263     netscapePluginInstanceProxyCounter.decrement();
264 #endif
265 }
266
267 void NetscapePluginInstanceProxy::resize(NSRect size, NSRect clipRect)
268 {
269     uint32_t requestID = 0;
270     
271     requestID = nextRequestID();
272
273     _WKPHResizePluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID,
274                               size.origin.x, size.origin.y, size.size.width, size.size.height,
275                               clipRect.origin.x, clipRect.origin.y, clipRect.size.width, clipRect.size.height);
276     
277     waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
278 }
279
280
281 void NetscapePluginInstanceProxy::setShouldHostLayersInWindowServer(bool shouldHostLayersInWindowServer)
282 {
283     _WKPHPluginShouldHostLayersInWindowServerChanged(m_pluginHostProxy->port(), m_pluginID, shouldHostLayersInWindowServer);
284 }
285
286 void NetscapePluginInstanceProxy::layerHostingModeChanged(bool hostsLayersInWindowServer, uint32_t renderContextID)
287 {
288     setRenderContextID(renderContextID);
289
290     [m_pluginView setHostsLayersInWindowServer:hostsLayersInWindowServer];
291 }
292
293 void NetscapePluginInstanceProxy::stopAllStreams()
294 {
295     Vector<RefPtr<HostedNetscapePluginStream> > streamsCopy;
296     copyValuesToVector(m_streams, streamsCopy);
297     for (size_t i = 0; i < streamsCopy.size(); i++)
298         streamsCopy[i]->stop();
299 }
300
301 void NetscapePluginInstanceProxy::cleanup()
302 {
303     stopAllStreams();
304     
305     m_requestTimer.stop();
306     
307     // Clear the object map, this will cause any outstanding JS objects that the plug-in had a reference to 
308     // to go away when the next garbage collection takes place.
309     m_localObjects.clear();
310     
311     if (Frame* frame = core([m_pluginView webFrame]))
312         frame->script().cleanupScriptObjectsForPlugin(m_pluginView);
313     
314     ProxyInstanceSet instances;
315     instances.swap(m_instances);
316     
317     // Invalidate all proxy instances.
318     ProxyInstanceSet::const_iterator end = instances.end();
319     for (ProxyInstanceSet::const_iterator it = instances.begin(); it != end; ++it)
320         (*it)->invalidate();
321     
322     m_pluginView = nil;
323     m_manualStream = 0;
324 }
325
326 void NetscapePluginInstanceProxy::invalidate()
327 {
328     // If the plug-in host has died, the proxy will be null.
329     if (!m_pluginHostProxy)
330         return;
331     
332     m_pluginHostProxy->removePluginInstance(this);
333     m_pluginHostProxy = 0;
334 }
335
336 void NetscapePluginInstanceProxy::destroy()
337 {
338     uint32_t requestID = nextRequestID();
339
340     ASSERT(!m_inDestroy);
341     m_inDestroy = true;
342     
343     FrameLoadMap::iterator end = m_pendingFrameLoads.end();
344     for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(); it != end; ++it)
345         [(it->key) _setInternalLoadDelegate:nil];
346
347     _WKPHDestroyPluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID);
348  
349     // If the plug-in host crashes while we're waiting for a reply, the last reference to the instance proxy
350     // will go away. Prevent this by protecting it here.
351     RefPtr<NetscapePluginInstanceProxy> protect(this);
352     
353     // We don't care about the reply here - we just want to block until the plug-in instance has been torn down.
354     waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
355
356     m_inDestroy = false;
357     
358     cleanup();
359     invalidate();
360 }
361
362 void NetscapePluginInstanceProxy::setManualStream(PassRefPtr<HostedNetscapePluginStream> manualStream) 
363 {
364     ASSERT(!m_manualStream);
365     
366     m_manualStream = manualStream;
367 }
368
369 bool NetscapePluginInstanceProxy::cancelStreamLoad(uint32_t streamID, NPReason reason) 
370 {
371     HostedNetscapePluginStream* stream = 0;
372     
373     if (m_manualStream && streamID == 1)
374         stream = m_manualStream.get();
375     else
376         stream = m_streams.get(streamID);
377     
378     if (!stream)
379         return false;
380     
381     stream->cancelLoad(reason);
382     return true;
383 }
384
385 void NetscapePluginInstanceProxy::disconnectStream(HostedNetscapePluginStream* stream)
386 {
387     if (stream == m_manualStream) {
388         m_manualStream = 0;
389         return;
390     }
391
392     ASSERT(m_streams.get(stream->streamID()) == stream);
393     m_streams.remove(stream->streamID());
394 }
395     
396 void NetscapePluginInstanceProxy::pluginHostDied()
397 {
398     m_pluginHostProxy = 0;
399
400     [m_pluginView pluginHostDied];
401
402     cleanup();
403 }
404
405 void NetscapePluginInstanceProxy::focusChanged(bool hasFocus)
406 {
407     _WKPHPluginInstanceFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus);
408 }
409
410 void NetscapePluginInstanceProxy::windowFocusChanged(bool hasFocus)
411 {
412     _WKPHPluginInstanceWindowFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus);
413 }
414
415 void NetscapePluginInstanceProxy::windowFrameChanged(NSRect frame)
416 {
417     _WKPHPluginInstanceWindowFrameChanged(m_pluginHostProxy->port(), m_pluginID, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height,
418                                           NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]));
419 }
420     
421 void NetscapePluginInstanceProxy::startTimers(bool throttleTimers)
422 {
423     _WKPHPluginInstanceStartTimers(m_pluginHostProxy->port(), m_pluginID, throttleTimers);
424 }
425     
426 void NetscapePluginInstanceProxy::mouseEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type)
427 {
428     NSPoint screenPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
429     NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil];
430     
431     int clickCount;
432     if (type == NPCocoaEventMouseEntered || type == NPCocoaEventMouseExited)
433         clickCount = 0;
434     else
435         clickCount = [event clickCount];
436     
437
438     _WKPHPluginInstanceMouseEvent(m_pluginHostProxy->port(), m_pluginID,
439                                   [event timestamp],
440                                   type, [event modifierFlags],
441                                   pluginPoint.x, pluginPoint.y,
442                                   screenPoint.x, screenPoint.y,
443                                   NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]),
444                                   [event buttonNumber], clickCount, 
445                                   [event deltaX], [event deltaY], [event deltaZ]);
446 }
447     
448 void NetscapePluginInstanceProxy::keyEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type)
449 {
450     NSData *charactersData = [[event characters] dataUsingEncoding:NSUTF8StringEncoding];
451     NSData *charactersIgnoringModifiersData = [[event charactersIgnoringModifiers] dataUsingEncoding:NSUTF8StringEncoding];
452     
453     _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID,
454                                      [event timestamp], 
455                                      type, [event modifierFlags], 
456                                      const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], 
457                                      const_cast<char*>(reinterpret_cast<const char*>([charactersIgnoringModifiersData bytes])), [charactersIgnoringModifiersData length], 
458                                      [event isARepeat], [event keyCode], WKGetNSEventKeyChar(event));
459 }
460
461 void NetscapePluginInstanceProxy::syntheticKeyDownWithCommandModifier(int keyCode, char character)
462 {
463     NSData *charactersData = [NSData dataWithBytes:&character length:1];
464
465     _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID, 
466                                      [NSDate timeIntervalSinceReferenceDate], 
467                                      NPCocoaEventKeyDown, NSCommandKeyMask,
468                                      const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], 
469                                      const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], 
470                                      false, keyCode, character);
471 }
472
473 void NetscapePluginInstanceProxy::flagsChanged(NSEvent *event)
474 {
475     _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID, 
476                                      [event timestamp], NPCocoaEventFlagsChanged, 
477                                      [event modifierFlags], 0, 0, 0, 0, false, [event keyCode], 0);
478 }
479
480 void NetscapePluginInstanceProxy::insertText(NSString *text)
481 {
482     NSData *textData = [text dataUsingEncoding:NSUTF8StringEncoding];
483     
484     _WKPHPluginInstanceInsertText(m_pluginHostProxy->port(), m_pluginID,
485                                   const_cast<char*>(reinterpret_cast<const char*>([textData bytes])), [textData length]);
486 }
487
488 bool NetscapePluginInstanceProxy::wheelEvent(NSView *pluginView, NSEvent *event)
489 {
490     NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil];
491
492     uint32_t requestID = nextRequestID();
493     _WKPHPluginInstanceWheelEvent(m_pluginHostProxy->port(), m_pluginID, requestID,
494                                   [event timestamp], [event modifierFlags], 
495                                   pluginPoint.x, pluginPoint.y, [event buttonNumber], 
496                                   [event deltaX], [event deltaY], [event deltaZ]);
497     
498     std::auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID);
499     if (!reply.get() || !reply->m_result)
500         return false;
501     
502     return true;
503 }
504
505 void NetscapePluginInstanceProxy::print(CGContextRef context, unsigned width, unsigned height)
506 {
507     uint32_t requestID = nextRequestID();
508     _WKPHPluginInstancePrint(m_pluginHostProxy->port(), m_pluginID, requestID, width, height);
509     
510     std::auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID);
511     if (!reply.get() || !reply->m_returnValue)
512         return;
513
514     RetainPtr<CGDataProvider> dataProvider = adoptCF(CGDataProviderCreateWithCFData(reply->m_result.get()));
515     RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
516     RetainPtr<CGImageRef> image = adoptCF(CGImageCreate(width, height, 8, 32, width * 4, colorSpace.get(), kCGImageAlphaFirst, dataProvider.get(), 0, false, kCGRenderingIntentDefault));
517
518     // Flip the context and draw the image.
519     CGContextSaveGState(context);
520     CGContextTranslateCTM(context, 0.0, height);
521     CGContextScaleCTM(context, 1.0, -1.0);
522     
523     CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.get());
524
525     CGContextRestoreGState(context);
526 }
527
528 void NetscapePluginInstanceProxy::snapshot(CGContextRef context, unsigned width, unsigned height)
529 {
530     uint32_t requestID = nextRequestID();
531     _WKPHPluginInstanceSnapshot(m_pluginHostProxy->port(), m_pluginID, requestID, width, height);
532     
533     std::auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID);
534     if (!reply.get() || !reply->m_returnValue)
535         return;
536
537     RetainPtr<CGDataProvider> dataProvider = adoptCF(CGDataProviderCreateWithCFData(reply->m_result.get()));
538     RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
539     RetainPtr<CGImageRef> image = adoptCF(CGImageCreate(width, height, 8, 32, width * 4, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, dataProvider.get(), 0, false, kCGRenderingIntentDefault));
540
541     CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.get());
542 }
543
544 void NetscapePluginInstanceProxy::stopTimers()
545 {
546     _WKPHPluginInstanceStopTimers(m_pluginHostProxy->port(), m_pluginID);
547 }
548
549 void NetscapePluginInstanceProxy::status(const char* message)
550 {
551     RetainPtr<CFStringRef> status = adoptCF(CFStringCreateWithCString(0, message ? message : "", kCFStringEncodingUTF8));
552     if (!status)
553         return;
554
555     WebView *wv = [m_pluginView webView];
556     [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status.get()];
557 }
558
559 NPError NetscapePluginInstanceProxy::loadURL(const char* url, const char* target, const char* postData, uint32_t postLen, LoadURLFlags flags, uint32_t& streamID)
560 {
561     if (!url)
562         return NPERR_INVALID_PARAM;
563  
564     NSMutableURLRequest *request = [m_pluginView requestWithURLCString:url];
565
566     if (flags & IsPost) {
567         NSData *httpBody = nil;
568
569         if (flags & PostDataIsFile) {
570             // If we're posting a file, buf is either a file URL or a path to the file.
571             if (!postData)
572                 return NPERR_INVALID_PARAM;
573             RetainPtr<CFStringRef> bufString = adoptCF(CFStringCreateWithCString(kCFAllocatorDefault, postData, kCFStringEncodingWindowsLatin1));
574             if (!bufString)
575                 return NPERR_INVALID_PARAM;
576             
577             NSURL *fileURL = [NSURL _web_URLWithDataAsString:(NSString *)bufString.get()];
578             NSString *path;
579             if ([fileURL isFileURL])
580                 path = [fileURL path];
581             else
582                 path = (NSString *)bufString.get();
583             httpBody = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
584             if (!httpBody)
585                 return NPERR_FILE_NOT_FOUND;
586         } else
587             httpBody = [NSData dataWithBytes:postData length:postLen];
588
589         if (![httpBody length])
590             return NPERR_INVALID_PARAM;
591
592         [request setHTTPMethod:@"POST"];
593         
594         if (flags & AllowHeadersInPostData) {
595             if ([httpBody _web_startsWithBlankLine])
596                 httpBody = [httpBody subdataWithRange:NSMakeRange(1, [httpBody length] - 1)];
597             else {
598                 NSInteger location = [httpBody _web_locationAfterFirstBlankLine];
599                 if (location != NSNotFound) {
600                     // If the blank line is somewhere in the middle of postData, everything before is the header.
601                     NSData *headerData = [httpBody subdataWithRange:NSMakeRange(0, location)];
602                     NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
603                     unsigned dataLength = [httpBody length] - location;
604
605                     // Sometimes plugins like to set Content-Length themselves when they post,
606                     // but CFNetwork does not like that. So we will remove the header
607                     // and instead truncate the data to the requested length.
608                     NSString *contentLength = [header objectForKey:@"Content-Length"];
609
610                     if (contentLength)
611                         dataLength = std::min(static_cast<unsigned>([contentLength intValue]), dataLength);
612                     [header removeObjectForKey:@"Content-Length"];
613
614                     if ([header count] > 0)
615                         [request setAllHTTPHeaderFields:header];
616
617                     // Everything after the blank line is the actual content of the POST.
618                     httpBody = [httpBody subdataWithRange:NSMakeRange(location, dataLength)];
619                 }
620             }
621         }
622
623         if (![httpBody length])
624             return NPERR_INVALID_PARAM;
625
626         // Plug-ins expect to receive uncached data when doing a POST (3347134).
627         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
628         [request setHTTPBody:httpBody];
629     }
630     
631     return loadRequest(request, target, flags & AllowPopups, streamID);
632 }
633
634 void NetscapePluginInstanceProxy::performRequest(PluginRequest* pluginRequest)
635 {
636     // Loading the request can cause the instance proxy to go away, so protect it.
637     RefPtr<NetscapePluginInstanceProxy> protect(this);
638
639     ASSERT(m_pluginView);
640     
641     NSURLRequest *request = pluginRequest->request();
642     NSString *frameName = pluginRequest->frameName();
643     WebFrame *frame = nil;
644     
645     NSURL *URL = [request URL];
646     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
647     
648     ASSERT(frameName || JSString);
649     if (frameName) {
650         // FIXME - need to get rid of this window creation which
651         // bypasses normal targeted link handling
652         frame = kit(core([m_pluginView webFrame])->loader().findFrameForNavigation(frameName));
653         if (!frame) {
654             WebView *currentWebView = [m_pluginView webView];
655             NSDictionary *features = [[NSDictionary alloc] init];
656             WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
657                                                         createWebViewWithRequest:nil
658                                                                   windowFeatures:features];
659             [features release];
660
661             if (!newWebView) {
662                 _WKPHLoadURLNotify(m_pluginHostProxy->port(), m_pluginID, pluginRequest->requestID(), NPERR_GENERIC_ERROR);
663                 return;
664             }
665             
666             frame = [newWebView mainFrame];
667             core(frame)->tree()->setName(frameName);
668             [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
669         }
670     }
671
672     if (JSString) {
673         ASSERT(!frame || [m_pluginView webFrame] == frame);
674         evaluateJavaScript(pluginRequest);
675     } else {
676         [frame loadRequest:request];
677
678         // Check if another plug-in view or even this view is waiting for the frame to load.
679         // If it is, tell it that the load was cancelled because it will be anyway.
680         WebHostedNetscapePluginView *view = [frame _internalLoadDelegate];
681         if (view != nil) {
682             ASSERT([view isKindOfClass:[WebHostedNetscapePluginView class]]);
683             [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK];
684         }
685         m_pendingFrameLoads.set(frame, pluginRequest);
686         [frame _setInternalLoadDelegate:m_pluginView];
687     }
688
689 }
690
691 void NetscapePluginInstanceProxy::webFrameDidFinishLoadWithReason(WebFrame* webFrame, NPReason reason)
692 {
693     FrameLoadMap::iterator it = m_pendingFrameLoads.find(webFrame);
694     ASSERT(it != m_pendingFrameLoads.end());
695         
696     PluginRequest* pluginRequest = it->value.get();
697     _WKPHLoadURLNotify(m_pluginHostProxy->port(), m_pluginID, pluginRequest->requestID(), reason);
698  
699     m_pendingFrameLoads.remove(it);
700
701     [webFrame _setInternalLoadDelegate:nil];
702 }
703
704 void NetscapePluginInstanceProxy::evaluateJavaScript(PluginRequest* pluginRequest)
705 {
706     NSURL *URL = [pluginRequest->request() URL];
707     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
708     ASSERT(JSString);
709
710     RefPtr<NetscapePluginInstanceProxy> protect(this); // Executing arbitrary JavaScript can destroy the proxy.
711
712     NSString *result = [[m_pluginView webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:pluginRequest->allowPopups()];
713     
714     // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
715     if (!m_pluginHostProxy)
716         return;
717
718     if (pluginRequest->frameName() != nil)
719         return;
720         
721     if ([result length] > 0) {
722         // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
723         NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
724         
725         RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, pluginRequest->requestID(), pluginRequest->request());
726         m_streams.add(stream->streamID(), stream);
727         
728         RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:URL 
729                                                                              MIMEType:@"text/plain" 
730                                                                 expectedContentLength:[JSData length]
731                                                                      textEncodingName:nil]);
732         stream->startStreamWithResponse(response.get());
733         stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]);
734         stream->didFinishLoading(0);
735     }
736 }
737
738 void NetscapePluginInstanceProxy::requestTimerFired(Timer<NetscapePluginInstanceProxy>*)
739 {
740     ASSERT(!m_pluginRequests.isEmpty());
741     ASSERT(m_pluginView);
742     
743     RefPtr<PluginRequest> request = m_pluginRequests.first();
744     m_pluginRequests.removeFirst();
745     
746     if (!m_pluginRequests.isEmpty())
747         m_requestTimer.startOneShot(0);
748     
749     performRequest(request.get());
750 }
751     
752 NPError NetscapePluginInstanceProxy::loadRequest(NSURLRequest *request, const char* cTarget, bool allowPopups, uint32_t& requestID)
753 {
754     NSURL *URL = [request URL];
755
756     if (!URL) 
757         return NPERR_INVALID_URL;
758
759     // Don't allow requests to be loaded when the document loader is stopping all loaders.
760     DocumentLoader* documentLoader = [[m_pluginView dataSource] _documentLoader];
761     if (!documentLoader || documentLoader->isStopping())
762         return NPERR_GENERIC_ERROR;
763
764     NSString *target = nil;
765     if (cTarget) {
766         // Find the frame given the target string.
767         target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding];
768     }
769     WebFrame *frame = [m_pluginView webFrame];
770
771     // don't let a plugin start any loads if it is no longer part of a document that is being 
772     // displayed unless the loads are in the same frame as the plugin.
773     if (documentLoader != core([m_pluginView webFrame])->loader().activeDocumentLoader() &&
774         (!cTarget || [frame findFrameNamed:target] != frame)) {
775         return NPERR_GENERIC_ERROR; 
776     }
777     
778     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
779     if (JSString != nil) {
780         if (![[[m_pluginView webView] preferences] isJavaScriptEnabled]) {
781             // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
782             return NPERR_GENERIC_ERROR;
783         }
784     } else {
785         if (!core([m_pluginView webFrame])->document()->securityOrigin()->canDisplay(URL))
786             return NPERR_GENERIC_ERROR;
787     }
788     
789     // FIXME: Handle wraparound
790     requestID = ++m_currentURLRequestID;
791         
792     if (cTarget || JSString) {
793         // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
794         // want to potentially kill the plug-in inside of its URL request.
795         
796         if (JSString && target && [frame findFrameNamed:target] != frame) {
797             // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
798             return NPERR_INVALID_PARAM;
799         }
800
801         RefPtr<PluginRequest> pluginRequest = PluginRequest::create(requestID, request, target, allowPopups);
802         m_pluginRequests.append(pluginRequest.release());
803         m_requestTimer.startOneShot(0);
804     } else {
805         RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, requestID, request);
806
807         ASSERT(!m_streams.contains(requestID));
808         m_streams.add(requestID, stream);
809         stream->start();
810     }
811     
812     return NPERR_NO_ERROR;
813 }
814
815 NetscapePluginInstanceProxy::Reply* NetscapePluginInstanceProxy::processRequestsAndWaitForReply(uint32_t requestID)
816 {
817     Reply* reply = 0;
818
819     ASSERT(m_pluginHostProxy);
820     while (!(reply = m_replies.take(requestID))) {
821         if (!m_pluginHostProxy->processRequests())
822             return 0;
823
824         // The host proxy can be destroyed while executing a nested processRequests() call, in which case it's normal
825         // to get a success result, but be unable to keep looping.
826         if (!m_pluginHostProxy)
827             return 0;
828     }
829     
830     ASSERT(reply);
831     return reply;
832 }
833     
834 // NPRuntime support
835 bool NetscapePluginInstanceProxy::getWindowNPObject(uint32_t& objectID)
836 {
837     Frame* frame = core([m_pluginView webFrame]);
838     if (!frame)
839         return false;
840     
841     if (!frame->script().canExecuteScripts(NotAboutToExecuteScript))
842         objectID = 0;
843     else
844         objectID = m_localObjects.idForObject(*pluginWorld()->vm(), frame->script().windowShell(pluginWorld())->window());
845         
846     return true;
847 }
848
849 bool NetscapePluginInstanceProxy::getPluginElementNPObject(uint32_t& objectID)
850 {
851     Frame* frame = core([m_pluginView webFrame]);
852     if (!frame)
853         return false;
854     
855     if (JSObject* object = frame->script().jsObjectForPluginElement([m_pluginView element]))
856         objectID = m_localObjects.idForObject(*pluginWorld()->vm(), object);
857     else
858         objectID = 0;
859     
860     return true;
861 }
862
863 bool NetscapePluginInstanceProxy::forgetBrowserObjectID(uint32_t objectID)
864 {
865     return m_localObjects.forget(objectID);
866 }
867  
868 bool NetscapePluginInstanceProxy::evaluate(uint32_t objectID, const String& script, data_t& resultData, mach_msg_type_number_t& resultLength, bool allowPopups)
869 {
870     resultData = 0;
871     resultLength = 0;
872
873     if (m_inDestroy)
874         return false;
875
876     if (!m_localObjects.contains(objectID)) {
877         LOG_ERROR("NetscapePluginInstanceProxy::evaluate: local object %u doesn't exist.", objectID);
878         return false;
879     }
880
881     Frame* frame = core([m_pluginView webFrame]);
882     if (!frame)
883         return false;
884
885     JSLockHolder lock(pluginWorld()->vm());
886     Strong<JSGlobalObject> globalObject(*pluginWorld()->vm(), frame->script().globalObject(pluginWorld()));
887     ExecState* exec = globalObject->globalExec();
888
889     UserGestureIndicator gestureIndicator(allowPopups ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
890     
891     JSValue result = JSC::evaluate(exec, makeSource(script));
892     
893     marshalValue(exec, result, resultData, resultLength);
894     exec->clearException();
895     return true;
896 }
897
898 bool 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)
899 {
900     resultData = 0;
901     resultLength = 0;
902     
903     if (m_inDestroy)
904         return false;
905     
906     JSObject* object = m_localObjects.get(objectID);
907     if (!object) {
908         LOG_ERROR("NetscapePluginInstanceProxy::invoke: local object %u doesn't exist.", objectID);
909         return false;
910     }
911     
912     Frame* frame = core([m_pluginView webFrame]);
913     if (!frame)
914         return false;
915     
916     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
917     JSLockHolder lock(exec);
918     JSValue function = object->get(exec, methodName);
919     CallData callData;
920     CallType callType = getCallData(function, callData);
921     if (callType == CallTypeNone)
922         return false;
923
924     MarkedArgumentBuffer argList;
925     demarshalValues(exec, argumentsData, argumentsLength, argList);
926
927     JSValue value = call(exec, function, callType, callData, object, argList);
928         
929     marshalValue(exec, value, resultData, resultLength);
930     exec->clearException();
931     return true;
932 }
933
934 bool NetscapePluginInstanceProxy::invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength)
935 {
936     if (m_inDestroy)
937         return false;
938
939     JSObject* object = m_localObjects.get(objectID);
940     if (!object) {
941         LOG_ERROR("NetscapePluginInstanceProxy::invokeDefault: local object %u doesn't exist.", objectID);
942         return false;
943     }
944     
945     Frame* frame = core([m_pluginView webFrame]);
946     if (!frame)
947         return false;
948     
949     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
950     JSLockHolder lock(exec);    
951     CallData callData;
952     CallType callType = object->methodTable()->getCallData(object, callData);
953     if (callType == CallTypeNone)
954         return false;
955
956     MarkedArgumentBuffer argList;
957     demarshalValues(exec, argumentsData, argumentsLength, argList);
958
959     JSValue value = call(exec, object, callType, callData, object, argList);
960     
961     marshalValue(exec, value, resultData, resultLength);
962     exec->clearException();
963     return true;
964 }
965
966 bool NetscapePluginInstanceProxy::construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength)
967 {
968     if (m_inDestroy)
969         return false;
970
971     JSObject* object = m_localObjects.get(objectID);
972     if (!object) {
973         LOG_ERROR("NetscapePluginInstanceProxy::construct: local object %u doesn't exist.", objectID);
974         return false;
975     }
976     
977     Frame* frame = core([m_pluginView webFrame]);
978     if (!frame)
979         return false;
980     
981     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
982     JSLockHolder lock(exec);
983
984     ConstructData constructData;
985     ConstructType constructType = object->methodTable()->getConstructData(object, constructData);
986     if (constructType == ConstructTypeNone)
987         return false;
988
989     MarkedArgumentBuffer argList;
990     demarshalValues(exec, argumentsData, argumentsLength, argList);
991
992     JSValue value = JSC::construct(exec, object, constructType, constructData, argList);
993     
994     marshalValue(exec, value, resultData, resultLength);
995     exec->clearException();
996     return true;
997 }
998
999 bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, const Identifier& propertyName, data_t& resultData, mach_msg_type_number_t& resultLength)
1000 {
1001     if (m_inDestroy)
1002         return false;
1003
1004     JSObject* object = m_localObjects.get(objectID);
1005     if (!object) {
1006         LOG_ERROR("NetscapePluginInstanceProxy::getProperty: local object %u doesn't exist.", objectID);
1007         return false;
1008     }
1009     
1010     Frame* frame = core([m_pluginView webFrame]);
1011     if (!frame)
1012         return false;
1013     
1014     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1015     JSLockHolder lock(exec);    
1016     JSValue value = object->get(exec, propertyName);
1017     
1018     marshalValue(exec, value, resultData, resultLength);
1019     exec->clearException();
1020     return true;
1021 }
1022     
1023 bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, unsigned propertyName, data_t& resultData, mach_msg_type_number_t& resultLength)
1024 {
1025     JSObject* object = m_localObjects.get(objectID);
1026     if (!object) {
1027         LOG_ERROR("NetscapePluginInstanceProxy::getProperty: local object %u doesn't exist.", objectID);
1028         return false;
1029     }
1030     
1031     Frame* frame = core([m_pluginView webFrame]);
1032     if (!frame)
1033         return false;
1034     
1035     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1036     JSLockHolder lock(exec);    
1037     JSValue value = object->get(exec, propertyName);
1038     
1039     marshalValue(exec, value, resultData, resultLength);
1040     exec->clearException();
1041     return true;
1042 }
1043
1044 bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, const Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength)
1045 {
1046     if (m_inDestroy)
1047         return false;
1048
1049     JSObject* object = m_localObjects.get(objectID);
1050     if (!object) {
1051         LOG_ERROR("NetscapePluginInstanceProxy::setProperty: local object %u doesn't exist.", objectID);
1052         return false;
1053     }
1054     
1055     Frame* frame = core([m_pluginView webFrame]);
1056     if (!frame)
1057         return false;
1058     
1059     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1060     JSLockHolder lock(exec);    
1061
1062     JSValue value = demarshalValue(exec, valueData, valueLength);
1063     PutPropertySlot slot;
1064     object->methodTable()->put(object, exec, propertyName, value, slot);
1065     
1066     exec->clearException();
1067     return true;
1068 }
1069
1070 bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength)
1071 {
1072     if (m_inDestroy)
1073         return false;
1074
1075     JSObject* object = m_localObjects.get(objectID);
1076     if (!object) {
1077         LOG_ERROR("NetscapePluginInstanceProxy::setProperty: local object %u doesn't exist.", objectID);
1078         return false;
1079     }
1080     
1081     Frame* frame = core([m_pluginView webFrame]);
1082     if (!frame)
1083         return false;
1084     
1085     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1086     JSLockHolder lock(exec);    
1087     
1088     JSValue value = demarshalValue(exec, valueData, valueLength);
1089     object->methodTable()->putByIndex(object, exec, propertyName, value, false);
1090     
1091     exec->clearException();
1092     return true;
1093 }
1094
1095 bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, const Identifier& propertyName)
1096 {
1097     if (m_inDestroy)
1098         return false;
1099
1100     JSObject* object = m_localObjects.get(objectID);
1101     if (!object) {
1102         LOG_ERROR("NetscapePluginInstanceProxy::removeProperty: local object %u doesn't exist.", objectID);
1103         return false;
1104     }
1105     
1106     Frame* frame = core([m_pluginView webFrame]);
1107     if (!frame)
1108         return false;
1109
1110     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1111     JSLockHolder lock(exec);
1112     if (!object->hasProperty(exec, propertyName)) {
1113         exec->clearException();
1114         return false;
1115     }
1116     
1117     object->methodTable()->deleteProperty(object, exec, propertyName);
1118     exec->clearException();    
1119     return true;
1120 }
1121     
1122 bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, unsigned propertyName)
1123 {
1124     if (m_inDestroy)
1125         return false;
1126
1127     JSObject* object = m_localObjects.get(objectID);
1128     if (!object) {
1129         LOG_ERROR("NetscapePluginInstanceProxy::removeProperty: local object %u doesn't exist.", objectID);
1130         return false;
1131     }
1132     
1133     Frame* frame = core([m_pluginView webFrame]);
1134     if (!frame)
1135         return false;
1136     
1137     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1138     JSLockHolder lock(exec);
1139     if (!object->hasProperty(exec, propertyName)) {
1140         exec->clearException();
1141         return false;
1142     }
1143     
1144     object->methodTable()->deletePropertyByIndex(object, exec, propertyName);
1145     exec->clearException();    
1146     return true;
1147 }
1148
1149 bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, const Identifier& propertyName)
1150 {
1151     if (m_inDestroy)
1152         return false;
1153
1154     JSObject* object = m_localObjects.get(objectID);
1155     if (!object) {
1156         LOG_ERROR("NetscapePluginInstanceProxy::hasProperty: local object %u doesn't exist.", objectID);
1157         return false;
1158     }
1159     
1160     Frame* frame = core([m_pluginView webFrame]);
1161     if (!frame)
1162         return false;
1163     
1164     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1165     bool result = object->hasProperty(exec, propertyName);
1166     exec->clearException();
1167     
1168     return result;
1169 }
1170
1171 bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, unsigned propertyName)
1172 {
1173     if (m_inDestroy)
1174         return false;
1175
1176     JSObject* object = m_localObjects.get(objectID);
1177     if (!object) {
1178         LOG_ERROR("NetscapePluginInstanceProxy::hasProperty: local object %u doesn't exist.", objectID);
1179         return false;
1180     }
1181     
1182     Frame* frame = core([m_pluginView webFrame]);
1183     if (!frame)
1184         return false;
1185     
1186     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1187     bool result = object->hasProperty(exec, propertyName);
1188     exec->clearException();
1189     
1190     return result;
1191 }
1192     
1193 bool NetscapePluginInstanceProxy::hasMethod(uint32_t objectID, const Identifier& methodName)
1194 {
1195     if (m_inDestroy)
1196         return false;
1197
1198     JSObject* object = m_localObjects.get(objectID);
1199     if (!object) {
1200         LOG_ERROR("NetscapePluginInstanceProxy::hasMethod: local object %u doesn't exist.", objectID);
1201         return false;
1202     }
1203
1204     Frame* frame = core([m_pluginView webFrame]);
1205     if (!frame)
1206         return false;
1207     
1208     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1209     JSLockHolder lock(exec);
1210     JSValue func = object->get(exec, methodName);
1211     exec->clearException();
1212     return !func.isUndefined();
1213 }
1214
1215 bool NetscapePluginInstanceProxy::enumerate(uint32_t objectID, data_t& resultData, mach_msg_type_number_t& resultLength)
1216 {
1217     if (m_inDestroy)
1218         return false;
1219
1220     JSObject* object = m_localObjects.get(objectID);
1221     if (!object) {
1222         LOG_ERROR("NetscapePluginInstanceProxy::enumerate: local object %u doesn't exist.", objectID);
1223         return false;
1224     }
1225     
1226     Frame* frame = core([m_pluginView webFrame]);
1227     if (!frame)
1228         return false;
1229     
1230     ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec();
1231     JSLockHolder lock(exec);
1232  
1233     PropertyNameArray propertyNames(exec);
1234     object->methodTable()->getPropertyNames(object, exec, propertyNames, ExcludeDontEnumProperties);
1235
1236     RetainPtr<NSMutableArray*> array = adoptNS([[NSMutableArray alloc] init]);
1237     for (unsigned i = 0; i < propertyNames.size(); i++) {
1238         uint64_t methodName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(propertyNames[i].string().utf8().data()));
1239
1240         [array.get() addObject:[NSNumber numberWithLongLong:methodName]];
1241     }
1242
1243     NSData *data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0];
1244     ASSERT(data);
1245
1246     resultLength = [data length];
1247     mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength);
1248
1249     memcpy(resultData, [data bytes], resultLength);
1250
1251     exec->clearException();
1252
1253     return true;
1254 }
1255
1256 static bool getObjectID(NetscapePluginInstanceProxy* pluginInstanceProxy, JSObject* object, uint64_t& objectID)
1257 {
1258     if (object->classInfo() != ProxyRuntimeObject::info())
1259         return false;
1260
1261     ProxyRuntimeObject* runtimeObject = static_cast<ProxyRuntimeObject*>(object);
1262     ProxyInstance* instance = runtimeObject->getInternalProxyInstance();
1263     if (!instance)
1264         return false;
1265
1266     if (instance->instanceProxy() != pluginInstanceProxy)
1267         return false;
1268
1269     objectID = instance->objectID();
1270     return true;
1271 }
1272     
1273 void NetscapePluginInstanceProxy::addValueToArray(NSMutableArray *array, ExecState* exec, JSValue value)
1274 {
1275     JSLockHolder lock(exec);
1276
1277     if (value.isString()) {
1278         [array addObject:[NSNumber numberWithInt:StringValueType]];
1279         [array addObject:value.toWTFString(exec)];
1280     } else if (value.isNumber()) {
1281         [array addObject:[NSNumber numberWithInt:DoubleValueType]];
1282         [array addObject:[NSNumber numberWithDouble:value.toNumber(exec)]];
1283     } else if (value.isBoolean()) {
1284         [array addObject:[NSNumber numberWithInt:BoolValueType]];
1285         [array addObject:[NSNumber numberWithBool:value.toBoolean(exec)]];
1286     } else if (value.isNull())
1287         [array addObject:[NSNumber numberWithInt:NullValueType]];
1288     else if (value.isObject()) {
1289         JSObject* object = asObject(value);
1290         uint64_t objectID;
1291         if (getObjectID(this, object, objectID)) {
1292             [array addObject:[NSNumber numberWithInt:NPObjectValueType]];
1293             [array addObject:[NSNumber numberWithInt:objectID]];
1294         } else {
1295             [array addObject:[NSNumber numberWithInt:JSObjectValueType]];
1296             [array addObject:[NSNumber numberWithInt:m_localObjects.idForObject(exec->vm(), object)]];
1297         }
1298     } else
1299         [array addObject:[NSNumber numberWithInt:VoidValueType]];
1300 }
1301
1302 void NetscapePluginInstanceProxy::marshalValue(ExecState* exec, JSValue value, data_t& resultData, mach_msg_type_number_t& resultLength)
1303 {
1304     RetainPtr<NSMutableArray*> array = adoptNS([[NSMutableArray alloc] init]);
1305     
1306     addValueToArray(array.get(), exec, value);
1307
1308     RetainPtr<NSData *> data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0];
1309     ASSERT(data);
1310     
1311     resultLength = [data.get() length];
1312     mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength);
1313     
1314     memcpy(resultData, [data.get() bytes], resultLength);
1315 }
1316
1317 RetainPtr<NSData *> NetscapePluginInstanceProxy::marshalValues(ExecState* exec, const ArgList& args)
1318 {
1319     RetainPtr<NSMutableArray*> array = adoptNS([[NSMutableArray alloc] init]);
1320
1321     for (unsigned i = 0; i < args.size(); i++)
1322         addValueToArray(array.get(), exec, args.at(i));
1323
1324     RetainPtr<NSData *> data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0];
1325     ASSERT(data);
1326
1327     return data;
1328 }    
1329
1330 bool NetscapePluginInstanceProxy::demarshalValueFromArray(ExecState* exec, NSArray *array, NSUInteger& index, JSValue& result)
1331 {
1332     if (index == [array count])
1333         return false;
1334                   
1335     int type = [[array objectAtIndex:index++] intValue];
1336     switch (type) {
1337         case VoidValueType:
1338             result = jsUndefined();
1339             return true;
1340         case NullValueType:
1341             result = jsNull();
1342             return true;
1343         case BoolValueType:
1344             result = jsBoolean([[array objectAtIndex:index++] boolValue]);
1345             return true;
1346         case DoubleValueType:
1347             result = jsNumber([[array objectAtIndex:index++] doubleValue]);
1348             return true;
1349         case StringValueType: {
1350             NSString *string = [array objectAtIndex:index++];
1351             
1352             result = jsString(exec, String(string));
1353             return true;
1354         }
1355         case JSObjectValueType: {
1356             uint32_t objectID = [[array objectAtIndex:index++] intValue];
1357             
1358             result = m_localObjects.get(objectID);
1359             ASSERT(result);
1360             return true;
1361         }
1362         case NPObjectValueType: {
1363             uint32_t objectID = [[array objectAtIndex:index++] intValue];
1364
1365             Frame* frame = core([m_pluginView webFrame]);
1366             if (!frame)
1367                 return false;
1368             
1369             if (!frame->script().canExecuteScripts(NotAboutToExecuteScript))
1370                 return false;
1371
1372             RefPtr<RootObject> rootObject = frame->script().createRootObject(m_pluginView);
1373             if (!rootObject)
1374                 return false;
1375             
1376             result = ProxyInstance::create(rootObject.release(), this, objectID)->createRuntimeObject(exec);
1377             return true;
1378         }
1379         default:
1380             ASSERT_NOT_REACHED();
1381             return false;
1382     }
1383 }
1384
1385 JSValue NetscapePluginInstanceProxy::demarshalValue(ExecState* exec, const char* valueData, mach_msg_type_number_t valueLength)
1386 {
1387     RetainPtr<NSData*> data = adoptNS([[NSData alloc] initWithBytesNoCopy:(void*)valueData length:valueLength freeWhenDone:NO]);
1388
1389     RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:data.get()
1390                                                                  mutabilityOption:NSPropertyListImmutable
1391                                                                            format:0
1392                                                                  errorDescription:0];
1393     NSUInteger position = 0;
1394     JSValue value;
1395     bool result = demarshalValueFromArray(exec, array.get(), position, value);
1396     ASSERT_UNUSED(result, result);
1397
1398     return value;
1399 }
1400
1401 void NetscapePluginInstanceProxy::demarshalValues(ExecState* exec, data_t valuesData, mach_msg_type_number_t valuesLength, MarkedArgumentBuffer& result)
1402 {
1403     RetainPtr<NSData*> data = adoptNS([[NSData alloc] initWithBytesNoCopy:valuesData length:valuesLength freeWhenDone:NO]);
1404
1405     RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:data.get()
1406                                                                  mutabilityOption:NSPropertyListImmutable
1407                                                                            format:0
1408                                                                  errorDescription:0];
1409     NSUInteger position = 0;
1410     JSValue value;
1411     while (demarshalValueFromArray(exec, array.get(), position, value))
1412         result.append(value);
1413 }
1414
1415 void NetscapePluginInstanceProxy::retainLocalObject(JSC::JSValue value)
1416 {
1417     if (!value.isObject() || value.inherits(ProxyRuntimeObject::info()))
1418         return;
1419
1420     m_localObjects.retain(asObject(value));
1421 }
1422
1423 void NetscapePluginInstanceProxy::releaseLocalObject(JSC::JSValue value)
1424 {
1425     if (!value.isObject() || value.inherits(ProxyRuntimeObject::info()))
1426         return;
1427
1428     m_localObjects.release(asObject(value));
1429 }
1430
1431 PassRefPtr<Instance> NetscapePluginInstanceProxy::createBindingsInstance(PassRefPtr<RootObject> rootObject)
1432 {
1433     uint32_t requestID = nextRequestID();
1434     
1435     if (_WKPHGetScriptableNPObject(m_pluginHostProxy->port(), m_pluginID, requestID) != KERN_SUCCESS)
1436         return 0;
1437
1438     std::auto_ptr<GetScriptableNPObjectReply> reply = waitForReply<GetScriptableNPObjectReply>(requestID);
1439     if (!reply.get())
1440         return 0;
1441
1442     if (!reply->m_objectID)
1443         return 0;
1444
1445     // Since the reply was non-null, "this" is still a valid pointer.
1446     return ProxyInstance::create(rootObject, this, reply->m_objectID);
1447 }
1448
1449 void NetscapePluginInstanceProxy::addInstance(ProxyInstance* instance)
1450 {
1451     ASSERT(!m_instances.contains(instance));
1452     
1453     m_instances.add(instance);
1454 }
1455     
1456 void NetscapePluginInstanceProxy::removeInstance(ProxyInstance* instance)
1457 {
1458     ASSERT(m_instances.contains(instance));
1459     
1460     m_instances.remove(instance);
1461 }
1462  
1463 void NetscapePluginInstanceProxy::willCallPluginFunction()
1464 {
1465     m_pluginFunctionCallDepth++;
1466 }
1467     
1468 void NetscapePluginInstanceProxy::didCallPluginFunction(bool& stopped)
1469 {
1470     ASSERT(m_pluginFunctionCallDepth > 0);
1471     m_pluginFunctionCallDepth--;
1472     
1473     // If -stop was called while we were calling into a plug-in function, and we're no longer
1474     // inside a plug-in function, stop now.
1475     if (!m_pluginFunctionCallDepth && m_shouldStopSoon) {
1476         m_shouldStopSoon = false;
1477         [m_pluginView stop];
1478         stopped = true;
1479     }
1480 }
1481     
1482 bool NetscapePluginInstanceProxy::shouldStop()
1483 {
1484     if (m_pluginFunctionCallDepth) {
1485         m_shouldStopSoon = true;
1486         return false;
1487     }
1488     
1489     return true;
1490 }
1491
1492 uint32_t NetscapePluginInstanceProxy::nextRequestID()
1493 {
1494     uint32_t requestID = ++m_currentRequestID;
1495     
1496     // We don't want to return the HashMap empty/deleted "special keys"
1497     if (requestID == 0 || requestID == static_cast<uint32_t>(-1))
1498         return nextRequestID();
1499     
1500     return requestID;
1501 }
1502
1503 void NetscapePluginInstanceProxy::invalidateRect(double x, double y, double width, double height)
1504 {
1505     ASSERT(m_pluginView);
1506     
1507     m_pluginIsWaitingForDraw = true;
1508     [m_pluginView invalidatePluginContentRect:NSMakeRect(x, y, width, height)];
1509 }
1510
1511 void NetscapePluginInstanceProxy::didDraw()
1512 {
1513     if (!m_pluginIsWaitingForDraw)
1514         return;
1515     
1516     m_pluginIsWaitingForDraw = false;
1517     _WKPHPluginInstanceDidDraw(m_pluginHostProxy->port(), m_pluginID);
1518 }
1519     
1520 bool NetscapePluginInstanceProxy::getCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t& cookiesData, mach_msg_type_number_t& cookiesLength)
1521 {
1522     ASSERT(m_pluginView);
1523     
1524     NSURL *url = [m_pluginView URLWithCString:urlData];
1525     if (!url)
1526         return false;
1527     
1528     if (Frame* frame = core([m_pluginView webFrame])) {
1529         String cookieString = cookies(frame->document(), url); 
1530         WTF::CString cookieStringUTF8 = cookieString.utf8();
1531         if (cookieStringUTF8.isNull())
1532             return false;
1533         
1534         cookiesLength = cookieStringUTF8.length();
1535         mig_allocate(reinterpret_cast<vm_address_t*>(&cookiesData), cookiesLength);
1536         memcpy(cookiesData, cookieStringUTF8.data(), cookiesLength);
1537         
1538         return true;
1539     }
1540
1541     return false;
1542 }
1543     
1544 bool NetscapePluginInstanceProxy::setCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t cookiesData, mach_msg_type_number_t cookiesLength)
1545 {
1546     ASSERT(m_pluginView);
1547     
1548     NSURL *url = [m_pluginView URLWithCString:urlData];
1549     if (!url)
1550         return false;
1551
1552     if (Frame* frame = core([m_pluginView webFrame])) {
1553         String cookieString = String::fromUTF8(cookiesData, cookiesLength);
1554         if (!cookieString)
1555             return false;
1556         
1557         WebCore::setCookies(frame->document(), url, cookieString);
1558         return true;
1559     }
1560
1561     return false;
1562 }
1563
1564 bool NetscapePluginInstanceProxy::getProxy(data_t urlData, mach_msg_type_number_t urlLength, data_t& proxyData, mach_msg_type_number_t& proxyLength)
1565 {
1566     ASSERT(m_pluginView);
1567     
1568     NSURL *url = [m_pluginView URLWithCString:urlData];
1569     if (!url)
1570         return false;
1571
1572     Vector<ProxyServer> proxyServers = proxyServersForURL(url, 0);
1573     WTF::CString proxyStringUTF8 = toString(proxyServers).utf8();
1574
1575     proxyLength = proxyStringUTF8.length();
1576     mig_allocate(reinterpret_cast<vm_address_t*>(&proxyData), proxyLength);
1577     memcpy(proxyData, proxyStringUTF8.data(), proxyLength);
1578     
1579     return true;
1580 }
1581     
1582 bool NetscapePluginInstanceProxy::getAuthenticationInfo(data_t protocolData, data_t hostData, uint32_t port, data_t schemeData, data_t realmData, 
1583                                                         data_t& usernameData, mach_msg_type_number_t& usernameLength, data_t& passwordData, mach_msg_type_number_t& passwordLength)
1584 {
1585     WTF::CString username;
1586     WTF::CString password;
1587     
1588     if (!WebKit::getAuthenticationInfo(protocolData, hostData, port, schemeData, realmData, username, password))
1589         return false;
1590     
1591     usernameLength = username.length();
1592     mig_allocate(reinterpret_cast<vm_address_t*>(&usernameData), usernameLength);
1593     memcpy(usernameData, username.data(), usernameLength);
1594     
1595     passwordLength = password.length();
1596     mig_allocate(reinterpret_cast<vm_address_t*>(&passwordData), passwordLength);
1597     memcpy(passwordData, password.data(), passwordLength);
1598     
1599     return true;
1600 }
1601
1602 bool NetscapePluginInstanceProxy::convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, 
1603                                                double& destX, double& destY, NPCoordinateSpace destSpace)
1604 {
1605     ASSERT(m_pluginView);
1606
1607     return [m_pluginView convertFromX:sourceX andY:sourceY space:sourceSpace toX:&destX andY:&destY space:destSpace];
1608 }
1609
1610 uint32_t NetscapePluginInstanceProxy::checkIfAllowedToLoadURL(const char* url, const char* target)
1611 {
1612     uint32_t checkID;
1613     
1614     // Assign a check ID
1615     do {
1616         checkID = ++m_urlCheckCounter;
1617     } while (m_urlChecks.contains(checkID) || !m_urlCheckCounter);
1618
1619     NSString *frameName = target ? [NSString stringWithCString:target encoding:NSISOLatin1StringEncoding] : nil;
1620
1621     NSNumber *contextInfo = [[NSNumber alloc] initWithUnsignedInt:checkID];
1622     WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[m_pluginView requestWithURLCString:url]
1623                                                                         target:frameName
1624                                                                   resultObject:m_pluginView
1625                                                                       selector:@selector(_containerCheckResult:contextInfo:)
1626                                                                     controller:m_pluginView 
1627                                                                    contextInfo:contextInfo];
1628     
1629     [contextInfo release];
1630     m_urlChecks.set(checkID, check);
1631     [check start];
1632     
1633     return checkID;
1634 }
1635
1636 void NetscapePluginInstanceProxy::cancelCheckIfAllowedToLoadURL(uint32_t checkID)
1637 {
1638     URLCheckMap::iterator it = m_urlChecks.find(checkID);
1639     if (it == m_urlChecks.end())
1640         return;
1641     
1642     WebPluginContainerCheck *check = it->value.get();
1643     [check cancel];
1644     m_urlChecks.remove(it);
1645 }
1646
1647 void NetscapePluginInstanceProxy::checkIfAllowedToLoadURLResult(uint32_t checkID, bool allowed)
1648 {
1649     _WKPHCheckIfAllowedToLoadURLResult(m_pluginHostProxy->port(), m_pluginID, checkID, allowed);
1650 }
1651
1652 void NetscapePluginInstanceProxy::resolveURL(const char* url, const char* target, data_t& resolvedURLData, mach_msg_type_number_t& resolvedURLLength)
1653 {
1654     ASSERT(m_pluginView);
1655     
1656     WTF::CString resolvedURL = [m_pluginView resolvedURLStringForURL:url target:target];
1657     
1658     resolvedURLLength = resolvedURL.length();
1659     mig_allocate(reinterpret_cast<vm_address_t*>(&resolvedURLData), resolvedURLLength);
1660     memcpy(resolvedURLData, resolvedURL.data(), resolvedURLLength);
1661 }
1662
1663 void NetscapePluginInstanceProxy::privateBrowsingModeDidChange(bool isPrivateBrowsingEnabled)
1664 {
1665     _WKPHPluginInstancePrivateBrowsingModeDidChange(m_pluginHostProxy->port(), m_pluginID, isPrivateBrowsingEnabled);
1666 }
1667
1668 static String& globalExceptionString()
1669 {
1670     DEFINE_STATIC_LOCAL(String, exceptionString, ());
1671     return exceptionString;
1672 }
1673
1674 void NetscapePluginInstanceProxy::setGlobalException(const String& exception)
1675 {
1676     globalExceptionString() = exception;
1677 }
1678
1679 void NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(ExecState* exec)
1680 {
1681     if (globalExceptionString().isNull())
1682         return;
1683
1684     {
1685         JSLockHolder lock(exec);
1686         throwError(exec, createError(exec, globalExceptionString()));
1687     }
1688
1689     globalExceptionString() = String();
1690 }
1691
1692 } // namespace WebKit
1693
1694 #endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)