WebKit:
[WebKit-https.git] / WebKit / mac / Plugins / Hosted / NetscapePluginInstanceProxy.mm
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #if USE(PLUGIN_HOST_PROCESS)
27
28 #import "NetscapePluginInstanceProxy.h"
29
30 #import "HostedNetscapePluginStream.h"
31 #import "NetscapePluginHostProxy.h"
32 #import "ProxyInstance.h"
33 #import "WebDataSourceInternal.h"
34 #import "WebFrameInternal.h"
35 #import "WebHostedNetscapePluginView.h"
36 #import "WebNSDataExtras.h"
37 #import "WebNSURLExtras.h"
38 #import "WebKitNSStringExtras.h"
39 #import "WebPluginRequest.h"
40 #import "WebViewInternal.h"
41 #import "WebUIDelegate.h"
42 #import "WebUIDelegatePrivate.h"
43
44 #import <mach/mach.h>
45 #import <WebCore/DocumentLoader.h>
46 #import <WebCore/Frame.h>
47 #import <WebCore/FrameLoader.h>
48 #import <WebCore/FrameTree.h>
49 #import <WebCore/ScriptController.h>
50 #import <WebCore/ScriptValue.h>
51 #include <runtime/JSLock.h>
52 #import <utility>
53
54 extern "C" {
55 #import "WebKitPluginClientServer.h"
56 #import "WebKitPluginHost.h"
57 }
58
59 using namespace JSC;
60 using namespace JSC::Bindings;
61 using namespace std;
62 using namespace WebCore;
63
64 namespace WebKit {
65
66 class NetscapePluginInstanceProxy::PluginRequest {
67 public:
68     PluginRequest(uint32_t requestID, NSURLRequest *request, NSString *frameName, bool didStartFromUserGesture)
69         : m_requestID(requestID)
70         , m_request(request)
71         , m_frameName(frameName)
72         , m_didStartFromUserGesture(didStartFromUserGesture)
73     {
74     }
75     
76     uint32_t requestID() const { return m_requestID; }
77     NSURLRequest *request() const { return m_request.get(); }
78     NSString *frameName() const { return m_frameName.get(); }
79     bool didStartFromUserGesture() const { return m_didStartFromUserGesture; }
80     
81 private:
82     uint32_t m_requestID;
83     RetainPtr<NSURLRequest *> m_request;
84     RetainPtr<NSString *> m_frameName;
85     bool m_didStartFromUserGesture;
86 };
87
88 static uint32_t pluginIDCounter;
89
90 NetscapePluginInstanceProxy::NetscapePluginInstanceProxy(NetscapePluginHostProxy* pluginHostProxy, WebHostedNetscapePluginView *pluginView)
91     : m_pluginHostProxy(pluginHostProxy)
92     , m_pluginView(pluginView)
93     , m_requestTimer(this, &NetscapePluginInstanceProxy::requestTimerFired)
94     , m_currentRequestID(0)
95     , m_renderContextID(0)
96     , m_useSoftwareRenderer(false)
97     , m_waitingForReply(false)
98     , m_objectIDCounter(0)
99 {
100     ASSERT(m_pluginView);
101     
102     // Assign a plug-in ID.
103     do {
104         m_pluginID = ++pluginIDCounter;
105     } while (pluginHostProxy->pluginInstance(m_pluginID) || !m_pluginID);
106     
107     pluginHostProxy->addPluginInstance(this);
108 }
109
110 NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy()
111 {
112     ASSERT(!m_pluginHostProxy);
113 }
114
115 void NetscapePluginInstanceProxy::resize(NSRect size, NSRect clipRect)
116 {
117     _WKPHResizePluginInstance(m_pluginHostProxy->port(), m_pluginID, size.origin.x, size.origin.y, size.size.width, size.size.height);
118 }
119
120 void NetscapePluginInstanceProxy::stopAllStreams()
121 {
122     Vector<RefPtr<HostedNetscapePluginStream> > streamsCopy;
123     copyValuesToVector(m_streams, streamsCopy);
124     for (size_t i = 0; i < streamsCopy.size(); i++)
125         streamsCopy[i]->stop();
126 }
127
128 void NetscapePluginInstanceProxy::destroy()
129 {
130     stopAllStreams();
131     
132     _WKPHDestroyPluginInstance(m_pluginHostProxy->port(), m_pluginID);
133     
134     // Clear the object map, this will cause any outstanding JS objects that the plug-in had a reference to 
135     // to go away when the next garbage collection takes place.
136     m_objects.clear();
137     
138     m_pluginHostProxy->removePluginInstance(this);
139     m_pluginHostProxy = 0;
140 }
141
142 HostedNetscapePluginStream *NetscapePluginInstanceProxy::pluginStream(uint32_t streamID)
143 {
144     return m_streams.get(streamID).get();
145 }
146
147 void NetscapePluginInstanceProxy::disconnectStream(HostedNetscapePluginStream* stream)
148 {
149     m_streams.remove(stream->streamID());
150 }
151     
152 void NetscapePluginInstanceProxy::pluginHostDied()
153 {
154     stopAllStreams();
155
156     m_pluginHostProxy = 0;
157     
158     [m_pluginView pluginHostDied];
159     m_pluginView = nil;
160 }
161
162 void NetscapePluginInstanceProxy::focusChanged(bool hasFocus)
163 {
164     _WKPHPluginInstanceFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus);
165 }
166
167 void NetscapePluginInstanceProxy::windowFocusChanged(bool hasFocus)
168 {
169     _WKPHPluginInstanceWindowFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus);
170 }
171
172 void NetscapePluginInstanceProxy::windowFrameChanged(NSRect frame)
173 {
174     _WKPHPluginInstanceWindowFrameChanged(m_pluginHostProxy->port(), m_pluginID, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height,
175                                           // FIXME: Is it always correct to pass the rect of the first screen here?
176                                           NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]));
177 }
178     
179 void NetscapePluginInstanceProxy::startTimers(bool throttleTimers)
180 {
181     _WKPHPluginInstanceStartTimers(m_pluginHostProxy->port(), m_pluginID, throttleTimers);
182 }
183     
184 void NetscapePluginInstanceProxy::mouseEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type)
185 {
186     NSPoint screenPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
187     NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil];
188     
189     int clickCount;
190     if (type == NPCocoaEventMouseEntered || type == NPCocoaEventMouseExited)
191         clickCount = 0;
192     else
193         clickCount = [event clickCount];
194     
195
196     _WKPHPluginInstanceMouseEvent(m_pluginHostProxy->port(), m_pluginID,
197                                   [event timestamp],
198                                   type, [event modifierFlags],
199                                   pluginPoint.x, pluginPoint.y,
200                                   screenPoint.x, screenPoint.y,
201                                   // FIXME: Is it always correct to pass the rect of the first screen here?
202                                   NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]),
203                                   [event buttonNumber], clickCount, 
204                                   [event deltaX], [event deltaY], [event deltaZ]);
205 }
206     
207 void NetscapePluginInstanceProxy::keyEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type)
208 {
209     NSData *charactersData = [[event characters] dataUsingEncoding:NSUTF8StringEncoding];
210     NSData *charactersIgnoringModifiersData = [[event charactersIgnoringModifiers] dataUsingEncoding:NSUTF8StringEncoding];
211     
212     _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID,
213                                      [event timestamp], 
214                                      type, [event modifierFlags], 
215                                      const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], 
216                                      const_cast<char*>(reinterpret_cast<const char*>([charactersIgnoringModifiersData bytes])), [charactersIgnoringModifiersData length], 
217                                      [event isARepeat], [event keyCode]);
218 }
219
220 void NetscapePluginInstanceProxy::stopTimers()
221 {
222     _WKPHPluginInstanceStopTimers(m_pluginHostProxy->port(), m_pluginID);
223 }
224
225 void NetscapePluginInstanceProxy::status(const char* message)
226 {
227     RetainPtr<CFStringRef> status(AdoptCF, CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8));
228     
229     if (!status)
230         return;
231     
232     WebView *wv = [m_pluginView webView];
233     [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status.get()];
234 }
235
236 NPError NetscapePluginInstanceProxy::loadURL(const char* url, const char* target, const char* postData, uint32_t postLen, LoadURLFlags flags, uint32_t& streamID)
237 {
238     if (!url)
239         return NPERR_INVALID_PARAM;
240  
241     NSMutableURLRequest *request = [m_pluginView requestWithURLCString:url];
242
243     if (flags & IsPost) {
244         NSData *httpBody = nil;
245
246         if (flags & PostDataIsFile) {
247             // If we're posting a file, buf is either a file URL or a path to the file.
248             RetainPtr<CFStringRef> bufString(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, postData, kCFStringEncodingWindowsLatin1));
249             if (!bufString)
250                 return NPERR_INVALID_PARAM;
251             
252             NSURL *fileURL = [NSURL _web_URLWithDataAsString:(NSString *)bufString.get()];
253             NSString *path;
254             if ([fileURL isFileURL])
255                 path = [fileURL path];
256             else
257                 path = (NSString *)bufString.get();
258             httpBody = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
259             if (!httpBody)
260                 return NPERR_FILE_NOT_FOUND;
261         } else
262             httpBody = [NSData dataWithBytes:postData length:postLen];
263
264         if (![httpBody length])
265             return NPERR_INVALID_PARAM;
266
267         [request setHTTPMethod:@"POST"];
268         
269         if (flags & AllowHeadersInPostData) {
270             if ([httpBody _web_startsWithBlankLine])
271                 httpBody = [httpBody subdataWithRange:NSMakeRange(1, [httpBody length] - 1)];
272             else {
273                 NSInteger location = [httpBody _web_locationAfterFirstBlankLine];
274                 if (location != NSNotFound) {
275                     // If the blank line is somewhere in the middle of postData, everything before is the header.
276                     NSData *headerData = [httpBody subdataWithRange:NSMakeRange(0, location)];
277                     NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
278                     unsigned dataLength = [httpBody length] - location;
279
280                     // Sometimes plugins like to set Content-Length themselves when they post,
281                     // but CFNetwork does not like that. So we will remove the header
282                     // and instead truncate the data to the requested length.
283                     NSString *contentLength = [header objectForKey:@"Content-Length"];
284
285                     if (contentLength)
286                         dataLength = min(static_cast<unsigned>([contentLength intValue]), dataLength);
287                     [header removeObjectForKey:@"Content-Length"];
288
289                     if ([header count] > 0)
290                         [request setAllHTTPHeaderFields:header];
291
292                     // Everything after the blank line is the actual content of the POST.
293                     httpBody = [httpBody subdataWithRange:NSMakeRange(location, dataLength)];
294                 }
295             }
296         }
297
298         if (![httpBody length])
299             return NPERR_INVALID_PARAM;
300
301         // Plug-ins expect to receive uncached data when doing a POST (3347134).
302         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
303         [request setHTTPBody:httpBody];
304     }
305     
306     return loadRequest(request, target, flags & CurrentEventIsUserGesture, streamID);
307 }
308
309 void NetscapePluginInstanceProxy::performRequest(PluginRequest* pluginRequest)
310 {
311     NSURLRequest *request = pluginRequest->request();
312     NSString *frameName = pluginRequest->frameName();
313     WebFrame *frame = nil;
314     
315     NSURL *URL = [request URL];
316     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
317     
318     ASSERT(frameName || JSString);
319     if (frameName) {
320         // FIXME - need to get rid of this window creation which
321         // bypasses normal targeted link handling
322         frame = kit(core([m_pluginView webFrame])->loader()->findFrameForNavigation(frameName));
323         if (!frame) {
324             WebView *currentWebView = [m_pluginView webView];
325             NSDictionary *features = [[NSDictionary alloc] init];
326             WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
327                                                         createWebViewWithRequest:nil
328                                                                   windowFeatures:features];
329             [features release];
330
331             if (!newWebView)
332                 return;
333             
334             frame = [newWebView mainFrame];
335             core(frame)->tree()->setName(frameName);
336             [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
337         }
338     }
339
340     if (JSString) {
341         ASSERT(!frame || [m_pluginView webFrame] == frame);
342         evaluateJavaScript(pluginRequest);
343     } else
344         [frame loadRequest:request];
345 }
346
347 void NetscapePluginInstanceProxy::evaluateJavaScript(PluginRequest* pluginRequest)
348 {
349     NSURL *URL = [pluginRequest->request() URL];
350     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
351     ASSERT(JSString);
352     
353     NSString *result = [[m_pluginView webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:pluginRequest->didStartFromUserGesture()];
354     
355     // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
356     if (!m_pluginHostProxy)
357         return;
358
359     if (pluginRequest->frameName() != nil)
360         return;
361         
362     if ([result length] > 0) {
363         // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
364         NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
365         
366         RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, pluginRequest->requestID(), pluginRequest->request());
367         
368         RetainPtr<NSURLResponse> response(AdoptNS, [[NSURLResponse alloc] initWithURL:URL 
369                                                                              MIMEType:@"text/plain" 
370                                                                 expectedContentLength:[JSData length]
371                                                                      textEncodingName:nil]);
372         stream->startStreamWithResponse(response.get());
373         stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]);
374         stream->didFinishLoading(0);
375     }
376 }
377
378 void NetscapePluginInstanceProxy::requestTimerFired(Timer<NetscapePluginInstanceProxy>*)
379 {
380     ASSERT(!m_pluginRequests.isEmpty());
381     
382     PluginRequest* request = m_pluginRequests.first();
383     m_pluginRequests.removeFirst();
384     
385     if (!m_pluginRequests.isEmpty())
386         m_requestTimer.startOneShot(0);
387     
388     performRequest(request);
389     delete request;
390 }
391     
392 NPError NetscapePluginInstanceProxy::loadRequest(NSURLRequest *request, const char* cTarget, bool currentEventIsUserGesture, uint32_t& requestID)
393 {
394     NSURL *URL = [request URL];
395
396     if (!URL) 
397         return NPERR_INVALID_URL;
398
399     // Don't allow requests to be loaded when the document loader is stopping all loaders.
400     if ([[m_pluginView dataSource] _documentLoader]->isStopping())
401         return NPERR_GENERIC_ERROR;
402     
403     NSString *target = nil;
404     if (cTarget) {
405         // Find the frame given the target string.
406         target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding];
407     }
408     WebFrame *frame = [m_pluginView webFrame];
409
410     // don't let a plugin start any loads if it is no longer part of a document that is being 
411     // displayed unless the loads are in the same frame as the plugin.
412     if ([[m_pluginView dataSource] _documentLoader] != core([m_pluginView webFrame])->loader()->activeDocumentLoader() &&
413         (!cTarget || [frame findFrameNamed:target] != frame)) {
414         return NPERR_GENERIC_ERROR; 
415     }
416     
417     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
418     if (JSString != nil) {
419         if (![[[m_pluginView webView] preferences] isJavaScriptEnabled]) {
420             // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
421             return NPERR_GENERIC_ERROR;
422         }
423     } else {
424         if (!FrameLoader::canLoad(URL, String(), core([m_pluginView webFrame])->document()))
425             return NPERR_GENERIC_ERROR;
426     }
427     
428     // FIXME: Handle wraparound
429     requestID = ++m_currentRequestID;
430         
431     if (cTarget || JSString) {
432         // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
433         // want to potentially kill the plug-in inside of its URL request.
434         
435         if (JSString && target && [frame findFrameNamed:target] != frame) {
436             // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
437             return NPERR_INVALID_PARAM;
438         }
439
440         PluginRequest* pluginRequest = new PluginRequest(requestID, request, target, currentEventIsUserGesture);
441         m_pluginRequests.append(pluginRequest);
442         m_requestTimer.startOneShot(0);
443     } else {
444         RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, requestID, request);
445
446         m_streams.add(requestID, stream);
447         stream->start();
448     }
449     
450     return NPERR_NO_ERROR;
451 }
452
453 void NetscapePluginInstanceProxy::processRequestsAndWaitForReply()
454 {
455     while (!m_currentReply.get()) {
456         kern_return_t kr = mach_msg_server_once(WebKitPluginClient_server, WKPCWebKitPluginClient_subsystem.maxsize + MAX_TRAILER_SIZE, m_pluginHostProxy->clientPort(), 0);
457         if (kr != KERN_SUCCESS) {
458             m_currentReply.reset();
459             break;
460         }
461     }
462 }
463     
464 uint32_t NetscapePluginInstanceProxy::idForObject(JSC::JSObject* object)
465 {
466     uint32_t objectID = 0;
467     
468     // Assign an object ID.
469     do {
470         objectID = ++m_objectIDCounter;
471     } while (!m_objectIDCounter || m_objectIDCounter == static_cast<uint32_t>(-1) || m_objects.contains(objectID));
472     
473     m_objects.set(objectID, object);
474     
475     return objectID;
476 }
477
478 // NPRuntime support
479 bool NetscapePluginInstanceProxy::getWindowNPObject(uint32_t& objectID)
480 {
481     Frame* frame = core([m_pluginView webFrame]);
482     if (!frame)
483         return false;
484     
485     if (!frame->script()->isEnabled())
486         objectID = 0;
487     else
488         objectID = idForObject(frame->script()->windowShell()->window());
489         
490     return true;
491 }
492     
493 void NetscapePluginInstanceProxy::releaseObject(uint32_t objectID)
494 {
495     m_objects.remove(objectID);
496 }
497  
498 bool NetscapePluginInstanceProxy::evaluate(uint32_t objectID, const String& script, data_t& resultData, mach_msg_type_number_t& resultLength)
499 {
500     resultData = 0;
501     resultLength = 0;
502
503     if (!m_objects.contains(objectID))
504         return false;
505
506     Frame* frame = core([m_pluginView webFrame]);
507     if (!frame)
508         return false;
509     
510     ExecState* exec = frame->script()->globalObject()->globalExec();
511     JSValuePtr value = frame->loader()->executeScript(script).jsValue();
512     
513     marshalValue(exec, value, resultData, resultLength);
514     exec->clearException();
515     return true;
516 }
517
518 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)
519 {
520     resultData = 0;
521     resultLength = 0;
522     
523     JSObject* object = m_objects.get(objectID);
524     if (!object)
525         return false;
526     
527     Frame* frame = core([m_pluginView webFrame]);
528     if (!frame)
529         return false;
530     
531     ExecState* exec = frame->script()->globalObject()->globalExec();
532     JSLock lock(false);
533     JSValuePtr function = object->get(exec, methodName);
534     CallData callData;
535     CallType callType = function.getCallData(callData);
536     if (callType == CallTypeNone)
537         return false;
538     
539     ArgList argList;
540     demarshalValues(exec, argumentsData, argumentsLength, argList);
541
542     ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject();
543     globalObject->startTimeoutCheck();
544     JSValuePtr value = call(exec, function, callType, callData, object, argList);
545     globalObject->stopTimeoutCheck();
546         
547     marshalValue(exec, value, resultData, resultLength);
548     exec->clearException();
549     return true;
550 }
551
552 bool NetscapePluginInstanceProxy::invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength)
553 {
554     JSObject* object = m_objects.get(objectID);
555     if (!object)
556         return false;
557     
558     Frame* frame = core([m_pluginView webFrame]);
559     if (!frame)
560         return false;
561     
562     ExecState* exec = frame->script()->globalObject()->globalExec();
563     JSLock lock(false);    
564     CallData callData;
565     CallType callType = object->getCallData(callData);
566     if (callType == CallTypeNone)
567         return false;
568     
569     ArgList argList;
570     demarshalValues(exec, argumentsData, argumentsLength, argList);
571
572     ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject();
573     globalObject->startTimeoutCheck();
574     JSValuePtr value = call(exec, object, callType, callData, object, argList);
575     globalObject->stopTimeoutCheck();
576     
577     marshalValue(exec, value, resultData, resultLength);
578     exec->clearException();
579     return true;
580 }
581
582 bool NetscapePluginInstanceProxy::construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength)
583 {
584     JSObject* object = m_objects.get(objectID);
585     if (!object)
586         return false;
587     
588     Frame* frame = core([m_pluginView webFrame]);
589     if (!frame)
590         return false;
591     
592     ExecState* exec = frame->script()->globalObject()->globalExec();
593     JSLock lock(false);
594
595     ConstructData constructData;
596     ConstructType constructType = object->getConstructData(constructData);
597     if (constructType == ConstructTypeNone)
598         return false;
599         
600     ArgList argList;
601     demarshalValues(exec, argumentsData, argumentsLength, argList);
602
603     ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject();
604     globalObject->startTimeoutCheck();
605     JSValuePtr value = JSC::construct(exec, object, constructType, constructData, argList);
606     globalObject->stopTimeoutCheck();
607     
608     marshalValue(exec, value, resultData, resultLength);
609     exec->clearException();
610     return true;
611 }
612
613 bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t &resultData, mach_msg_type_number_t& resultLength)
614 {
615     JSObject* object = m_objects.get(objectID);
616     if (!object)
617         return false;
618     
619     Frame* frame = core([m_pluginView webFrame]);
620     if (!frame)
621         return false;
622     
623     ExecState* exec = frame->script()->globalObject()->globalExec();
624     JSLock lock(false);    
625     JSValuePtr value = object->get(exec, propertyName);
626     
627     marshalValue(exec, value, resultData, resultLength);
628     exec->clearException();
629     return true;
630 }
631     
632 bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, unsigned propertyName, data_t &resultData, mach_msg_type_number_t& resultLength)
633 {
634     JSObject* object = m_objects.get(objectID);
635     if (!object)
636         return false;
637     
638     Frame* frame = core([m_pluginView webFrame]);
639     if (!frame)
640         return false;
641     
642     ExecState* exec = frame->script()->globalObject()->globalExec();
643     JSLock lock(false);    
644     JSValuePtr value = object->get(exec, propertyName);
645     
646     marshalValue(exec, value, resultData, resultLength);
647     exec->clearException();
648     return true;
649 }
650
651 bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength)
652 {
653     JSObject* object = m_objects.get(objectID);
654     if (!object)
655         return false;
656     
657     Frame* frame = core([m_pluginView webFrame]);
658     if (!frame)
659         return false;
660     
661     ExecState* exec = frame->script()->globalObject()->globalExec();
662     JSLock lock(false);    
663
664     JSValuePtr value = demarshalValue(exec, valueData, valueLength);
665     PutPropertySlot slot;
666     object->put(exec, propertyName, value, slot);
667     
668     exec->clearException();
669     return true;
670 }
671
672 bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength)
673 {
674     JSObject* object = m_objects.get(objectID);
675     if (!object)
676         return false;
677     
678     Frame* frame = core([m_pluginView webFrame]);
679     if (!frame)
680         return false;
681     
682     ExecState* exec = frame->script()->globalObject()->globalExec();
683     JSLock lock(false);    
684     
685     JSValuePtr value = demarshalValue(exec, valueData, valueLength);
686     object->put(exec, propertyName, value);
687     
688     exec->clearException();
689     return true;
690 }
691
692 bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, const JSC::Identifier& propertyName)
693 {
694     JSObject* object = m_objects.get(objectID);
695     if (!object)
696         return false;
697     
698     Frame* frame = core([m_pluginView webFrame]);
699     if (!frame)
700         return false;
701
702     ExecState* exec = frame->script()->globalObject()->globalExec();
703     if (!object->hasProperty(exec, propertyName)) {
704         exec->clearException();
705         return false;
706     }
707     
708     JSLock lock(false);
709     object->deleteProperty(exec, propertyName);
710     exec->clearException();    
711     return true;
712 }
713     
714 bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, unsigned propertyName)
715 {
716     JSObject* object = m_objects.get(objectID);
717     if (!object)
718         return false;
719     
720     Frame* frame = core([m_pluginView webFrame]);
721     if (!frame)
722         return false;
723     
724     ExecState* exec = frame->script()->globalObject()->globalExec();
725     if (!object->hasProperty(exec, propertyName)) {
726         exec->clearException();
727         return false;
728     }
729     
730     JSLock lock(false);
731     object->deleteProperty(exec, propertyName);
732     exec->clearException();    
733     return true;
734 }
735
736 bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, const JSC::Identifier& propertyName)
737 {
738     JSObject* object = m_objects.get(objectID);
739     if (!object)
740         return false;
741     
742     Frame* frame = core([m_pluginView webFrame]);
743     if (!frame)
744         return false;
745     
746     ExecState* exec = frame->script()->globalObject()->globalExec();
747     bool result = object->hasProperty(exec, propertyName);
748     exec->clearException();
749     
750     return result;
751 }
752
753 bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, unsigned propertyName)
754 {
755     JSObject* object = m_objects.get(objectID);
756     if (!object)
757         return false;
758     
759     Frame* frame = core([m_pluginView webFrame]);
760     if (!frame)
761         return false;
762     
763     ExecState* exec = frame->script()->globalObject()->globalExec();
764     bool result = object->hasProperty(exec, propertyName);
765     exec->clearException();
766     
767     return result;
768 }
769     
770 bool NetscapePluginInstanceProxy::hasMethod(uint32_t objectID, const JSC::Identifier& methodName)
771 {
772     JSObject* object = m_objects.get(objectID);
773     if (!object)
774         return false;
775
776     Frame* frame = core([m_pluginView webFrame]);
777     if (!frame)
778         return false;
779     
780     ExecState* exec = frame->script()->globalObject()->globalExec();
781     JSLock lock(false);
782     JSValuePtr func = object->get(exec, methodName);
783     exec->clearException();
784     return !func.isUndefined();
785 }
786
787 void NetscapePluginInstanceProxy::marshalValue(ExecState* exec, JSValuePtr value, data_t& resultData, mach_msg_type_number_t& resultLength)
788 {
789     RetainPtr<NSMutableArray*> array(AdoptNS, [[NSMutableArray alloc] init]);
790     
791     JSLock lock(false);
792
793     if (value.isString()) {
794         [array.get() addObject:[NSNumber numberWithInt:StringValueType]];
795         [array.get() addObject:String(value.toString(exec))];
796     } else if (value.isNumber()) {
797         [array.get() addObject:[NSNumber numberWithInt:DoubleValueType]];
798         [array.get() addObject:[NSNumber numberWithDouble:value.toNumber(exec)]];
799     } else if (value.isBoolean()) {
800         [array.get() addObject:[NSNumber numberWithInt:BoolValueType]];
801         [array.get() addObject:[NSNumber numberWithDouble:value.toBoolean(exec)]];
802     } else if (value.isNull())
803         [array.get() addObject:[NSNumber numberWithInt:NullValueType]];
804     else if (value.isObject()) {
805         [array.get() addObject:[NSNumber numberWithInt:ObjectValueType]];
806         [array.get() addObject:[NSNumber numberWithInt:idForObject(asObject(value))]];
807     } else
808         [array.get() addObject:[NSNumber numberWithInt:VoidValueType]];
809
810     RetainPtr<NSData*> data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0];
811     ASSERT(data);
812     
813     resultLength = [data.get() length];
814     mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength);
815     
816     memcpy(resultData, [data.get() bytes], resultLength);
817 }
818
819 bool NetscapePluginInstanceProxy::demarshalValueFromArray(ExecState* exec, NSArray *array, NSUInteger& index, JSValuePtr& result)
820 {
821     if (index == [array count])
822         return false;
823                   
824     int type = [[array objectAtIndex:index++] intValue];
825     switch (type) {
826         case VoidValueType:
827             result = jsUndefined();
828             return true;
829         case NullValueType:
830             result = jsNull();
831             return true;
832         case BoolValueType:
833             result = jsBoolean([[array objectAtIndex:index++] boolValue]);
834             return true;
835         case DoubleValueType:
836             result = jsNumber(exec, [[array objectAtIndex:index++] doubleValue]);
837             return true;
838         case StringValueType: {
839             NSString *string = [array objectAtIndex:index++];
840             
841             result = jsString(exec, String(string));
842             return true;
843         }
844         case ObjectValueType: {
845             uint32_t objectID = [[array objectAtIndex:index++] intValue];
846             
847             result = m_objects.get(objectID);
848             return true;
849         }
850         default:
851             return false;
852     }
853 }
854
855 JSValuePtr NetscapePluginInstanceProxy::demarshalValue(ExecState* exec, data_t valueData, mach_msg_type_number_t valueLength)
856 {
857     RetainPtr<NSData*> data(AdoptNS, [[NSData alloc] initWithBytesNoCopy:valueData length:valueLength freeWhenDone:NO]);
858
859     RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:data.get()
860                                                                  mutabilityOption:NSPropertyListImmutable
861                                                                            format:0
862                                                                  errorDescription:0];
863     NSUInteger position = 0;
864     JSValuePtr value;
865     bool result = demarshalValueFromArray(exec, array.get(), position, value);
866     ASSERT_UNUSED(result, result);
867
868     return value;
869 }
870
871 void NetscapePluginInstanceProxy::demarshalValues(ExecState* exec, data_t valuesData, mach_msg_type_number_t valuesLength, ArgList& result)
872 {
873     RetainPtr<NSData*> data(AdoptNS, [[NSData alloc] initWithBytesNoCopy:valuesData length:valuesLength freeWhenDone:NO]);
874
875     RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:data.get()
876                                                                  mutabilityOption:NSPropertyListImmutable
877                                                                            format:0
878                                                                  errorDescription:0];
879     NSUInteger position = 0;
880     JSValuePtr value;
881     while (demarshalValueFromArray(exec, array.get(), position, value))
882         result.append(value);
883 }
884
885 PassRefPtr<Instance> NetscapePluginInstanceProxy::createBindingsInstance(PassRefPtr<RootObject>)
886 {
887     if (_WKPHGetScriptableNPObject(m_pluginHostProxy->port(), m_pluginID) != KERN_SUCCESS)
888         return 0;
889     
890     auto_ptr<GetScriptableNPObjectReply> reply = waitForReply<GetScriptableNPObjectReply>();
891     if (!reply.get())
892         return 0;
893     
894     // FIXME: Implement
895     return 0;
896 }
897
898 } // namespace WebKit
899
900 #endif // USE(PLUGIN_HOST_PROCESS)