OSDN Git Service

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