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