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