From dcc8cf2e65d1aa555cce12431a16547e66b469ee Mon Sep 17 00:00:00 2001 From: Steve Block Date: Tue, 27 Apr 2010 16:31:00 +0100 Subject: Merge webkit.org at r58033 : Initial merge by git Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1 --- .../mac/Plugins/Hosted/NetscapePluginHostProxy.h | 18 +-- .../mac/Plugins/Hosted/NetscapePluginHostProxy.mm | 118 +++++++++++----- .../Plugins/Hosted/NetscapePluginInstanceProxy.h | 12 +- .../Plugins/Hosted/NetscapePluginInstanceProxy.mm | 156 +++++++++++++-------- WebKit/mac/Plugins/Hosted/ProxyInstance.h | 9 +- WebKit/mac/Plugins/Hosted/ProxyInstance.mm | 54 +++++-- WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.h | 53 +++++++ WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.mm | 55 ++++++++ .../Plugins/Hosted/WebHostedNetscapePluginView.h | 1 - .../Plugins/Hosted/WebHostedNetscapePluginView.mm | 45 +++--- WebKit/mac/Plugins/Hosted/WebKitPluginClient.defs | 2 +- WebKit/mac/Plugins/Hosted/WebKitPluginHost.defs | 6 + WebKit/mac/Plugins/WebBaseNetscapePluginView.h | 18 ++- WebKit/mac/Plugins/WebBaseNetscapePluginView.mm | 41 ++++-- .../Plugins/WebNetscapePluginEventHandlerCarbon.mm | 11 +- WebKit/mac/Plugins/WebNetscapePluginView.mm | 22 +-- WebKit/mac/Plugins/WebNullPluginView.h | 41 ------ WebKit/mac/Plugins/WebNullPluginView.mm | 100 ------------- WebKit/mac/Plugins/WebPluginController.mm | 107 ++++++++++++-- 19 files changed, 554 insertions(+), 315 deletions(-) create mode 100644 WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.h create mode 100644 WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.mm delete mode 100644 WebKit/mac/Plugins/WebNullPluginView.h delete mode 100644 WebKit/mac/Plugins/WebNullPluginView.mm (limited to 'WebKit/mac/Plugins') diff --git a/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.h b/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.h index cd3729f..d35503f 100644 --- a/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.h +++ b/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.h @@ -43,8 +43,8 @@ class NetscapePluginHostProxy { public: NetscapePluginHostProxy(mach_port_t clientPort, mach_port_t pluginHostPort, const ProcessSerialNumber& pluginHostPSN, bool shouldCacheMissingPropertiesAndMethods); - mach_port_t port() const { return m_pluginHostPort; } - mach_port_t clientPort() const { return m_clientPort; } + mach_port_t port() const { ASSERT(fastMallocSize(this)); return m_pluginHostPort; } + mach_port_t clientPort() const { ASSERT(fastMallocSize(this)); return m_clientPort; } void addPluginInstance(NetscapePluginInstanceProxy*); void removePluginInstance(NetscapePluginInstanceProxy*); @@ -54,15 +54,15 @@ public: bool isMenuBarVisible() const { return m_menuBarIsVisible; } void setMenuBarVisible(bool); - bool isFullScreenWindowShowing() const { return m_fullScreenWindowIsShowing; } - void setFullScreenWindowIsShowing(bool); + bool isFullscreenWindowShowing() const { return m_fullscreenWindowIsShowing; } + void setFullscreenWindowIsShowing(bool); void setModal(bool); void applicationDidBecomeActive(); bool processRequests(); - bool isProcessingRequests() const { return m_processingRequests; } + static bool isProcessingRequests() { return s_processingRequests; } bool shouldCacheMissingPropertiesAndMethods() const { return m_shouldCacheMissingPropertiesAndMethods; } @@ -73,8 +73,8 @@ private: void beginModal(); void endModal(); - void didEnterFullScreen() const; - void didExitFullScreen() const; + void didEnterFullscreen() const; + void didExitFullscreen() const; static void deadNameNotificationCallback(CFMachPortRef, void *msg, CFIndex size, void *info); @@ -96,10 +96,10 @@ private: RetainPtr m_placeholderWindow; unsigned m_isModal; bool m_menuBarIsVisible; - bool m_fullScreenWindowIsShowing; + bool m_fullscreenWindowIsShowing; const ProcessSerialNumber m_pluginHostPSN; - unsigned m_processingRequests; + static unsigned s_processingRequests; bool m_shouldCacheMissingPropertiesAndMethods; }; diff --git a/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm b/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm index 836277c..b437012 100644 --- a/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm +++ b/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm @@ -89,15 +89,16 @@ static PluginProxyMap& pluginProxyMap() return pluginProxyMap; } +unsigned NetscapePluginHostProxy::s_processingRequests; + NetscapePluginHostProxy::NetscapePluginHostProxy(mach_port_t clientPort, mach_port_t pluginHostPort, const ProcessSerialNumber& pluginHostPSN, bool shouldCacheMissingPropertiesAndMethods) : m_clientPort(clientPort) , m_portSet(MACH_PORT_NULL) , m_pluginHostPort(pluginHostPort) , m_isModal(false) , m_menuBarIsVisible(true) - , m_fullScreenWindowIsShowing(false) + , m_fullscreenWindowIsShowing(false) , m_pluginHostPSN(pluginHostPSN) - , m_processingRequests(0) , m_shouldCacheMissingPropertiesAndMethods(shouldCacheMissingPropertiesAndMethods) { pluginProxyMap().add(m_clientPort, this); @@ -184,7 +185,9 @@ void NetscapePluginHostProxy::removePluginInstance(NetscapePluginInstanceProxy* NetscapePluginInstanceProxy* NetscapePluginHostProxy::pluginInstance(uint32_t pluginID) { - return m_instances.get(pluginID).get(); + NetscapePluginInstanceProxy* result = m_instances.get(pluginID).get(); + ASSERT(!result || result->hostProxy() == this); + return result; } void NetscapePluginHostProxy::deadNameNotificationCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) @@ -202,12 +205,12 @@ void NetscapePluginHostProxy::setMenuBarVisible(bool visible) [NSMenu setMenuBarVisible:visible]; } -void NetscapePluginHostProxy::didEnterFullScreen() const +void NetscapePluginHostProxy::didEnterFullscreen() const { SetFrontProcess(&m_pluginHostPSN); } -void NetscapePluginHostProxy::didExitFullScreen() const +void NetscapePluginHostProxy::didExitFullscreen() const { // If the plug-in host is the current application then we should bring ourselves to the front when it exits full-screen mode. @@ -223,16 +226,16 @@ void NetscapePluginHostProxy::didExitFullScreen() const SetFrontProcess(¤tProcess); } -void NetscapePluginHostProxy::setFullScreenWindowIsShowing(bool isShowing) +void NetscapePluginHostProxy::setFullscreenWindowIsShowing(bool isShowing) { - if (m_fullScreenWindowIsShowing == isShowing) + if (m_fullscreenWindowIsShowing == isShowing) return; - m_fullScreenWindowIsShowing = isShowing; - if (m_fullScreenWindowIsShowing) - didEnterFullScreen(); + m_fullscreenWindowIsShowing = isShowing; + if (m_fullscreenWindowIsShowing) + didEnterFullscreen(); else - didExitFullScreen(); + didExitFullscreen(); } @@ -294,7 +297,7 @@ void NetscapePluginHostProxy::setModal(bool modal) bool NetscapePluginHostProxy::processRequests() { - m_processingRequests++; + s_processingRequests++; if (!m_portSet) { mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &m_portSet); @@ -310,7 +313,7 @@ bool NetscapePluginHostProxy::processRequests() if (kr != KERN_SUCCESS) { LOG_ERROR("Could not receive mach message, error %x", kr); - m_processingRequests--; + s_processingRequests--; return false; } @@ -323,24 +326,24 @@ bool NetscapePluginHostProxy::processRequests() if (kr != KERN_SUCCESS) { LOG_ERROR("Could not send mach message, error %x", kr); - m_processingRequests--; + s_processingRequests--; return false; } } - m_processingRequests--; + s_processingRequests--; return true; } if (msg->msgh_local_port == CFMachPortGetPort(m_deadNameNotificationPort.get())) { ASSERT(msg->msgh_id == MACH_NOTIFY_DEAD_NAME); pluginHostDied(); - m_processingRequests--; + s_processingRequests--; return false; } ASSERT_NOT_REACHED(); - m_processingRequests--; + s_processingRequests--; return false; } @@ -437,7 +440,7 @@ kern_return_t WKPCInvalidateRect(mach_port_t clientPort, uint32_t pluginID, doub if (NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID)) instanceProxy->invalidateRect(x, y, width, height); return KERN_SUCCESS; - } + } // Defer the work CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{ @@ -578,7 +581,11 @@ kern_return_t WKPCEvaluate(mach_port_t clientPort, uint32_t pluginID, uint32_t r data_t resultData = 0; mach_msg_type_number_t resultLength = 0; boolean_t returnValue = instanceProxy->evaluate(objectID, script, resultData, resultLength, allowPopups); - + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); if (resultData) mig_deallocate(reinterpret_cast(resultData), resultLength); @@ -610,7 +617,7 @@ static Identifier identifierFromIdentifierRep(IdentifierRep* identifier) ASSERT(identifier->isString()); const char* str = identifier->string(); - return Identifier(JSDOMWindow::commonJSGlobalData(), String::fromUTF8WithLatin1Fallback(str, strlen(str))); + return Identifier(JSDOMWindow::commonJSGlobalData(), stringToUString(String::fromUTF8WithLatin1Fallback(str, strlen(str)))); } kern_return_t WKPCInvoke(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier, @@ -637,7 +644,11 @@ kern_return_t WKPCInvoke(mach_port_t clientPort, uint32_t pluginID, uint32_t req data_t resultData = 0; mach_msg_type_number_t resultLength = 0; boolean_t returnValue = instanceProxy->invoke(objectID, methodNameIdentifier, argumentsData, argumentsLength, resultData, resultLength); - + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); if (resultData) mig_deallocate(reinterpret_cast(resultData), resultLength); @@ -663,7 +674,11 @@ kern_return_t WKPCInvokeDefault(mach_port_t clientPort, uint32_t pluginID, uint3 data_t resultData = 0; mach_msg_type_number_t resultLength = 0; boolean_t returnValue = instanceProxy->invokeDefault(objectID, argumentsData, argumentsLength, resultData, resultLength); - + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); if (resultData) mig_deallocate(reinterpret_cast(resultData), resultLength); @@ -701,7 +716,7 @@ kern_return_t WKPCGetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_ NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); if (!instanceProxy) return KERN_FAILURE; - + IdentifierRep* identifier = reinterpret_cast(serverIdentifier); if (!IdentifierRep::isValid(identifier)) return KERN_FAILURE; @@ -717,7 +732,11 @@ kern_return_t WKPCGetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_ returnValue = instanceProxy->getProperty(objectID, propertyNameIdentifier, resultData, resultLength); } else returnValue = instanceProxy->setProperty(objectID, identifier->number(), resultData, resultLength); - + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); if (resultData) mig_deallocate(reinterpret_cast(resultData), resultLength); @@ -750,6 +769,10 @@ kern_return_t WKPCSetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_ } else result = instanceProxy->setProperty(objectID, identifier->number(), valueData, valueLength); + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, result); return KERN_SUCCESS; @@ -778,6 +801,10 @@ kern_return_t WKPCRemoveProperty(mach_port_t clientPort, uint32_t pluginID, uint } else result = instanceProxy->removeProperty(objectID, identifier->number()); + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, result); return KERN_SUCCESS; @@ -805,7 +832,11 @@ kern_return_t WKPCHasProperty(mach_port_t clientPort, uint32_t pluginID, uint32_ returnValue = instanceProxy->hasProperty(objectID, propertyNameIdentifier); } else returnValue = instanceProxy->hasProperty(objectID, identifier->number()); - + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue); return KERN_SUCCESS; @@ -830,6 +861,10 @@ kern_return_t WKPCHasMethod(mach_port_t clientPort, uint32_t pluginID, uint32_t Identifier methodNameIdentifier = identifierFromIdentifierRep(identifier); boolean_t returnValue = instanceProxy->hasMethod(objectID, methodNameIdentifier); + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue); return KERN_SUCCESS; @@ -872,7 +907,11 @@ kern_return_t WKPCEnumerate(mach_port_t clientPort, uint32_t pluginID, uint32_t data_t resultData = 0; mach_msg_type_number_t resultLength = 0; boolean_t returnValue = instanceProxy->enumerate(objectID, resultData, resultLength); - + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); if (resultData) @@ -892,13 +931,13 @@ kern_return_t WKPCSetMenuBarVisible(mach_port_t clientPort, boolean_t menuBarVis return KERN_SUCCESS; } -kern_return_t WKPCSetFullScreenWindowIsShowing(mach_port_t clientPort, boolean_t fullScreenWindowIsShowing) +kern_return_t WKPCSetFullscreenWindowIsShowing(mach_port_t clientPort, boolean_t fullscreenWindowIsShowing) { NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); if (!hostProxy) return KERN_FAILURE; - hostProxy->setFullScreenWindowIsShowing(fullScreenWindowIsShowing); + hostProxy->setFullscreenWindowIsShowing(fullscreenWindowIsShowing); return KERN_SUCCESS; } @@ -908,9 +947,18 @@ kern_return_t WKPCSetModal(mach_port_t clientPort, boolean_t modal) NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); if (!hostProxy) return KERN_FAILURE; - - hostProxy->setModal(modal); - + + if (!hostProxy->isProcessingRequests()) { + hostProxy->setModal(modal); + return KERN_SUCCESS; + } + + // Defer the work + CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{ + if (NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort)) + hostProxy->setModal(modal); + }); + return KERN_SUCCESS; } @@ -1090,7 +1138,7 @@ kern_return_t WKPCRunSyncOpenPanel(mach_port_t clientPort, data_t panelData, mac NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); if (!hostProxy) return KERN_FAILURE; - + NSOpenPanel *sheet = [NSOpenPanel openPanel]; NSDictionary *panelState = [NSPropertyListSerialization propertyListFromData:[NSData dataWithBytes:panelData length:panelDataLength] mutabilityOption:NSPropertyListImmutable @@ -1114,7 +1162,11 @@ kern_return_t WKPCRunSyncOpenPanel(mach_port_t clientPort, data_t panelData, mac [sheet setRequiredFileType:[panelState objectForKey:@"requiredFileType"]]; [sheet setTitle:[panelState objectForKey:@"title"]]; [sheet runModal]; - + + NetscapePluginHostProxy* newHostProxy = pluginProxyMap().get(clientPort); + if (newHostProxy != hostProxy) + return KERN_FAILURE; + NSDictionary *ret = [NSDictionary dictionaryWithObjectsAndKeys: [sheet filenames], @"filenames", WKNoteOpenPanelFiles([sheet filenames]), @"extensions", diff --git a/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h b/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h index 29a5a2d..593d336 100644 --- a/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h +++ b/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h @@ -72,14 +72,14 @@ public: return m_pluginID; } - uint32_t renderContextID() const { return m_renderContextID; } + uint32_t renderContextID() const { ASSERT(fastMallocSize(this)); return m_renderContextID; } void setRenderContextID(uint32_t renderContextID) { m_renderContextID = renderContextID; } bool useSoftwareRenderer() const { return m_useSoftwareRenderer; } void setUseSoftwareRenderer(bool useSoftwareRenderer) { m_useSoftwareRenderer = useSoftwareRenderer; } - WebHostedNetscapePluginView *pluginView() const { return m_pluginView; } - NetscapePluginHostProxy* hostProxy() const { return m_pluginHostProxy; } + WebHostedNetscapePluginView *pluginView() const { ASSERT(fastMallocSize(this)); return m_pluginView; } + NetscapePluginHostProxy* hostProxy() const { ASSERT(fastMallocSize(this)); return m_pluginHostProxy; } bool cancelStreamLoad(uint32_t streamID, NPReason); void disconnectStream(HostedNetscapePluginStream*); @@ -89,7 +89,7 @@ public: void pluginHostDied(); - void resize(NSRect size, NSRect clipRect, bool sync); + void resize(NSRect size, NSRect clipRect); void destroy(); void focusChanged(bool hasFocus); void windowFocusChanged(bool hasFocus); @@ -102,6 +102,7 @@ public: void syntheticKeyDownWithCommandModifier(int keyCode, char character); void flagsChanged(NSEvent *); void print(CGContextRef, unsigned width, unsigned height); + void snapshot(CGContextRef, unsigned width, unsigned height); void startTimers(bool throttleTimers); void stopTimers(); @@ -256,8 +257,9 @@ public: template std::auto_ptr waitForReply(uint32_t requestID) { + RefPtr protect(this); // Plug-in host may crash while we are waiting for reply, releasing all instances to the instance proxy. + willCallPluginFunction(); - m_waitingForReply = true; Reply* reply = processRequestsAndWaitForReply(requestID); diff --git a/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm b/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm index 515f9f7..f027534 100644 --- a/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm +++ b/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm @@ -30,6 +30,7 @@ #import "HostedNetscapePluginStream.h" #import "NetscapePluginHostProxy.h" #import "ProxyInstance.h" +#import "ProxyRuntimeObject.h" #import "WebDataSourceInternal.h" #import "WebFrameInternal.h" #import "WebHostedNetscapePluginView.h" @@ -43,7 +44,6 @@ #import #import #import -#import #import #import #import @@ -60,6 +60,7 @@ #import #import #import +#import extern "C" { #import "WebKitPluginClientServer.h" @@ -116,6 +117,9 @@ inline bool NetscapePluginInstanceProxy::LocalObjectMap::contains(uint32_t objec inline JSC::JSObject* NetscapePluginInstanceProxy::LocalObjectMap::get(uint32_t objectID) const { + if (objectID == HashTraits::emptyValue() || HashTraits::isDeletedValue(objectID)) + return 0; + return m_idToJSObjectMap.get(objectID); } @@ -178,8 +182,16 @@ void NetscapePluginInstanceProxy::LocalObjectMap::clear() bool NetscapePluginInstanceProxy::LocalObjectMap::forget(uint32_t objectID) { + if (objectID == HashTraits::emptyValue() || HashTraits::isDeletedValue(objectID)) { + LOG_ERROR("NetscapePluginInstanceProxy::LocalObjectMap::forget: local object id %u is not valid.", objectID); + return true; + } + HashMap >::iterator iter = m_idToJSObjectMap.find(objectID); - ASSERT(iter != m_idToJSObjectMap.end()); + if (iter == m_idToJSObjectMap.end()) { + LOG_ERROR("NetscapePluginInstanceProxy::LocalObjectMap::forget: local object %u doesn't exist.", objectID); + return true; + } HashMap >::iterator rIter = m_jsObjectToIDMap.find(iter->second.get()); @@ -245,19 +257,17 @@ NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy() #endif } -void NetscapePluginInstanceProxy::resize(NSRect size, NSRect clipRect, bool sync) +void NetscapePluginInstanceProxy::resize(NSRect size, NSRect clipRect) { uint32_t requestID = 0; - if (sync) - requestID = nextRequestID(); + requestID = nextRequestID(); _WKPHResizePluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID, size.origin.x, size.origin.y, size.size.width, size.size.height, clipRect.origin.x, clipRect.origin.y, clipRect.size.width, clipRect.size.height); - if (sync) - waitForReply(requestID); + waitForReply(requestID); } void NetscapePluginInstanceProxy::stopAllStreams() @@ -464,9 +474,6 @@ bool NetscapePluginInstanceProxy::wheelEvent(NSView *pluginView, NSEvent *event) pluginPoint.x, pluginPoint.y, [event buttonNumber], [event deltaX], [event deltaY], [event deltaZ]); - // Protect ourselves in case waiting for the reply causes us to be deleted. - RefPtr protect(this); - auto_ptr reply = waitForReply(requestID); if (!reply.get() || !reply->m_result) return false; @@ -497,6 +504,22 @@ void NetscapePluginInstanceProxy::print(CGContextRef context, unsigned width, un CGContextRestoreGState(context); } +void NetscapePluginInstanceProxy::snapshot(CGContextRef context, unsigned width, unsigned height) +{ + uint32_t requestID = nextRequestID(); + _WKPHPluginInstanceSnapshot(m_pluginHostProxy->port(), m_pluginID, requestID, width, height); + + auto_ptr reply = waitForReply(requestID); + if (!reply.get() || !reply->m_returnValue) + return; + + RetainPtr dataProvider(AdoptCF, CGDataProviderCreateWithCFData(reply->m_result.get())); + RetainPtr colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr image(AdoptCF, CGImageCreate(width, height, 8, 32, width * 4, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, dataProvider.get(), 0, false, kCGRenderingIntentDefault)); + + CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.get()); +} + void NetscapePluginInstanceProxy::stopTimers() { _WKPHPluginInstanceStopTimers(m_pluginHostProxy->port(), m_pluginID); @@ -765,10 +788,16 @@ NPError NetscapePluginInstanceProxy::loadRequest(NSURLRequest *request, const ch NetscapePluginInstanceProxy::Reply* NetscapePluginInstanceProxy::processRequestsAndWaitForReply(uint32_t requestID) { Reply* reply = 0; - + + ASSERT(m_pluginHostProxy); while (!(reply = m_replies.take(requestID))) { if (!m_pluginHostProxy->processRequests()) return 0; + + // The host proxy can be destroyed while executing a nested processRequests() call, in which case it's normal + // to get a success result, but be unable to keep looping. + if (!m_pluginHostProxy) + return 0; } ASSERT(reply); @@ -782,7 +811,7 @@ bool NetscapePluginInstanceProxy::getWindowNPObject(uint32_t& objectID) if (!frame) return false; - if (!frame->script()->canExecuteScripts()) + if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript)) objectID = 0; else objectID = m_localObjects.idForObject(frame->script()->windowShell(pluginWorld())->window()); @@ -814,8 +843,10 @@ bool NetscapePluginInstanceProxy::evaluate(uint32_t objectID, const String& scri resultData = 0; resultLength = 0; - if (!m_localObjects.contains(objectID)) + if (!m_localObjects.contains(objectID)) { + LOG_ERROR("NetscapePluginInstanceProxy::evaluate: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -857,8 +888,10 @@ bool NetscapePluginInstanceProxy::invoke(uint32_t objectID, const Identifier& me return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::invoke: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -891,8 +924,10 @@ bool NetscapePluginInstanceProxy::invokeDefault(uint32_t objectID, data_t argume return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::invokeDefault: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -924,8 +959,10 @@ bool NetscapePluginInstanceProxy::construct(uint32_t objectID, data_t argumentsD return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::construct: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -958,8 +995,10 @@ bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, const Identifie return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::getProperty: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -977,8 +1016,10 @@ bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, const Identifie bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, unsigned propertyName, data_t& resultData, mach_msg_type_number_t& resultLength) { JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::getProperty: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -999,8 +1040,10 @@ bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, const Identifie return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::setProperty: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -1023,8 +1066,10 @@ bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, unsigned proper return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::setProperty: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -1046,8 +1091,10 @@ bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, const Identi return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::removeProperty: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -1071,8 +1118,10 @@ bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, unsigned pro return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::removeProperty: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -1096,8 +1145,10 @@ bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, const Identifie return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::hasProperty: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -1116,8 +1167,10 @@ bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, unsigned proper return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::hasProperty: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -1136,8 +1189,10 @@ bool NetscapePluginInstanceProxy::hasMethod(uint32_t objectID, const Identifier& return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::hasMethod: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -1156,8 +1211,10 @@ bool NetscapePluginInstanceProxy::enumerate(uint32_t objectID, data_t& resultDat return false; JSObject* object = m_localObjects.get(objectID); - if (!object) + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::enumerate: local object %u doesn't exist.", objectID); return false; + } Frame* frame = core([m_pluginView webFrame]); if (!frame) @@ -1171,7 +1228,7 @@ bool NetscapePluginInstanceProxy::enumerate(uint32_t objectID, data_t& resultDat RetainPtr array(AdoptNS, [[NSMutableArray alloc] init]); for (unsigned i = 0; i < propertyNames.size(); i++) { - uint64_t methodName = reinterpret_cast(_NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().c_str())); + uint64_t methodName = reinterpret_cast(_NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().data())); [array.get() addObject:[NSNumber numberWithLongLong:methodName]]; } @@ -1195,7 +1252,7 @@ void NetscapePluginInstanceProxy::addValueToArray(NSMutableArray *array, ExecSta if (value.isString()) { [array addObject:[NSNumber numberWithInt:StringValueType]]; - [array addObject:String(value.toString(exec))]; + [array addObject:ustringToString(value.toString(exec))]; } else if (value.isNumber()) { [array addObject:[NSNumber numberWithInt:DoubleValueType]]; [array addObject:[NSNumber numberWithDouble:value.toNumber(exec)]]; @@ -1206,9 +1263,9 @@ void NetscapePluginInstanceProxy::addValueToArray(NSMutableArray *array, ExecSta [array addObject:[NSNumber numberWithInt:NullValueType]]; else if (value.isObject()) { JSObject* object = asObject(value); - if (object->classInfo() == &RuntimeObjectImp::s_info) { - RuntimeObjectImp* imp = static_cast(object); - if (ProxyInstance* instance = static_cast(imp->getInternalInstance())) { + if (object->classInfo() == &ProxyRuntimeObject::s_info) { + ProxyRuntimeObject* runtimeObject = static_cast(object); + if (ProxyInstance* instance = runtimeObject->getInternalProxyInstance()) { [array addObject:[NSNumber numberWithInt:NPObjectValueType]]; [array addObject:[NSNumber numberWithInt:instance->objectID()]]; } @@ -1287,7 +1344,7 @@ bool NetscapePluginInstanceProxy::demarshalValueFromArray(ExecState* exec, NSArr if (!frame) return false; - if (!frame->script()->canExecuteScripts()) + if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript)) return false; RefPtr rootObject = frame->script()->createRootObject(m_pluginView); @@ -1335,26 +1392,18 @@ void NetscapePluginInstanceProxy::demarshalValues(ExecState* exec, data_t values void NetscapePluginInstanceProxy::retainLocalObject(JSC::JSValue value) { - if (!value.isObject()) - return; - - JSObject* object = asObject(value); - if (object->classInfo() == &RuntimeObjectImp::s_info) + if (!value.isObject() || value.inherits(&ProxyRuntimeObject::s_info)) return; - m_localObjects.retain(object); + m_localObjects.retain(asObject(value)); } void NetscapePluginInstanceProxy::releaseLocalObject(JSC::JSValue value) { - if (!value.isObject()) + if (!value.isObject() || value.inherits(&ProxyRuntimeObject::s_info)) return; - JSObject* object = asObject(value); - if (object->classInfo() == &RuntimeObjectImp::s_info) - return; - - m_localObjects.release(object); + m_localObjects.release(asObject(value)); } PassRefPtr NetscapePluginInstanceProxy::createBindingsInstance(PassRefPtr rootObject) @@ -1364,10 +1413,6 @@ PassRefPtr NetscapePluginInstanceProxy::createBindingsInstance(PassRef if (_WKPHGetScriptableNPObject(m_pluginHostProxy->port(), m_pluginID, requestID) != KERN_SUCCESS) return 0; - // If the plug-in host crashes while we're waiting for a reply, the last reference to the instance proxy - // will go away. Prevent this by protecting it here. - RefPtr protect(this); - auto_ptr reply = waitForReply(requestID); if (!reply.get()) return 0; @@ -1375,6 +1420,7 @@ PassRefPtr NetscapePluginInstanceProxy::createBindingsInstance(PassRef if (!reply->m_objectID) return 0; + // Since the reply was non-null, "this" is still a valid pointer. return ProxyInstance::create(rootObject, this, reply->m_objectID); } @@ -1458,7 +1504,7 @@ bool NetscapePluginInstanceProxy::getCookies(data_t urlData, mach_msg_type_numbe if (Frame* frame = core([m_pluginView webFrame])) { String cookieString = cookies(frame->document(), url); - WebCore::CString cookieStringUTF8 = cookieString.utf8(); + WTF::CString cookieStringUTF8 = cookieString.utf8(); if (cookieStringUTF8.isNull()) return false; @@ -1500,7 +1546,7 @@ bool NetscapePluginInstanceProxy::getProxy(data_t urlData, mach_msg_type_number_ if (!url) return false; - WebCore::CString proxyStringUTF8 = proxiesForURL(url); + WTF::CString proxyStringUTF8 = proxiesForURL(url); proxyLength = proxyStringUTF8.length(); mig_allocate(reinterpret_cast(&proxyData), proxyLength); @@ -1512,8 +1558,8 @@ bool NetscapePluginInstanceProxy::getProxy(data_t urlData, mach_msg_type_number_ bool NetscapePluginInstanceProxy::getAuthenticationInfo(data_t protocolData, data_t hostData, uint32_t port, data_t schemeData, data_t realmData, data_t& usernameData, mach_msg_type_number_t& usernameLength, data_t& passwordData, mach_msg_type_number_t& passwordLength) { - WebCore::CString username; - WebCore::CString password; + WTF::CString username; + WTF::CString password; if (!WebKit::getAuthenticationInfo(protocolData, hostData, port, schemeData, realmData, username, password)) return false; @@ -1583,7 +1629,7 @@ void NetscapePluginInstanceProxy::resolveURL(const char* url, const char* target { ASSERT(m_pluginView); - WebCore::CString resolvedURL = [m_pluginView resolvedURLStringForURL:url target:target]; + WTF::CString resolvedURL = [m_pluginView resolvedURLStringForURL:url target:target]; resolvedURLLength = resolvedURL.length(); mig_allocate(reinterpret_cast(&resolvedURLData), resolvedURLLength); @@ -1613,10 +1659,10 @@ void NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(ExecState* exec { JSLock lock(SilenceAssertionsOnly); - throwError(exec, GeneralError, globalExceptionString()); + throwError(exec, GeneralError, stringToUString(globalExceptionString())); } - globalExceptionString() = UString(); + globalExceptionString() = String(); } } // namespace WebKit diff --git a/WebKit/mac/Plugins/Hosted/ProxyInstance.h b/WebKit/mac/Plugins/Hosted/ProxyInstance.h index 6e8ac47..c8fb118 100644 --- a/WebKit/mac/Plugins/Hosted/ProxyInstance.h +++ b/WebKit/mac/Plugins/Hosted/ProxyInstance.h @@ -58,10 +58,13 @@ public: private: ProxyInstance(PassRefPtr, NetscapePluginInstanceProxy*, uint32_t objectID); - - virtual JSC::Bindings::Class *getClass() const; - virtual JSC::JSValue invokeMethod(JSC::ExecState*, const JSC::Bindings::MethodList&, const JSC::ArgList& args); + virtual JSC::Bindings::RuntimeObject* newRuntimeObject(JSC::ExecState*); + + virtual JSC::Bindings::Class* getClass() const; + + virtual JSC::JSValue getMethod(JSC::ExecState* exec, const JSC::Identifier& propertyName); + virtual JSC::JSValue invokeMethod(JSC::ExecState*, JSC::RuntimeMethod*, const JSC::ArgList& args); virtual bool supportsInvokeDefaultMethod() const; virtual JSC::JSValue invokeDefaultMethod(JSC::ExecState*, const JSC::ArgList&); diff --git a/WebKit/mac/Plugins/Hosted/ProxyInstance.mm b/WebKit/mac/Plugins/Hosted/ProxyInstance.mm index c7a0ebe..9a976f9 100644 --- a/WebKit/mac/Plugins/Hosted/ProxyInstance.mm +++ b/WebKit/mac/Plugins/Hosted/ProxyInstance.mm @@ -28,9 +28,12 @@ #import "ProxyInstance.h" #import "NetscapePluginHostProxy.h" +#import "ProxyRuntimeObject.h" #import #import #import +#import +#import #import extern "C" { @@ -128,7 +131,12 @@ ProxyInstance::~ProxyInstance() invalidate(); } -JSC::Bindings::Class *ProxyInstance::getClass() const +RuntimeObject* ProxyInstance::newRuntimeObject(ExecState* exec) +{ + return new (exec) ProxyRuntimeObject(exec, this); +} + +JSC::Bindings::Class* ProxyInstance::getClass() const { return proxyClass(); } @@ -147,16 +155,20 @@ JSValue ProxyInstance::invoke(JSC::ExecState* exec, InvokeType type, uint64_t id if (_WKPHNPObjectInvoke(m_instanceProxy->hostProxy()->port(), m_instanceProxy->pluginID(), requestID, m_objectID, type, identifier, (char*)[arguments.get() bytes], [arguments.get() length]) != KERN_SUCCESS) { - for (unsigned i = 0; i < args.size(); i++) - m_instanceProxy->releaseLocalObject(args.at(i)); + if (m_instanceProxy) { + for (unsigned i = 0; i < args.size(); i++) + m_instanceProxy->releaseLocalObject(args.at(i)); + } return jsUndefined(); } auto_ptr reply = waitForReply(requestID); NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(exec); - for (unsigned i = 0; i < args.size(); i++) - m_instanceProxy->releaseLocalObject(args.at(i)); + if (m_instanceProxy) { + for (unsigned i = 0; i < args.size(); i++) + m_instanceProxy->releaseLocalObject(args.at(i)); + } if (!reply.get() || !reply->m_returnValue) return jsUndefined(); @@ -164,8 +176,33 @@ JSValue ProxyInstance::invoke(JSC::ExecState* exec, InvokeType type, uint64_t id return m_instanceProxy->demarshalValue(exec, (char*)CFDataGetBytePtr(reply->m_result.get()), CFDataGetLength(reply->m_result.get())); } -JSValue ProxyInstance::invokeMethod(ExecState* exec, const MethodList& methodList, const ArgList& args) +class ProxyRuntimeMethod : public RuntimeMethod { +public: + ProxyRuntimeMethod(ExecState* exec, const Identifier& name, Bindings::MethodList& list) + : RuntimeMethod(exec, name, list) + { + } + + virtual const ClassInfo* classInfo() const { return &s_info; } + + static const ClassInfo s_info; +}; + +const ClassInfo ProxyRuntimeMethod::s_info = { "ProxyRuntimeMethod", &RuntimeMethod::s_info, 0, 0 }; + +JSValue ProxyInstance::getMethod(JSC::ExecState* exec, const JSC::Identifier& propertyName) +{ + MethodList methodList = getClass()->methodsNamed(propertyName, this); + return new (exec) ProxyRuntimeMethod(exec, propertyName, methodList); +} + +JSValue ProxyInstance::invokeMethod(ExecState* exec, JSC::RuntimeMethod* runtimeMethod, const ArgList& args) { + if (!asObject(runtimeMethod)->inherits(&ProxyRuntimeMethod::s_info)) + return throwError(exec, TypeError, "Attempt to invoke non-plug-in method on plug-in object."); + + const MethodList& methodList = *runtimeMethod->methods(); + ASSERT(methodList.size() == 1); ProxyMethod* method = static_cast(methodList[0]); @@ -280,7 +317,7 @@ void ProxyInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArr if (identifier->isString()) { const char* str = identifier->string(); - nameArray.add(Identifier(JSDOMWindow::commonJSGlobalData(), String::fromUTF8WithLatin1Fallback(str, strlen(str)))); + nameArray.add(Identifier(JSDOMWindow::commonJSGlobalData(), stringToUString(String::fromUTF8WithLatin1Fallback(str, strlen(str))))); } else nameArray.add(Identifier::from(exec, identifier->number())); } @@ -396,7 +433,8 @@ void ProxyInstance::setFieldValue(ExecState* exec, const Field* field, JSValue v m_instanceProxy->pluginID(), requestID, m_objectID, serverIdentifier, valueData, valueLength); mig_deallocate(reinterpret_cast(valueData), valueLength); - m_instanceProxy->releaseLocalObject(value); + if (m_instanceProxy) + m_instanceProxy->releaseLocalObject(value); if (kr != KERN_SUCCESS) return; diff --git a/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.h b/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.h new file mode 100644 index 0000000..af3c5db --- /dev/null +++ b/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if USE(PLUGIN_HOST_PROCESS) + +#ifndef ProxyRuntimeObject_h +#define ProxyRuntimeObject_h + +#include + +namespace WebKit { + +class ProxyInstance; + +class ProxyRuntimeObject : public JSC::Bindings::RuntimeObject { +public: + ProxyRuntimeObject(JSC::ExecState*, PassRefPtr); + virtual ~ProxyRuntimeObject(); + + ProxyInstance* getInternalProxyInstance() const; + + static const JSC::ClassInfo s_info; + +private: + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } +}; + +} + +#endif +#endif diff --git a/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.mm b/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.mm new file mode 100644 index 0000000..5ba6e15 --- /dev/null +++ b/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.mm @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if USE(PLUGIN_HOST_PROCESS) + +#include "ProxyInstance.h" +#include "ProxyRuntimeObject.h" + +using namespace JSC; + +namespace WebKit { + + +const ClassInfo ProxyRuntimeObject::s_info = { "ProxyRuntimeObject", &RuntimeObject::s_info, 0, 0 }; + +ProxyRuntimeObject::ProxyRuntimeObject(ExecState* exec, PassRefPtr instance) + : RuntimeObject(exec, instance) +{ +} + +ProxyRuntimeObject::~ProxyRuntimeObject() +{ +} + +ProxyInstance* ProxyRuntimeObject::getInternalProxyInstance() const +{ + return static_cast(getInternalInstance()); +} + + +} + +#endif diff --git a/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.h b/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.h index 5313ff2..1eb164d 100644 --- a/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.h +++ b/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.h @@ -45,7 +45,6 @@ namespace WebKit { NSSize _previousSize; RefPtr _proxy; - BOOL _pluginHostDied; } - (id)initWithFrame:(NSRect)r diff --git a/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm b/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm index 0ad76f0..cd3724e 100644 --- a/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm +++ b/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm @@ -41,8 +41,9 @@ #import #import #import -#import +#import #import +#import #import #import @@ -180,10 +181,9 @@ extern "C" { if (!shouldClipOutPlugin) visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow); - BOOL sizeChanged = !NSEqualSizes(_previousSize, boundsInWindow.size); _previousSize = boundsInWindow.size; - _proxy->resize(boundsInWindow, visibleRectInWindow, sizeChanged); + _proxy->resize(boundsInWindow, visibleRectInWindow); } - (void)windowFocusChanged:(BOOL)hasFocus @@ -287,6 +287,9 @@ extern "C" { - (void)handleMouseEntered:(NSEvent *)event { + // Set cursor to arrow. Plugins often handle cursor internally, but those that don't will just get this default one. + [[NSCursor arrowCursor] set]; + if (_isStarted && _proxy) _proxy->mouseEvent(self, event, NPCocoaEventMouseEntered); } @@ -295,6 +298,11 @@ extern "C" { { if (_isStarted && _proxy) _proxy->mouseEvent(self, event, NPCocoaEventMouseExited); + + // Set cursor back to arrow cursor. Because NSCursor doesn't know about changes that the plugin made, we could get confused about what we think the + // current cursor is otherwise. Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin. + // FIXME: This should be job of plugin host, see . + [[NSCursor arrowCursor] set]; } - (void)scrollWheel:(NSEvent *)event @@ -348,7 +356,9 @@ extern "C" { - (void)pluginHostDied { - _pluginHostDied = YES; + RenderEmbeddedObject* renderer = toRenderEmbeddedObject(_element->renderer()); + if (renderer) + renderer->setShowsCrashedPluginIndicator(); _pluginLayer = nil; _proxy = 0; @@ -359,6 +369,11 @@ extern "C" { [self invalidatePluginContentRect:[self bounds]]; } +- (void)visibleRectDidChange +{ + [super visibleRectDidChange]; + WKSyncSurfaceToView(self); +} - (void)drawRect:(NSRect)rect { @@ -369,28 +384,12 @@ extern "C" { _proxy->didDraw(); } else _proxy->print(reinterpret_cast([[NSGraphicsContext currentContext] graphicsPort]), [self bounds].size.width, [self bounds].size.height); + } else if ([self inFlatteningPaint] && [self supportsSnapshotting]) { + _proxy->snapshot(reinterpret_cast([[NSGraphicsContext currentContext] graphicsPort]), [self bounds].size.width, [self bounds].size.height); } - + return; } - - if (_pluginHostDied) { - static NSImage *nullPlugInImage; - if (!nullPlugInImage) { - NSBundle *bundle = [NSBundle bundleForClass:[WebHostedNetscapePluginView class]]; - nullPlugInImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"nullplugin" ofType:@"tiff"]]; - [nullPlugInImage setFlipped:YES]; - } - - if (!nullPlugInImage) - return; - - NSSize imageSize = [nullPlugInImage size]; - NSSize viewSize = [self bounds].size; - - NSPoint point = NSMakePoint((viewSize.width - imageSize.width) / 2.0, (viewSize.height - imageSize.height) / 2.0); - [nullPlugInImage drawAtPoint:point fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; - } } - (PassRefPtr)createPluginBindingsInstance:(PassRefPtr)rootObject diff --git a/WebKit/mac/Plugins/Hosted/WebKitPluginClient.defs b/WebKit/mac/Plugins/Hosted/WebKitPluginClient.defs index 6522bf7..6b1a319 100644 --- a/WebKit/mac/Plugins/Hosted/WebKitPluginClient.defs +++ b/WebKit/mac/Plugins/Hosted/WebKitPluginClient.defs @@ -234,7 +234,7 @@ simpleroutine PCBooleanAndDataReply(clientPort :mach_port_t; simpleroutine PCRunSyncOpenPanel(clientPort :mach_port_t; panelData :data_t); -simpleroutine PCSetFullScreenWindowIsShowing(clientPort :mach_port_t; +simpleroutine PCSetFullscreenWindowIsShowing(clientPort :mach_port_t; isShowing :boolean_t); simpleroutine PCSetException(clientPort :mach_port_t; diff --git a/WebKit/mac/Plugins/Hosted/WebKitPluginHost.defs b/WebKit/mac/Plugins/Hosted/WebKitPluginHost.defs index c7cec89..5d9df45 100644 --- a/WebKit/mac/Plugins/Hosted/WebKitPluginHost.defs +++ b/WebKit/mac/Plugins/Hosted/WebKitPluginHost.defs @@ -242,3 +242,9 @@ simpleroutine PHPluginInstancePrivateBrowsingModeDidChange(pluginHostPort :mach_ simpleroutine PHSyncOpenPanelReply(pluginHostPort :mach_port_t; filenames :data_t); + +simpleroutine PHPluginInstanceSnapshot(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + width :uint32_t; + height :uint32_t); diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginView.h b/WebKit/mac/Plugins/WebBaseNetscapePluginView.h index 18dc004..81d801a 100644 --- a/WebKit/mac/Plugins/WebBaseNetscapePluginView.h +++ b/WebKit/mac/Plugins/WebBaseNetscapePluginView.h @@ -41,13 +41,21 @@ @class WebFrame; @class WebView; -namespace WebCore { +namespace WTF { class CString; +} + +namespace WebCore { class HTMLPlugInElement; } class WebHaltablePlugin; +// Also declared in WebCore/WidgetMac.mm +@interface NSView (Widget) +- (void)visibleRectDidChange; +@end + @interface WebBaseNetscapePluginView : NSView { RetainPtr _pluginPackage; @@ -123,10 +131,12 @@ class WebHaltablePlugin; - (void)addWindowObservers; - (void)removeWindowObservers; - (BOOL)shouldClipOutPlugin; +- (BOOL)inFlatteningPaint; +- (BOOL)supportsSnapshotting; - (BOOL)convertFromX:(double)sourceX andY:(double)sourceY space:(NPCoordinateSpace)sourceSpace toX:(double *)destX andY:(double *)destY space:(NPCoordinateSpace)destSpace; -- (WebCore::CString)resolvedURLStringForURL:(const char*)url target:(const char*)target; +- (WTF::CString)resolvedURLStringForURL:(const char*)url target:(const char*)target; - (void)invalidatePluginContentRect:(NSRect)rect; @@ -135,11 +145,11 @@ class WebHaltablePlugin; namespace WebKit { #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) -WebCore::CString proxiesForURL(NSURL *); +WTF::CString proxiesForURL(NSURL *); #endif bool getAuthenticationInfo(const char* protocolStr, const char* hostStr, int32_t port, const char* schemeStr, const char* realmStr, - WebCore::CString& username, WebCore::CString& password); + WTF::CString& username, WTF::CString& password); } #endif diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm b/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm index 04a42ea..eec80f8 100644 --- a/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm +++ b/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm @@ -46,7 +46,6 @@ #import #import #import -#import #import #import #import @@ -60,6 +59,7 @@ #import #import #import +#import #define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification" #define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification" @@ -337,13 +337,10 @@ String WebHaltablePlugin::pluginName() const - (NSRect)_windowClipRect { RenderObject* renderer = _element->renderer(); - - if (renderer && renderer->view()) { - if (FrameView* frameView = renderer->view()->frameView()) - return frameView->windowClipRectForLayer(renderer->enclosingLayer(), true); - } - - return NSZeroRect; + if (!renderer || !renderer->view()) + return NSZeroRect; + + return toRenderWidget(renderer)->windowClipRect(); } - (NSRect)visibleRect @@ -353,6 +350,11 @@ String WebHaltablePlugin::pluginName() const return NSIntersectionRect([self convertRect:[self _windowClipRect] fromView:nil], [super visibleRect]); } +- (void)visibleRectDidChange +{ + [self renewGState]; +} + - (BOOL)acceptsFirstResponder { return YES; @@ -560,7 +562,30 @@ String WebHaltablePlugin::pluginName() const NSWindow *window = [self window]; return !window || [window isMiniaturized] || [NSApp isHidden] || ![self isDescendantOf:[[self window] contentView]] || [self isHiddenOrHasHiddenAncestor]; } + +- (BOOL)inFlatteningPaint +{ + RenderObject* renderer = _element->renderer(); + if (renderer && renderer->view()) { + if (FrameView* frameView = renderer->view()->frameView()) + return frameView->paintBehavior() & PaintBehaviorFlattenCompositingLayers; + } + + return NO; +} + +- (BOOL)supportsSnapshotting +{ + NSBundle *pluginBundle = [_pluginPackage.get() bundle]; + if (![[pluginBundle bundleIdentifier] isEqualToString:@"com.macromedia.Flash Player.plugin"]) + return YES; + // Flash has a bogus Info.plist entry for CFBundleVersionString, so use CFBundleShortVersionString. + NSString *versionString = [pluginBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + // Flash 10.1d51 has a crashing bug if sent a drawRect event when using the CA rendering model: + return ![versionString isEqual:@"10.1.51.95"]; +} + - (BOOL)hasBeenHalted { return _hasBeenHalted; diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm index d8324f7..a5e8f73 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm +++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm @@ -199,8 +199,17 @@ void WebNetscapePluginEventHandlerCarbon::mouseDragged(NSEvent*) { } -void WebNetscapePluginEventHandlerCarbon::mouseMoved(NSEvent*) +void WebNetscapePluginEventHandlerCarbon::mouseMoved(NSEvent* theEvent) { + EventRecord event; + + getCarbonEvent(&event, theEvent); + event.what = adjustCursorEvent; + + BOOL acceptedEvent; + acceptedEvent = sendEvent(&event); + + LOG(PluginEvents, "NPP_HandleEvent(mouseMoved): %d", acceptedEvent); } void WebNetscapePluginEventHandlerCarbon::keyDown(NSEvent *theEvent) diff --git a/WebKit/mac/Plugins/WebNetscapePluginView.mm b/WebKit/mac/Plugins/WebNetscapePluginView.mm index 8fb1503..388b84b 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginView.mm +++ b/WebKit/mac/Plugins/WebNetscapePluginView.mm @@ -50,7 +50,6 @@ #import "WebPluginContainerCheck.h" #import "WebNetscapeContainerCheckContextInfo.h" #import "WebNetscapePluginEventHandler.h" -#import "WebNullPluginView.h" #import "WebPreferences.h" #import "WebPluginRequest.h" #import "WebViewInternal.h" @@ -59,7 +58,6 @@ #import #import #import -#import #import #import #import @@ -77,12 +75,13 @@ #import #import #import +#import #import #define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification" #define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification" #define WKNVSupportsCompositingCoreAnimationPluginsBool 74656 /* TRUE if the browser supports hardware compositing of Core Animation plug-ins */ -static const int WKNVSilverlightFullScreenPerformanceIssueFixed = 7288546; /* TRUE if Siverlight addressed its underlying bug in */ +static const int WKNVSilverlightFullscreenPerformanceIssueFixed = 7288546; /* TRUE if Siverlight addressed its underlying bug in */ using namespace WebCore; using namespace WebKit; @@ -754,6 +753,9 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) if (!_isStarted) return; + // Set cursor to arrow. Plugins often handle cursor internally, but those that don't will just get this default one. + [[NSCursor arrowCursor] set]; + _eventHandler->mouseEntered(theEvent); } @@ -1394,7 +1396,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) - (void)drawRect:(NSRect)rect { - if (drawingModel == NPDrawingModelCoreAnimation) + if (drawingModel == NPDrawingModelCoreAnimation && (![self inFlatteningPaint] || ![self supportsSnapshotting])) return; if (!_isStarted) @@ -2276,7 +2278,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) - (char*)resolveURL:(const char*)url forTarget:(const char*)target { - WebCore::CString location = [self resolvedURLStringForURL:url target:target]; + CString location = [self resolvedURLStringForURL:url target:target]; if (location.isNull()) return 0; @@ -2307,13 +2309,13 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) // 1) Microsoft releases a genuine fix for 7288546. // 2) Enough Silverlight users update to the new Silverlight. // For now, we'll distinguish older broken versions of Silverlight by asking the plug-in if it resolved its full screen badness. -- (void)_workaroundSilverlightFullScreenBug:(BOOL)initializedPlugin +- (void)_workaroundSilverlightFullscreenBug:(BOOL)initializedPlugin { #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) ASSERT(_isSilverlight); - NPBool isFullScreenPerformanceIssueFixed = 0; + NPBool isFullscreenPerformanceIssueFixed = 0; NPPluginFuncs *pluginFuncs = [_pluginPackage.get() pluginFuncs]; - if (pluginFuncs->getvalue && pluginFuncs->getvalue(plugin, static_cast(WKNVSilverlightFullScreenPerformanceIssueFixed), &isFullScreenPerformanceIssueFixed) == NPERR_NO_ERROR && isFullScreenPerformanceIssueFixed) + if (pluginFuncs->getvalue && pluginFuncs->getvalue(plugin, static_cast(WKNVSilverlightFullscreenPerformanceIssueFixed), &isFullscreenPerformanceIssueFixed) == NPERR_NO_ERROR && isFullscreenPerformanceIssueFixed) return; static CGLPixelFormatObj pixelFormatObject = 0; @@ -2354,7 +2356,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) NPError npErr = [_pluginPackage.get() pluginFuncs]->newp((char *)[_MIMEType.get() cString], plugin, _mode, argsCount, cAttributes, cValues, NULL); [[self class] setCurrentPluginView:nil]; if (_isSilverlight) - [self _workaroundSilverlightFullScreenBug:YES]; + [self _workaroundSilverlightFullscreenBug:YES]; LOG(Plugins, "NPP_New: %d", npErr); return npErr; } @@ -2364,7 +2366,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin); if (_isSilverlight) - [self _workaroundSilverlightFullScreenBug:NO]; + [self _workaroundSilverlightFullscreenBug:NO]; NPError npErr; npErr = ![_pluginPackage.get() pluginFuncs]->destroy(plugin, NULL); diff --git a/WebKit/mac/Plugins/WebNullPluginView.h b/WebKit/mac/Plugins/WebNullPluginView.h deleted file mode 100644 index 3ca1532..0000000 --- a/WebKit/mac/Plugins/WebNullPluginView.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import - -@class DOMElement; - -@interface WebNullPluginView : NSImageView -{ - NSError *error; - DOMElement *element; -} - -- (id)initWithFrame:(NSRect)frame error:(NSError *)error DOMElement:(DOMElement *)element; - -@end diff --git a/WebKit/mac/Plugins/WebNullPluginView.mm b/WebKit/mac/Plugins/WebNullPluginView.mm deleted file mode 100644 index bcc7a4b..0000000 --- a/WebKit/mac/Plugins/WebNullPluginView.mm +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "WebNullPluginView.h" - -#import "DOMElementInternal.h" -#import "WebDelegateImplementationCaching.h" -#import "WebFrameInternal.h" -#import "WebViewInternal.h" -#import -#import - -@implementation WebNullPluginView - -- initWithFrame:(NSRect)frame error:(NSError *)err DOMElement:(DOMElement *)elem -{ - static NSImage *nullPlugInImage; - if (!nullPlugInImage) { - NSBundle *bundle = [NSBundle bundleForClass:[WebNullPluginView class]]; - NSString *imagePath = [bundle pathForResource:@"nullplugin" ofType:@"tiff"]; - nullPlugInImage = [[NSImage alloc] initWithContentsOfFile:imagePath]; - } - - self = [super initWithFrame:frame]; - if (!self) - return nil; - - error = [err retain]; - if (err) - element = [elem retain]; - - [self setImage:nullPlugInImage]; - - return self; -} - -- (void)dealloc - -{ - [error release]; - [element release]; - [super dealloc]; -} - -- (void)reportFailure -{ - NSError *localError = error; - DOMElement *localElement = element; - - error = nil; - element = nil; - - WebFrame *webFrame = kit(core(localElement)->document()->frame()); - if (webFrame) { - WebView *webView = [webFrame webView]; - WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView); - if (implementations->plugInFailedWithErrorFunc) - CallResourceLoadDelegate(implementations->plugInFailedWithErrorFunc, webView, - @selector(webView:plugInFailedWithError:dataSource:), localError, [webFrame _dataSource]); - } - - [localError release]; - [localElement release]; -} - -- (void)viewDidMoveToWindow -{ - if (!error) - return; - - if ([self window]) - [self reportFailure]; -} - -@end diff --git a/WebKit/mac/Plugins/WebPluginController.mm b/WebKit/mac/Plugins/WebPluginController.mm index 4343119..1c85862 100644 --- a/WebKit/mac/Plugins/WebPluginController.mm +++ b/WebKit/mac/Plugins/WebPluginController.mm @@ -36,6 +36,7 @@ #import "WebHTMLViewPrivate.h" #import "WebKitErrorsPrivate.h" #import "WebKitLogging.h" +#import "WebNSObjectExtras.h" #import "WebNSURLExtras.h" #import "WebNSViewExtras.h" #import "WebPlugin.h" @@ -57,6 +58,7 @@ #import #import #import +#import #import using namespace WebCore; @@ -78,6 +80,10 @@ using namespace HTMLNames; - (void)pluginDestroy; @end +static bool isKindOfClass(id, NSString* className); +static void installFlip4MacPlugInWorkaroundIfNecessary(); + + static NSMutableSet *pluginViews = nil; @implementation WebPluginController @@ -209,7 +215,10 @@ static NSMutableSet *pluginViews = nil; BOOL oldDefersCallbacks = [[self webView] defersCallbacks]; if (!oldDefersCallbacks) [[self webView] setDefersCallbacks:YES]; - + + if (isKindOfClass(view, @"WmvPlugin")) + installFlip4MacPlugInWorkaroundIfNecessary(); + LOG(Plugins, "initializing plug-in %@", view); if ([view respondsToSelector:@selector(webPlugInInitialize)]) { JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); @@ -351,21 +360,11 @@ static void cancelOutstandingCheck(const void *item, void *context) } } -// For compatibility only. -- (void)showURL:(NSURL *)URL inFrame:(NSString *)target -{ - [self webPlugInContainerLoadRequest:[NSURLRequest requestWithURL:URL] inFrame:target]; -} - - (void)webPlugInContainerShowStatus:(NSString *)message { - if (!message) { + if (!message) message = @""; - } - if (!_documentView) { - LOG_ERROR("could not show status message (%@) because plug-in has already been destroyed", message); - return; - } + WebView *v = [_dataSource _webView]; [[v _UIDelegateForwarder] webView:v setStatusText:message]; } @@ -475,3 +474,85 @@ static WebCore::HTMLMediaElement* mediaProxyClient(DOMElement* element) #endif @end + +static bool isKindOfClass(id object, NSString *className) +{ + Class cls = NSClassFromString(className); + + if (!cls) + return false; + + return [object isKindOfClass:cls]; +} + + +// Existing versions of the Flip4Mac WebKit plug-in have an object lifetime bug related to an NSAlert that is +// used to notify the user about updates to the plug-in. This bug can result in Safari crashing if the page +// containing the plug-in navigates while the alert is displayed (). +// +// The gist of the bug is thus: Flip4Mac sets an instance of the TSUpdateCheck class as the modal delegate of the +// NSAlert instance. This TSUpdateCheck instance itself has a delegate. The delegate is set to the WmvPlugin +// instance which is the NSView subclass that is exposed to WebKit as the plug-in view. Since this relationship +// is that of delegates the TSUpdateCheck does not retain the WmvPlugin. This leads to a bug if the WmvPlugin +// instance is destroyed before the TSUpdateCheck instance as the TSUpdateCheck instance will be left with a +// pointer to a stale object. This will happen if a page containing the Flip4Mac plug-in triggers a navigation +// while the update sheet is visible as the WmvPlugin instance is removed from the view hierarchy and there are +// no other references to keep the object alive. +// +// We work around this bug by patching the following two messages: +// +// 1) -[NSAlert beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:] +// 2) -[TSUpdateCheck alertDidEnd:returnCode:contextInfo:] +// +// Our override of 1) detects whether it is Flip4Mac's update sheet triggering the alert by checking whether the +// modal delegate is an instance of TSUpdateCheck. If it is, it retains the modal delegate's delegate. +// +// Our override of 2) then autoreleases the delegate, balancing the retain we added in 1). +// +// These two overrides have the effect of ensuring that the WmvPlugin instance will always outlive the TSUpdateCheck +// instance, preventing the TSUpdateCheck instance from accessing a stale delegate pointer and crashing the application. + + +typedef void (*beginSheetModalForWindowIMP)(id, SEL, NSWindow *, id, SEL, void*); +static beginSheetModalForWindowIMP original_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_; + +typedef void (*alertDidEndIMP)(id, SEL, NSAlert *, NSInteger, void*); +static alertDidEndIMP original_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_; + +static void WebKit_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_(id object, SEL selector, NSAlert *alert, NSInteger returnCode, void* contextInfo) +{ + [[object delegate] autorelease]; + + original_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_(object, selector, alert, returnCode, contextInfo); +} + +static void WebKit_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(id object, SEL selector, NSWindow *window, id modalDelegate, SEL didEndSelector, void* contextInfo) +{ + if (isKindOfClass(modalDelegate, @"TSUpdateCheck")) + [[modalDelegate delegate] retain]; + + original_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(object, selector, window, modalDelegate, didEndSelector, contextInfo); +} + +static void installFlip4MacPlugInWorkaroundIfNecessary() +{ + static bool hasInstalledFlip4MacPlugInWorkaround; + if (!hasInstalledFlip4MacPlugInWorkaround) { + Class TSUpdateCheck = objc_lookUpClass("TSUpdateCheck"); + if (!TSUpdateCheck) + return; + + Method methodToPatch = class_getInstanceMethod(TSUpdateCheck, @selector(alertDidEnd:returnCode:contextInfo:)); + if (!methodToPatch) + return; + + IMP originalMethod = method_setImplementation(methodToPatch, reinterpret_cast(WebKit_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_)); + original_TSUpdateCheck_alertDidEnd_returnCode_contextInfo_ = reinterpret_cast(originalMethod); + + methodToPatch = class_getInstanceMethod(objc_getRequiredClass("NSAlert"), @selector(beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:)); + originalMethod = method_setImplementation(methodToPatch, reinterpret_cast(WebKit_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_)); + original_NSAlert_beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_ = reinterpret_cast(originalMethod); + + hasInstalledFlip4MacPlugInWorkaround = true; + } +} -- cgit v1.1