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