diff options
Diffstat (limited to 'WebKit/mac/Plugins/WebNetscapePluginView.mm')
-rw-r--r-- | WebKit/mac/Plugins/WebNetscapePluginView.mm | 2513 |
1 files changed, 0 insertions, 2513 deletions
diff --git a/WebKit/mac/Plugins/WebNetscapePluginView.mm b/WebKit/mac/Plugins/WebNetscapePluginView.mm deleted file mode 100644 index b215c8d..0000000 --- a/WebKit/mac/Plugins/WebNetscapePluginView.mm +++ /dev/null @@ -1,2513 +0,0 @@ -/* - * Copyright (C) 2005, 2006, 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. - */ - -#if ENABLE(NETSCAPE_PLUGIN_API) - -#import "WebNetscapePluginView.h" - -#import "QuickDrawCompatibility.h" -#import "WebDataSourceInternal.h" -#import "WebDefaultUIDelegate.h" -#import "WebFrameInternal.h" -#import "WebFrameView.h" -#import "WebKitErrorsPrivate.h" -#import "WebKitLogging.h" -#import "WebKitNSStringExtras.h" -#import "WebKitSystemInterface.h" -#import "WebNSDataExtras.h" -#import "WebNSDictionaryExtras.h" -#import "WebNSObjectExtras.h" -#import "WebNSURLExtras.h" -#import "WebNSURLRequestExtras.h" -#import "WebNSViewExtras.h" -#import "WebNetscapeContainerCheckContextInfo.h" -#import "WebNetscapeContainerCheckPrivate.h" -#import "WebNetscapePluginEventHandler.h" -#import "WebNetscapePluginPackage.h" -#import "WebNetscapePluginStream.h" -#import "WebPluginContainerCheck.h" -#import "WebPluginRequest.h" -#import "WebPreferences.h" -#import "WebUIDelegatePrivate.h" -#import "WebViewInternal.h" -#import <Carbon/Carbon.h> -#import <WebCore/CookieJar.h> -#import <WebCore/DocumentLoader.h> -#import <WebCore/Element.h> -#import <WebCore/Frame.h> -#import <WebCore/FrameLoader.h> -#import <WebCore/FrameTree.h> -#import <WebCore/FrameView.h> -#import <WebCore/HTMLPlugInElement.h> -#import <WebCore/Page.h> -#import <WebCore/PluginMainThreadScheduler.h> -#import <WebCore/ProxyServer.h> -#import <WebCore/ScriptController.h> -#import <WebCore/SecurityOrigin.h> -#import <WebCore/SoftLinking.h> -#import <WebCore/WebCoreObjCExtras.h> -#import <WebCore/WebCoreURLResponse.h> -#import <WebCore/npruntime_impl.h> -#import <WebKit/DOMPrivate.h> -#import <WebKit/WebUIDelegate.h> -#import <objc/objc-runtime.h> -#import <runtime/InitializeThreading.h> -#import <runtime/JSLock.h> -#import <wtf/Assertions.h> -#import <wtf/Threading.h> -#import <wtf/text/CString.h> - -#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 <rdar://problem/7288546> */ - -using namespace WebCore; -using namespace WebKit; -using namespace std; - -static inline bool isDrawingModelQuickDraw(NPDrawingModel drawingModel) -{ -#ifndef NP_NO_QUICKDRAW - return drawingModel == NPDrawingModelQuickDraw; -#else - return false; -#endif -}; - -@interface WebNetscapePluginView (Internal) -- (NPError)_createPlugin; -- (void)_destroyPlugin; -- (NSBitmapImageRep *)_printedPluginBitmap; -- (void)_redeliverStream; -- (BOOL)_shouldCancelSrcStream; -@end - -static WebNetscapePluginView *currentPluginView = nil; - -typedef struct OpaquePortState* PortState; - -static const double ThrottledTimerInterval = 0.25; - -class PluginTimer : public TimerBase { -public: - typedef void (*TimerFunc)(NPP npp, uint32_t timerID); - - PluginTimer(NPP npp, uint32_t timerID, uint32_t interval, NPBool repeat, TimerFunc timerFunc) - : m_npp(npp) - , m_timerID(timerID) - , m_interval(interval) - , m_repeat(repeat) - , m_timerFunc(timerFunc) - { - } - - void start(bool throttle) - { - ASSERT(!isActive()); - - double timeInterval = m_interval / 1000.0; - - if (throttle) - timeInterval = max(timeInterval, ThrottledTimerInterval); - - if (m_repeat) - startRepeating(timeInterval); - else - startOneShot(timeInterval); - } - -private: - virtual void fired() - { - m_timerFunc(m_npp, m_timerID); - if (!m_repeat) - delete this; - } - - NPP m_npp; - uint32_t m_timerID; - uint32_t m_interval; - NPBool m_repeat; - TimerFunc m_timerFunc; -}; - -#ifndef NP_NO_QUICKDRAW - -// QuickDraw is not available in 64-bit - -typedef struct { - GrafPtr oldPort; - GDHandle oldDevice; - Point oldOrigin; - RgnHandle oldClipRegion; - RgnHandle oldVisibleRegion; - RgnHandle clipRegion; - BOOL forUpdate; -} PortState_QD; - -#endif /* NP_NO_QUICKDRAW */ - -typedef struct { - CGContextRef context; -} PortState_CG; - -@class NSTextInputContext; -@interface NSResponder (AppKitDetails) -- (NSTextInputContext *)inputContext; -@end - -@interface WebNetscapePluginView (ForwardDeclarations) -- (void)setWindowIfNecessary; -- (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification; -@end - -@implementation WebNetscapePluginView - -+ (void)initialize -{ - JSC::initializeThreading(); - WTF::initializeMainThreadToProcessMainThread(); -#ifndef BUILDING_ON_TIGER - WebCoreObjCFinalizeOnMainThread(self); -#endif - WKSendUserChangeNotifications(); -} - -// MARK: EVENTS - -// The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers -// the entire window frame (or structure region to use the Carbon term) rather then just the window content. -// We can remove this when <rdar://problem/4201099> is fixed. -- (void)fixWindowPort -{ -#ifndef NP_NO_QUICKDRAW - ASSERT(isDrawingModelQuickDraw(drawingModel)); - - NSWindow *currentWindow = [self currentWindow]; - if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")]) - return; - - float windowHeight = [currentWindow frame].size.height; - NSView *contentView = [currentWindow contentView]; - NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates - - CGrafPtr oldPort; - GetPort(&oldPort); - SetPort(GetWindowPort((WindowRef)[currentWindow windowRef])); - - MovePortTo(static_cast<short>(contentRect.origin.x), /* Flip Y */ static_cast<short>(windowHeight - NSMaxY(contentRect))); - PortSize(static_cast<short>(contentRect.size.width), static_cast<short>(contentRect.size.height)); - - SetPort(oldPort); -#endif -} - -#ifndef NP_NO_QUICKDRAW -static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context) -{ - UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) & kCGBitmapByteOrderMask; - if (byteOrder == kCGBitmapByteOrderDefault) - switch (CGBitmapContextGetBitsPerPixel(context)) { - case 16: - byteOrder = kCGBitmapByteOrder16Host; - break; - case 32: - byteOrder = kCGBitmapByteOrder32Host; - break; - } - switch (byteOrder) { - case kCGBitmapByteOrder16Little: - return k16LE555PixelFormat; - case kCGBitmapByteOrder32Little: - return k32BGRAPixelFormat; - case kCGBitmapByteOrder16Big: - return k16BE555PixelFormat; - case kCGBitmapByteOrder32Big: - return k32ARGBPixelFormat; - } - ASSERT_NOT_REACHED(); - return 0; -} - -static inline void getNPRect(const CGRect& cgr, NPRect& npr) -{ - npr.top = static_cast<uint16_t>(cgr.origin.y); - npr.left = static_cast<uint16_t>(cgr.origin.x); - npr.bottom = static_cast<uint16_t>(CGRectGetMaxY(cgr)); - npr.right = static_cast<uint16_t>(CGRectGetMaxX(cgr)); -} - -#endif - -static inline void getNPRect(const NSRect& nr, NPRect& npr) -{ - npr.top = static_cast<uint16_t>(nr.origin.y); - npr.left = static_cast<uint16_t>(nr.origin.x); - npr.bottom = static_cast<uint16_t>(NSMaxY(nr)); - npr.right = static_cast<uint16_t>(NSMaxX(nr)); -} - -- (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate -{ - ASSERT([self currentWindow] != nil); - - // The base coordinates of a window and it's contentView happen to be the equal at a userSpaceScaleFactor - // of 1. For non-1.0 scale factors this assumption is false. - NSView *windowContentView = [[self window] contentView]; - NSRect boundsInWindow = [self convertRect:[self bounds] toView:windowContentView]; - NSRect visibleRectInWindow = [self convertRect:[self visibleRect] toView:windowContentView]; - - // Flip Y to convert -[NSWindow contentView] coordinates to top-left-based window coordinates. - float borderViewHeight = [[self currentWindow] frame].size.height; - boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow); - visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow); - -#ifndef NP_NO_QUICKDRAW - WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef]; - ASSERT(windowRef); - - // Look at the Carbon port to convert top-left-based window coordinates into top-left-based content coordinates. - if (isDrawingModelQuickDraw(drawingModel)) { - // If drawing with QuickDraw, fix the window port so that it has the same bounds as the NSWindow's - // content view. This makes it easier to convert between AppKit view and QuickDraw port coordinates. - [self fixWindowPort]; - - ::Rect portBounds; - CGrafPtr port = GetWindowPort(windowRef); - GetPortBounds(port, &portBounds); - - PixMap *pix = *GetPortPixMap(port); - boundsInWindow.origin.x += pix->bounds.left - portBounds.left; - boundsInWindow.origin.y += pix->bounds.top - portBounds.top; - visibleRectInWindow.origin.x += pix->bounds.left - portBounds.left; - visibleRectInWindow.origin.y += pix->bounds.top - portBounds.top; - } -#endif - - window.type = NPWindowTypeWindow; - window.x = (int32_t)boundsInWindow.origin.x; - window.y = (int32_t)boundsInWindow.origin.y; - window.width = static_cast<uint32_t>(NSWidth(boundsInWindow)); - window.height = static_cast<uint32_t>(NSHeight(boundsInWindow)); - - // "Clip-out" the plug-in when: - // 1) it's not really in a window or off-screen or has no height or width. - // 2) window.x is a "big negative number" which is how WebCore expresses off-screen widgets. - // 3) the window is miniaturized or the app is hidden - // 4) we're inside of viewWillMoveToWindow: with a nil window. In this case, superviews may already have nil - // superviews and nil windows and results from convertRect:toView: are incorrect. - if (window.width <= 0 || window.height <= 0 || window.x < -100000 || [self shouldClipOutPlugin]) { - - // The following code tries to give plug-ins the same size they will eventually have. - // The specifiedWidth and specifiedHeight variables are used to predict the size that - // WebCore will eventually resize us to. - - // The QuickTime plug-in has problems if you give it a width or height of 0. - // Since other plug-ins also might have the same sort of trouble, we make sure - // to always give plug-ins a size other than 0,0. - - if (window.width <= 0) - window.width = specifiedWidth > 0 ? specifiedWidth : 100; - if (window.height <= 0) - window.height = specifiedHeight > 0 ? specifiedHeight : 100; - - window.clipRect.bottom = window.clipRect.top; - window.clipRect.left = window.clipRect.right; - - // Core Animation plug-ins need to be updated (with a 0,0,0,0 clipRect) when - // moved to a background tab. We don't do this for Core Graphics plug-ins as - // older versions of Flash have historical WebKit-specific code that isn't - // compatible with this behavior. - if (drawingModel == NPDrawingModelCoreAnimation) - getNPRect(NSZeroRect, window.clipRect); - } else { - getNPRect(visibleRectInWindow, window.clipRect); - } - - // Save the port state, set up the port for entry into the plugin - PortState portState; - switch (drawingModel) { -#ifndef NP_NO_QUICKDRAW - case NPDrawingModelQuickDraw: { - // Set up NS_Port. - ::Rect portBounds; - CGrafPtr port = GetWindowPort(windowRef); - GetPortBounds(port, &portBounds); - nPort.qdPort.port = port; - nPort.qdPort.portx = (int32_t)-boundsInWindow.origin.x; - nPort.qdPort.porty = (int32_t)-boundsInWindow.origin.y; - window.window = &nPort; - - PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD)); - portState = (PortState)qdPortState; - - GetGWorld(&qdPortState->oldPort, &qdPortState->oldDevice); - - qdPortState->oldOrigin.h = portBounds.left; - qdPortState->oldOrigin.v = portBounds.top; - - qdPortState->oldClipRegion = NewRgn(); - GetPortClipRegion(port, qdPortState->oldClipRegion); - - qdPortState->oldVisibleRegion = NewRgn(); - GetPortVisibleRegion(port, qdPortState->oldVisibleRegion); - - RgnHandle clipRegion = NewRgn(); - qdPortState->clipRegion = clipRegion; - - CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - if (currentContext && WKCGContextIsBitmapContext(currentContext)) { - // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData - // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext - // returns true, it still might not be a context we need to create a GWorld for; for example - // transparency layers will return true, but return 0 for CGBitmapContextGetData. - void* offscreenData = CGBitmapContextGetData(currentContext); - if (offscreenData) { - // If the current context is an offscreen bitmap, then create a GWorld for it. - ::Rect offscreenBounds; - offscreenBounds.top = 0; - offscreenBounds.left = 0; - offscreenBounds.right = CGBitmapContextGetWidth(currentContext); - offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext); - GWorldPtr newOffscreenGWorld; - QDErr err = NewGWorldFromPtr(&newOffscreenGWorld, - getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0, - static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext)); - ASSERT(newOffscreenGWorld); - ASSERT(!err); - if (!err) { - if (offscreenGWorld) - DisposeGWorld(offscreenGWorld); - offscreenGWorld = newOffscreenGWorld; - - SetGWorld(offscreenGWorld, NULL); - - port = offscreenGWorld; - - nPort.qdPort.port = port; - boundsInWindow = [self bounds]; - - // Generate a QD origin based on the current affine transform for currentContext. - CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext); - CGPoint origin = {0,0}; - CGPoint axisFlip = {1,1}; - origin = CGPointApplyAffineTransform(origin, offscreenMatrix); - axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix); - - // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that. - origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x); - origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y); - - nPort.qdPort.portx = static_cast<int32_t>(-boundsInWindow.origin.x + origin.x); - nPort.qdPort.porty = static_cast<int32_t>(-boundsInWindow.origin.y - origin.y); - window.x = 0; - window.y = 0; - window.window = &nPort; - - // Use the clip bounds from the context instead of the bounds we created - // from the window above. - getNPRect(CGRectOffset(CGContextGetClipBoundingBox(currentContext), -origin.x, origin.y), window.clipRect); - } - } - } - - MacSetRectRgn(clipRegion, - window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty, - window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty); - - // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip. - if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) { - // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are - // not going to be redrawn this update. This forces plug-ins to play nice with z-index ordering. - if (forUpdate) { - RgnHandle viewClipRegion = NewRgn(); - - // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and - // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView - // knows about the true set of dirty rects. - NSView *opaqueAncestor = [self opaqueAncestor]; - const NSRect *dirtyRects; - NSInteger dirtyRectCount, dirtyRectIndex; - [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount]; - - for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) { - NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor]; - if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) { - // Create a region for this dirty rect - RgnHandle dirtyRectRegion = NewRgn(); - SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect))); - - // Union this dirty rect with the rest of the dirty rects - UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion); - DisposeRgn(dirtyRectRegion); - } - } - - // Intersect the dirty region with the clip region, so that we only draw over dirty parts - SectRgn(clipRegion, viewClipRegion, clipRegion); - DisposeRgn(viewClipRegion); - } - } - - // Switch to the port and set it up. - SetPort(port); - PenNormal(); - ForeColor(blackColor); - BackColor(whiteColor); - SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty); - SetPortClipRegion(nPort.qdPort.port, clipRegion); - - if (forUpdate) { - // AppKit may have tried to help us by doing a BeginUpdate. - // But the invalid region at that level didn't include AppKit's notion of what was not valid. - // We reset the port's visible region to counteract what BeginUpdate did. - SetPortVisibleRegion(nPort.qdPort.port, clipRegion); - InvalWindowRgn(windowRef, clipRegion); - } - - qdPortState->forUpdate = forUpdate; - break; - } -#endif /* NP_NO_QUICKDRAW */ - - case NPDrawingModelCoreGraphics: { - if (![self canDraw]) { - portState = NULL; - break; - } - - ASSERT([NSView focusView] == self); - - CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); - - PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG)); - portState = (PortState)cgPortState; - cgPortState->context = context; - -#ifndef NP_NO_CARBON - if (eventModel != NPEventModelCocoa) { - // Update the plugin's window/context - nPort.cgPort.window = windowRef; - nPort.cgPort.context = context; - window.window = &nPort.cgPort; - } -#endif /* NP_NO_CARBON */ - - // Save current graphics context's state; will be restored by -restorePortState: - CGContextSaveGState(context); - - // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip. - if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) { - // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and - // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView - // knows about the true set of dirty rects. - NSView *opaqueAncestor = [self opaqueAncestor]; - const NSRect *dirtyRects; - NSInteger count; - [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count]; - Vector<CGRect, 16> convertedDirtyRects; - convertedDirtyRects.resize(count); - for (int i = 0; i < count; ++i) - reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor]; - CGContextClipToRects(context, convertedDirtyRects.data(), count); - } - - break; - } - - case NPDrawingModelCoreAnimation: - // Just set the port state to a dummy value. - portState = (PortState)1; - break; - - default: - ASSERT_NOT_REACHED(); - portState = NULL; - break; - } - - return portState; -} - -- (PortState)saveAndSetNewPortState -{ - return [self saveAndSetNewPortStateForUpdate:NO]; -} - -- (void)restorePortState:(PortState)portState -{ - ASSERT([self currentWindow]); - ASSERT(portState); - - switch (drawingModel) { -#ifndef NP_NO_QUICKDRAW - case NPDrawingModelQuickDraw: { - PortState_QD *qdPortState = (PortState_QD *)portState; - WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef]; - CGrafPtr port = GetWindowPort(windowRef); - - SetPort(port); - - if (qdPortState->forUpdate) - ValidWindowRgn(windowRef, qdPortState->clipRegion); - - SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v); - - SetPortClipRegion(port, qdPortState->oldClipRegion); - if (qdPortState->forUpdate) - SetPortVisibleRegion(port, qdPortState->oldVisibleRegion); - - DisposeRgn(qdPortState->oldClipRegion); - DisposeRgn(qdPortState->oldVisibleRegion); - DisposeRgn(qdPortState->clipRegion); - - SetGWorld(qdPortState->oldPort, qdPortState->oldDevice); - break; - } -#endif /* NP_NO_QUICKDRAW */ - - case NPDrawingModelCoreGraphics: { - ASSERT([NSView focusView] == self); - - CGContextRef context = ((PortState_CG *)portState)->context; - ASSERT(!nPort.cgPort.context || (context == nPort.cgPort.context)); - CGContextRestoreGState(context); - break; - } - - case NPDrawingModelCoreAnimation: - ASSERT(portState == (PortState)1); - break; - default: - ASSERT_NOT_REACHED(); - break; - } -} - -- (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect -{ - if (![self window]) - return NO; - ASSERT(event); - - if (!_isStarted) - return NO; - - ASSERT([_pluginPackage.get() pluginFuncs]->event); - - // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow. - // We probably don't want more general reentrancy protection; we are really - // protecting only against this one case, which actually comes up when - // you first install the SVG viewer plug-in. - if (inSetWindow) - return NO; - - Frame* frame = core([self webFrame]); - if (!frame) - return NO; - Page* page = frame->page(); - if (!page) - return NO; - - // Can only send drawRect (updateEvt) to CoreGraphics plugins when actually drawing - ASSERT((drawingModel != NPDrawingModelCoreGraphics) || !eventIsDrawRect || [NSView focusView] == self); - - PortState portState = NULL; - - if (isDrawingModelQuickDraw(drawingModel) || (drawingModel != NPDrawingModelCoreAnimation && eventIsDrawRect)) { - // In CoreGraphics mode, the port state only needs to be saved/set when redrawing the plug-in view. - // The plug-in is not allowed to draw at any other time. - portState = [self saveAndSetNewPortStateForUpdate:eventIsDrawRect]; - // We may have changed the window, so inform the plug-in. - [self setWindowIfNecessary]; - } - -#if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW) - // Draw green to help debug. - // If we see any green we know something's wrong. - // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined. - if (isDrawingModelQuickDraw(drawingModel) && eventIsDrawRect) { - ForeColor(greenColor); - const ::Rect bigRect = { -10000, -10000, 10000, 10000 }; - PaintRect(&bigRect); - ForeColor(blackColor); - } -#endif - - // Temporarily retain self in case the plug-in view is released while sending an event. - [[self retain] autorelease]; - - BOOL acceptedEvent; - [self willCallPlugInFunction]; - // Set the pluginAllowPopup flag. - ASSERT(_eventHandler); - bool oldAllowPopups = frame->script()->allowPopupsFromPlugin(); - frame->script()->setAllowPopupsFromPlugin(_eventHandler->currentEventIsUserGesture()); - { - JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); - acceptedEvent = [_pluginPackage.get() pluginFuncs]->event(plugin, event); - } - // Restore the old pluginAllowPopup flag. - frame->script()->setAllowPopupsFromPlugin(oldAllowPopups); - [self didCallPlugInFunction]; - - if (portState) { - if ([self currentWindow]) - [self restorePortState:portState]; - if (portState != (PortState)1) - free(portState); - } - - return acceptedEvent; -} - -- (void)windowFocusChanged:(BOOL)hasFocus -{ - _eventHandler->windowFocusChanged(hasFocus); -} - -- (void)sendDrawRectEvent:(NSRect)rect -{ - ASSERT(_eventHandler); - - CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); - _eventHandler->drawRect(context, rect); -} - -- (void)stopTimers -{ - [super stopTimers]; - - if (_eventHandler) - _eventHandler->stopTimers(); - - if (!timers) - return; - - HashMap<uint32_t, PluginTimer*>::const_iterator end = timers->end(); - for (HashMap<uint32_t, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) { - PluginTimer* timer = it->second; - timer->stop(); - } -} - -- (void)startTimers -{ - [super startTimers]; - - // If the plugin is completely obscured (scrolled out of view, for example), then we will - // send null events at a reduced rate. - _eventHandler->startTimers(_isCompletelyObscured); - - if (!timers) - return; - - HashMap<uint32_t, PluginTimer*>::const_iterator end = timers->end(); - for (HashMap<uint32_t, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) { - PluginTimer* timer = it->second; - ASSERT(!timer->isActive()); - timer->start(_isCompletelyObscured); - } -} - -- (void)focusChanged -{ - // We need to null check the event handler here because - // the plug-in view can resign focus after it's been stopped - // and the event handler has been deleted. - if (_eventHandler) - _eventHandler->focusChanged(_hasFocus); -} - -- (void)mouseDown:(NSEvent *)theEvent -{ - if (!_isStarted) - return; - - _eventHandler->mouseDown(theEvent); -} - -- (void)mouseUp:(NSEvent *)theEvent -{ - if (!_isStarted) - return; - - _eventHandler->mouseUp(theEvent); -} - -- (void)handleMouseEntered:(NSEvent *)theEvent -{ - 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); -} - -- (void)handleMouseExited:(NSEvent *)theEvent -{ - if (!_isStarted) - return; - - _eventHandler->mouseExited(theEvent); - - // 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. - [[NSCursor arrowCursor] set]; -} - -- (void)handleMouseMoved:(NSEvent *)theEvent -{ - if (!_isStarted) - return; - - _eventHandler->mouseMoved(theEvent); -} - -- (void)mouseDragged:(NSEvent *)theEvent -{ - if (!_isStarted) - return; - - _eventHandler->mouseDragged(theEvent); -} - -- (void)scrollWheel:(NSEvent *)theEvent -{ - if (!_isStarted) { - [super scrollWheel:theEvent]; - return; - } - - if (!_eventHandler->scrollWheel(theEvent)) - [super scrollWheel:theEvent]; -} - -- (void)keyUp:(NSEvent *)theEvent -{ - if (!_isStarted) - return; - - _eventHandler->keyUp(theEvent); -} - -- (void)keyDown:(NSEvent *)theEvent -{ - if (!_isStarted) - return; - - _eventHandler->keyDown(theEvent); -} - -- (void)flagsChanged:(NSEvent *)theEvent -{ - if (!_isStarted) - return; - - _eventHandler->flagsChanged(theEvent); -} - -- (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character -{ - if (!_isStarted) - return; - - _eventHandler->syntheticKeyDownWithCommandModifier(keyCode, character); -} - -- (void)privateBrowsingModeDidChange -{ - if (!_isStarted) - return; - - NPBool value = _isPrivateBrowsingEnabled; - - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); - if ([_pluginPackage.get() pluginFuncs]->setvalue) - [_pluginPackage.get() pluginFuncs]->setvalue(plugin, NPNVprivateModeBool, &value); - } - [self didCallPlugInFunction]; -} - -// MARK: WEB_NETSCAPE_PLUGIN - -- (BOOL)isNewWindowEqualToOldWindow -{ - if (window.x != lastSetWindow.x) - return NO; - if (window.y != lastSetWindow.y) - return NO; - if (window.width != lastSetWindow.width) - return NO; - if (window.height != lastSetWindow.height) - return NO; - if (window.clipRect.top != lastSetWindow.clipRect.top) - return NO; - if (window.clipRect.left != lastSetWindow.clipRect.left) - return NO; - if (window.clipRect.bottom != lastSetWindow.clipRect.bottom) - return NO; - if (window.clipRect.right != lastSetWindow.clipRect.right) - return NO; - if (window.type != lastSetWindow.type) - return NO; - - switch (drawingModel) { -#ifndef NP_NO_QUICKDRAW - case NPDrawingModelQuickDraw: - if (nPort.qdPort.portx != lastSetPort.qdPort.portx) - return NO; - if (nPort.qdPort.porty != lastSetPort.qdPort.porty) - return NO; - if (nPort.qdPort.port != lastSetPort.qdPort.port) - return NO; - break; -#endif /* NP_NO_QUICKDRAW */ - - case NPDrawingModelCoreGraphics: - if (nPort.cgPort.window != lastSetPort.cgPort.window) - return NO; - if (nPort.cgPort.context != lastSetPort.cgPort.context) - return NO; - break; - - case NPDrawingModelCoreAnimation: - if (window.window != lastSetWindow.window) - return NO; - break; - default: - ASSERT_NOT_REACHED(); - break; - } - - return YES; -} - --(void)tellQuickTimeToChill -{ -#ifndef NP_NO_QUICKDRAW - ASSERT(isDrawingModelQuickDraw(drawingModel)); - - // Make a call to the secret QuickDraw API that makes QuickTime calm down. - WindowRef windowRef = (WindowRef)[[self window] windowRef]; - if (!windowRef) { - return; - } - CGrafPtr port = GetWindowPort(windowRef); - ::Rect bounds; - GetPortBounds(port, &bounds); - WKCallDrawingNotification(port, &bounds); -#endif /* NP_NO_QUICKDRAW */ -} - -- (void)updateAndSetWindow -{ - // A plug-in can only update if it's (1) already been started (2) isn't stopped - // and (3) is able to draw on-screen. To meet condition (3) the plug-in must not - // be hidden and be attached to a window. There are two exceptions to this rule: - // - // Exception 1: QuickDraw plug-ins must be manually told when to stop writing - // bits to the window backing store, thus to do so requires a new call to - // NPP_SetWindow() with an empty NPWindow struct. - // - // Exception 2: CoreGraphics plug-ins expect to have their drawable area updated - // when they are moved to a background tab, via a NPP_SetWindow call. This is - // accomplished by allowing -saveAndSetNewPortStateForUpdate to "clip-out" the window's - // clipRect. Flash is curently an exception to this. See 6453738. - // - - if (!_isStarted) - return; - -#ifdef NP_NO_QUICKDRAW - if (![self canDraw]) - return; -#else - if (drawingModel == NPDrawingModelQuickDraw) - [self tellQuickTimeToChill]; - else if (drawingModel == NPDrawingModelCoreGraphics && ![self canDraw] && _isFlash) { - // The Flash plug-in does not expect an NPP_SetWindow call from WebKit in this case. - // See Exception 2 above. - return; - } -#endif // NP_NO_QUICKDRAW - - BOOL didLockFocus = [NSView focusView] != self && [self lockFocusIfCanDraw]; - - PortState portState = [self saveAndSetNewPortState]; - if (portState) { - [self setWindowIfNecessary]; - [self restorePortState:portState]; - if (portState != (PortState)1) - free(portState); - } else if (drawingModel == NPDrawingModelCoreGraphics) - [self setWindowIfNecessary]; - - if (didLockFocus) - [self unlockFocus]; -} - -- (void)setWindowIfNecessary -{ - if (!_isStarted) - return; - - if (![self isNewWindowEqualToOldWindow]) { - // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow. - // We probably don't want more general reentrancy protection; we are really - // protecting only against this one case, which actually comes up when - // you first install the SVG viewer plug-in. - NPError npErr; - ASSERT(!inSetWindow); - - inSetWindow = YES; - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); - npErr = [_pluginPackage.get() pluginFuncs]->setwindow(plugin, &window); - } - [self didCallPlugInFunction]; - inSetWindow = NO; - -#ifndef NDEBUG - switch (drawingModel) { -#ifndef NP_NO_QUICKDRAW - case NPDrawingModelQuickDraw: - LOG(Plugins, "NPP_SetWindow (QuickDraw): %d, port=0x%08x, window.x:%d window.y:%d window.width:%d window.height:%d", - npErr, (int)nPort.qdPort.port, (int)window.x, (int)window.y, (int)window.width, (int)window.height); - break; -#endif /* NP_NO_QUICKDRAW */ - - case NPDrawingModelCoreGraphics: - LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d", - npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height, - window.clipRect.right - window.clipRect.left, window.clipRect.bottom - window.clipRect.top); - break; - - case NPDrawingModelCoreAnimation: - LOG(Plugins, "NPP_SetWindow (CoreAnimation): %d, window=%p window.x:%d window.y:%d window.width:%d window.height:%d", - npErr, window.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height); - break; - - default: - ASSERT_NOT_REACHED(); - break; - } -#endif /* !defined(NDEBUG) */ - - lastSetWindow = window; - lastSetPort = nPort; - } -} - -+ (void)setCurrentPluginView:(WebNetscapePluginView *)view -{ - currentPluginView = view; -} - -+ (WebNetscapePluginView *)currentPluginView -{ - return currentPluginView; -} - -- (BOOL)createPlugin -{ - // Open the plug-in package so it remains loaded while our plugin uses it - [_pluginPackage.get() open]; - - // Initialize drawingModel to an invalid value so that we can detect when the plugin does not specify a drawingModel - drawingModel = (NPDrawingModel)-1; - - // Initialize eventModel to an invalid value so that we can detect when the plugin does not specify an event model. - eventModel = (NPEventModel)-1; - - NPError npErr = [self _createPlugin]; - if (npErr != NPERR_NO_ERROR) { - LOG_ERROR("NPP_New failed with error: %d", npErr); - [self _destroyPlugin]; - [_pluginPackage.get() close]; - return NO; - } - - if (drawingModel == (NPDrawingModel)-1) { -#ifndef NP_NO_QUICKDRAW - // Default to QuickDraw if the plugin did not specify a drawing model. - drawingModel = NPDrawingModelQuickDraw; -#else - // QuickDraw is not available, so we can't default to it. Instead, default to CoreGraphics. - drawingModel = NPDrawingModelCoreGraphics; -#endif - } - - if (eventModel == (NPEventModel)-1) { - // If the plug-in did not specify a drawing model we default to Carbon when it is available. -#ifndef NP_NO_CARBON - eventModel = NPEventModelCarbon; -#else - eventModel = NPEventModelCocoa; -#endif // NP_NO_CARBON - } - -#ifndef NP_NO_CARBON - if (eventModel == NPEventModelCocoa && isDrawingModelQuickDraw(drawingModel)) { - LOG(Plugins, "Plugin can't use use Cocoa event model with QuickDraw drawing model: %@", _pluginPackage.get()); - [self _destroyPlugin]; - [_pluginPackage.get() close]; - - return NO; - } -#endif // NP_NO_CARBON - -#ifndef BUILDING_ON_TIGER - if (drawingModel == NPDrawingModelCoreAnimation) { - void *value = 0; - if ([_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) { - - // The plug-in gives us a retained layer. - _pluginLayer.adoptNS((CALayer *)value); - - BOOL accleratedCompositingEnabled = false; -#if USE(ACCELERATED_COMPOSITING) - accleratedCompositingEnabled = [[[self webView] preferences] acceleratedCompositingEnabled]; -#endif - if (accleratedCompositingEnabled) { - // FIXME: This code can be shared between WebHostedNetscapePluginView and WebNetscapePluginView. -#ifndef BUILDING_ON_LEOPARD - // Since this layer isn't going to be inserted into a view, we need to create another layer and flip its geometry - // in order to get the coordinate system right. - RetainPtr<CALayer> realPluginLayer(AdoptNS, _pluginLayer.releaseRef()); - - _pluginLayer.adoptNS([[CALayer alloc] init]); - _pluginLayer.get().bounds = realPluginLayer.get().bounds; - _pluginLayer.get().geometryFlipped = YES; - - realPluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; - [_pluginLayer.get() addSublayer:realPluginLayer.get()]; -#endif - // Eagerly enter compositing mode, since we know we'll need it. This avoids firing setNeedsStyleRecalc() - // for iframes that contain composited plugins at bad times. https://bugs.webkit.org/show_bug.cgi?id=39033 - core([self webFrame])->view()->enterCompositingMode(); - [self element]->setNeedsStyleRecalc(SyntheticStyleChange); - } else - [self setWantsLayer:YES]; - - LOG(Plugins, "%@ is using Core Animation drawing model with layer %@", _pluginPackage.get(), _pluginLayer.get()); - } - - ASSERT(_pluginLayer); - } -#endif - - // Create the event handler - _eventHandler.set(WebNetscapePluginEventHandler::create(self)); - - return YES; -} - -#ifndef BUILDING_ON_TIGER -// FIXME: This method is an ideal candidate to move up to the base class -- (CALayer *)pluginLayer -{ - return _pluginLayer.get(); -} - -- (void)setLayer:(CALayer *)newLayer -{ - [super setLayer:newLayer]; - - if (newLayer && _pluginLayer) { - _pluginLayer.get().frame = [newLayer frame]; - _pluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; - [newLayer addSublayer:_pluginLayer.get()]; - } -} -#endif - -- (void)loadStream -{ - if ([self _shouldCancelSrcStream]) - return; - - if (_loadManually) { - [self _redeliverStream]; - return; - } - - // If the OBJECT/EMBED tag has no SRC, the URL is passed to us as "". - // Check for this and don't start a load in this case. - if (_sourceURL && ![_sourceURL.get() _web_isEmpty]) { - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_sourceURL.get()]; - [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()]; - [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO]; - } -} - -- (BOOL)shouldStop -{ - // If we're already calling a plug-in function, do not call NPP_Destroy(). The plug-in function we are calling - // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said - // plugin-function returns. - // See <rdar://problem/4480737>. - if (pluginFunctionCallDepth > 0) { - shouldStopSoon = YES; - return NO; - } - - return YES; -} - -- (void)destroyPlugin -{ - // To stop active streams it's necessary to invoke stop() on a copy - // of streams. This is because calling WebNetscapePluginStream::stop() also has the side effect - // of removing a stream from this hash set. - Vector<RefPtr<WebNetscapePluginStream> > streamsCopy; - copyToVector(streams, streamsCopy); - for (size_t i = 0; i < streamsCopy.size(); i++) - streamsCopy[i]->stop(); - - [[_pendingFrameLoads.get() allKeys] makeObjectsPerformSelector:@selector(_setInternalLoadDelegate:) withObject:nil]; - [NSObject cancelPreviousPerformRequestsWithTarget:self]; - - // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted. - lastSetWindow.type = (NPWindowType)0; - -#ifndef BUILDING_ON_TIGER - _pluginLayer = 0; -#endif - - [self _destroyPlugin]; - [_pluginPackage.get() close]; - - _eventHandler.clear(); -} - -- (NPEventModel)eventModel -{ - return eventModel; -} - -- (NPP)plugin -{ - return plugin; -} - -- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values -{ - ASSERT([keys count] == [values count]); - - // Convert the attributes to 2 C string arrays. - // These arrays are passed to NPP_New, but the strings need to be - // modifiable and live the entire life of the plugin. - - // The Java plug-in requires the first argument to be the base URL - if ([_MIMEType.get() isEqualToString:@"application/x-java-applet"]) { - cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *)); - cValues = (char **)malloc(([values count] + 1) * sizeof(char *)); - cAttributes[0] = strdup("DOCBASE"); - cValues[0] = strdup([_baseURL.get() _web_URLCString]); - argsCount++; - } else { - cAttributes = (char **)malloc([keys count] * sizeof(char *)); - cValues = (char **)malloc([values count] * sizeof(char *)); - } - - BOOL isWMP = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.WMP.defaultplugin"; - - unsigned i; - unsigned count = [keys count]; - for (i = 0; i < count; i++) { - NSString *key = [keys objectAtIndex:i]; - NSString *value = [values objectAtIndex:i]; - if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) { - specifiedHeight = [value intValue]; - } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) { - specifiedWidth = [value intValue]; - } - // Avoid Window Media Player crash when these attributes are present. - if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) { - continue; - } - cAttributes[argsCount] = strdup([key UTF8String]); - cValues[argsCount] = strdup([value UTF8String]); - LOG(Plugins, "%@ = %@", key, value); - argsCount++; - } -} - -- (uint32_t)checkIfAllowedToLoadURL:(const char*)urlCString frame:(const char*)frameNameCString - callbackFunc:(void (*)(NPP npp, uint32_t checkID, NPBool allowed, void* context))callbackFunc - context:(void*)context -{ - if (!_containerChecksInProgress) - _containerChecksInProgress = [[NSMutableDictionary alloc] init]; - - NSString *frameName = frameNameCString ? [NSString stringWithCString:frameNameCString encoding:NSISOLatin1StringEncoding] : nil; - - ++_currentContainerCheckRequestID; - WebNetscapeContainerCheckContextInfo *contextInfo = [[WebNetscapeContainerCheckContextInfo alloc] initWithCheckRequestID:_currentContainerCheckRequestID - callbackFunc:callbackFunc - context:context]; - - WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[self requestWithURLCString:urlCString] - target:frameName - resultObject:self - selector:@selector(_containerCheckResult:contextInfo:) - controller:self - contextInfo:contextInfo]; - - [contextInfo release]; - [_containerChecksInProgress setObject:check forKey:[NSNumber numberWithInt:_currentContainerCheckRequestID]]; - [check start]; - - return _currentContainerCheckRequestID; -} - -- (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo -{ - ASSERT([contextInfo isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]); - void (*pluginCallback)(NPP npp, uint32_t, NPBool, void*) = [contextInfo callback]; - - if (!pluginCallback) { - ASSERT_NOT_REACHED(); - return; - } - - pluginCallback([self plugin], [contextInfo checkRequestID], (policy == PolicyUse), [contextInfo context]); -} - -- (void)cancelCheckIfAllowedToLoadURL:(uint32_t)checkID -{ - WebPluginContainerCheck *check = (WebPluginContainerCheck *)[_containerChecksInProgress objectForKey:[NSNumber numberWithInt:checkID]]; - - if (!check) - return; - - [check cancel]; - [_containerChecksInProgress removeObjectForKey:[NSNumber numberWithInt:checkID]]; -} - -// WebPluginContainerCheck automatically calls this method after invoking our _containerCheckResult: selector. -// It works this way because calling -[WebPluginContainerCheck cancel] allows it to do it's teardown process. -- (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck -{ - ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]); - WebPluginContainerCheck *check = (WebPluginContainerCheck *)webPluginContainerCheck; - ASSERT([[check contextInfo] isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]); - - [self cancelCheckIfAllowedToLoadURL:[[check contextInfo] checkRequestID]]; -} - -#ifdef BUILDING_ON_TIGER -// The Tiger compiler requires these two methods be present. Otherwise it doesn't think WebNetscapePluginView -// conforms to the WebPluginContainerCheckController protocol. -- (WebView *)webView -{ - return [super webView]; -} - -- (WebFrame *)webFrame -{ - return [super webFrame]; -} -#endif - -// MARK: NSVIEW - -- (id)initWithFrame:(NSRect)frame - pluginPackage:(WebNetscapePluginPackage *)pluginPackage - URL:(NSURL *)URL - baseURL:(NSURL *)baseURL - MIMEType:(NSString *)MIME - attributeKeys:(NSArray *)keys - attributeValues:(NSArray *)values - loadManually:(BOOL)loadManually - element:(PassRefPtr<WebCore::HTMLPlugInElement>)element -{ - self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element]; - if (!self) - return nil; - - _pendingFrameLoads.adoptNS([[NSMutableDictionary alloc] init]); - - // load the plug-in if it is not already loaded - if (![pluginPackage load]) { - [self release]; - return nil; - } - - return self; -} - -- (id)initWithFrame:(NSRect)frame -{ - ASSERT_NOT_REACHED(); - return nil; -} - -- (void)fini -{ -#ifndef NP_NO_QUICKDRAW - if (offscreenGWorld) - DisposeGWorld(offscreenGWorld); -#endif - - for (unsigned i = 0; i < argsCount; i++) { - free(cAttributes[i]); - free(cValues[i]); - } - free(cAttributes); - free(cValues); - - ASSERT(!_eventHandler); - - if (timers) { - deleteAllValues(*timers); - delete timers; - } - - [_containerChecksInProgress release]; -} - -- (void)disconnectStream:(WebNetscapePluginStream*)stream -{ - streams.remove(stream); -} - -- (void)dealloc -{ - ASSERT(!_isStarted); - ASSERT(!plugin); - - [self fini]; - - [super dealloc]; -} - -- (void)finalize -{ - ASSERT_MAIN_THREAD(); - ASSERT(!_isStarted); - - [self fini]; - - [super finalize]; -} - -- (void)drawRect:(NSRect)rect -{ - if (_cachedSnapshot) { - NSRect sourceRect = { NSZeroPoint, [_cachedSnapshot.get() size] }; - [_cachedSnapshot.get() drawInRect:[self bounds] fromRect:sourceRect operation:NSCompositeSourceOver fraction:1]; - return; - } - - if (drawingModel == NPDrawingModelCoreAnimation && (!_snapshotting || ![self supportsSnapshotting])) - return; - - if (!_isStarted) - return; - - if ([NSGraphicsContext currentContextDrawingToScreen] || _isFlash) - [self sendDrawRectEvent:rect]; - else { - NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap]; - if (printedPluginBitmap) { - // Flip the bitmap before drawing because the QuickDraw port is flipped relative - // to this view. - CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - CGContextSaveGState(cgContext); - NSRect bounds = [self bounds]; - CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds)); - CGContextScaleCTM(cgContext, 1.0f, -1.0f); - [printedPluginBitmap drawInRect:bounds]; - CGContextRestoreGState(cgContext); - } - } -} - -- (NPObject *)createPluginScriptableObject -{ - if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted) - return NULL; - - NPObject *value = NULL; - NPError error; - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); - error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginScriptableNPObject, &value); - } - [self didCallPlugInFunction]; - if (error != NPERR_NO_ERROR) - return NULL; - - return value; -} - -- (void)willCallPlugInFunction -{ - ASSERT(plugin); - - // Could try to prevent infinite recursion here, but it's probably not worth the effort. - pluginFunctionCallDepth++; -} - -- (void)didCallPlugInFunction -{ - ASSERT(pluginFunctionCallDepth > 0); - pluginFunctionCallDepth--; - - // If -stop was called while we were calling into a plug-in function, and we're no longer - // inside a plug-in function, stop now. - if (pluginFunctionCallDepth == 0 && shouldStopSoon) { - shouldStopSoon = NO; - [self stop]; - } -} - --(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response -{ - ASSERT(_loadManually); - ASSERT(!_manualStream); - - _manualStream = WebNetscapePluginStream::create(core([self webFrame])->loader()); -} - -- (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data -{ - ASSERT(_loadManually); - ASSERT(_manualStream); - - _dataLengthReceived += [data length]; - - if (!_isStarted) - return; - - if (!_manualStream->plugin()) { - // Check if the load should be cancelled - if ([self _shouldCancelSrcStream]) { - NSURLResponse *response = [[self dataSource] response]; - - NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad - contentURL:[response URL] - pluginPageURL:nil - pluginName:nil // FIXME: Get this from somewhere - MIMEType:[response MIMEType]]; - [[self dataSource] _documentLoader]->cancelMainResourceLoad(error); - [error release]; - return; - } - - _manualStream->setRequestURL([[[self dataSource] request] URL]); - _manualStream->setPlugin([self plugin]); - ASSERT(_manualStream->plugin()); - - _manualStream->startStreamWithResponse([[self dataSource] response]); - } - - if (_manualStream->plugin()) - _manualStream->didReceiveData(0, static_cast<const char *>([data bytes]), [data length]); -} - -- (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error -{ - ASSERT(_loadManually); - - _error = error; - - if (!_isStarted) { - return; - } - - _manualStream->destroyStreamWithError(error); -} - -- (void)pluginViewFinishedLoading:(NSView *)pluginView -{ - ASSERT(_loadManually); - ASSERT(_manualStream); - - if (_isStarted) - _manualStream->didFinishLoading(0); -} - -- (NSTextInputContext *)inputContext -{ - return nil; -} - -@end - -@implementation WebNetscapePluginView (WebNPPCallbacks) - -- (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest -{ - // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called - // if we are stopped since this method is called after a delay and we call - // cancelPreviousPerformRequestsWithTarget inside of stop. - if (!_isStarted) { - return; - } - - NSURL *URL = [[JSPluginRequest request] URL]; - NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; - ASSERT(JSString); - - NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]]; - - // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop. - if (!_isStarted) { - return; - } - - if ([JSPluginRequest frameName] != nil) { - // FIXME: If the result is a string, we probably want to put that string into the frame. - if ([JSPluginRequest sendNotification]) { - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); - [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]); - } - [self didCallPlugInFunction]; - } - } else if ([result length] > 0) { - // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does. - NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding]; - - RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create([NSURLRequest requestWithURL:URL], plugin, [JSPluginRequest sendNotification], [JSPluginRequest notifyData]); - - RetainPtr<NSURLResponse> response(AdoptNS, [[NSURLResponse alloc] initWithURL:URL - MIMEType:@"text/plain" - expectedContentLength:[JSData length] - textEncodingName:nil]); - - stream->startStreamWithResponse(response.get()); - stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]); - stream->didFinishLoading(0); - } -} - -- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason -{ - ASSERT(_isStarted); - - WebPluginRequest *pluginRequest = [_pendingFrameLoads.get() objectForKey:webFrame]; - ASSERT(pluginRequest != nil); - ASSERT([pluginRequest sendNotification]); - - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); - [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]); - } - [self didCallPlugInFunction]; - - [_pendingFrameLoads.get() removeObjectForKey:webFrame]; - [webFrame _setInternalLoadDelegate:nil]; -} - -- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error -{ - NPReason reason = NPRES_DONE; - if (error != nil) - reason = WebNetscapePluginStream::reasonForError(error); - [self webFrame:webFrame didFinishLoadWithReason:reason]; -} - -- (void)loadPluginRequest:(WebPluginRequest *)pluginRequest -{ - NSURLRequest *request = [pluginRequest request]; - NSString *frameName = [pluginRequest frameName]; - WebFrame *frame = nil; - - NSURL *URL = [request URL]; - NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; - - ASSERT(frameName || JSString); - - if (frameName) { - // FIXME - need to get rid of this window creation which - // bypasses normal targeted link handling - frame = kit(core([self webFrame])->loader()->findFrameForNavigation(frameName)); - if (frame == nil) { - WebView *currentWebView = [self webView]; - NSDictionary *features = [[NSDictionary alloc] init]; - WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView - createWebViewWithRequest:nil - windowFeatures:features]; - [features release]; - - if (!newWebView) { - if ([pluginRequest sendNotification]) { - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); - [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]); - } - [self didCallPlugInFunction]; - } - return; - } - - frame = [newWebView mainFrame]; - core(frame)->tree()->setName(frameName); - [[newWebView _UIDelegateForwarder] webViewShow:newWebView]; - } - } - - if (JSString) { - ASSERT(frame == nil || [self webFrame] == frame); - [self evaluateJavaScriptPluginRequest:pluginRequest]; - } else { - [frame loadRequest:request]; - if ([pluginRequest sendNotification]) { - // Check if another plug-in view or even this view is waiting for the frame to load. - // If it is, tell it that the load was cancelled because it will be anyway. - WebNetscapePluginView *view = [frame _internalLoadDelegate]; - if (view != nil) { - ASSERT([view isKindOfClass:[WebNetscapePluginView class]]); - [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK]; - } - [_pendingFrameLoads.get() _webkit_setObject:pluginRequest forUncopiedKey:frame]; - [frame _setInternalLoadDelegate:self]; - } - } -} - -- (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification -{ - NSURL *URL = [request URL]; - - if (!URL) - return NPERR_INVALID_URL; - - // Don't allow requests to be loaded when the document loader is stopping all loaders. - if ([[self dataSource] _documentLoader]->isStopping()) - return NPERR_GENERIC_ERROR; - - NSString *target = nil; - if (cTarget) { - // Find the frame given the target string. - target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding]; - } - WebFrame *frame = [self webFrame]; - - // don't let a plugin start any loads if it is no longer part of a document that is being - // displayed unless the loads are in the same frame as the plugin. - if ([[self dataSource] _documentLoader] != core([self webFrame])->loader()->activeDocumentLoader() && - (!cTarget || [frame findFrameNamed:target] != frame)) { - return NPERR_GENERIC_ERROR; - } - - NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; - if (JSString != nil) { - if (![[[self webView] preferences] isJavaScriptEnabled]) { - // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does. - return NPERR_GENERIC_ERROR; - } else if (cTarget == NULL && _mode == NP_FULL) { - // Don't allow a JavaScript request from a standalone plug-in that is self-targetted - // because this can cause the user to be redirected to a blank page (3424039). - return NPERR_INVALID_PARAM; - } - } else { - if (!core([self webFrame])->document()->securityOrigin()->canDisplay(URL)) - return NPERR_GENERIC_ERROR; - } - - if (cTarget || JSString) { - // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't - // want to potentially kill the plug-in inside of its URL request. - - if (JSString && target && [frame findFrameNamed:target] != frame) { - // For security reasons, only allow JS requests to be made on the frame that contains the plug-in. - return NPERR_INVALID_PARAM; - } - - bool currentEventIsUserGesture = false; - if (_eventHandler) - currentEventIsUserGesture = _eventHandler->currentEventIsUserGesture(); - - WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request - frameName:target - notifyData:notifyData - sendNotification:sendNotification - didStartFromUserGesture:currentEventIsUserGesture]; - [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0]; - [pluginRequest release]; - } else { - RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create(request, plugin, sendNotification, notifyData); - - streams.add(stream.get()); - stream->start(); - } - - return NPERR_NO_ERROR; -} - --(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData -{ - LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget); - - NSMutableURLRequest *request = [self requestWithURLCString:URLCString]; - return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES]; -} - --(NPError)getURL:(const char *)URLCString target:(const char *)cTarget -{ - LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget); - - NSMutableURLRequest *request = [self requestWithURLCString:URLCString]; - return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO]; -} - -- (NPError)_postURL:(const char *)URLCString - target:(const char *)target - len:(UInt32)len - buf:(const char *)buf - file:(NPBool)file - notifyData:(void *)notifyData - sendNotification:(BOOL)sendNotification - allowHeaders:(BOOL)allowHeaders -{ - if (!URLCString || !len || !buf) { - return NPERR_INVALID_PARAM; - } - - NSData *postData = nil; - - if (file) { - // If we're posting a file, buf is either a file URL or a path to the file. - NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1); - if (!bufString) { - return NPERR_INVALID_PARAM; - } - NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString]; - NSString *path; - if ([fileURL isFileURL]) { - path = [fileURL path]; - } else { - path = bufString; - } - postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]]; - CFRelease(bufString); - if (!postData) { - return NPERR_FILE_NOT_FOUND; - } - } else { - postData = [NSData dataWithBytes:buf length:len]; - } - - if ([postData length] == 0) { - return NPERR_INVALID_PARAM; - } - - NSMutableURLRequest *request = [self requestWithURLCString:URLCString]; - [request setHTTPMethod:@"POST"]; - - if (allowHeaders) { - if ([postData _web_startsWithBlankLine]) { - postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)]; - } else { - NSInteger location = [postData _web_locationAfterFirstBlankLine]; - if (location != NSNotFound) { - // If the blank line is somewhere in the middle of postData, everything before is the header. - NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)]; - NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields]; - unsigned dataLength = [postData length] - location; - - // Sometimes plugins like to set Content-Length themselves when they post, - // but WebFoundation does not like that. So we will remove the header - // and instead truncate the data to the requested length. - NSString *contentLength = [header objectForKey:@"Content-Length"]; - - if (contentLength != nil) - dataLength = min<unsigned>([contentLength intValue], dataLength); - [header removeObjectForKey:@"Content-Length"]; - - if ([header count] > 0) { - [request setAllHTTPHeaderFields:header]; - } - // Everything after the blank line is the actual content of the POST. - postData = [postData subdataWithRange:NSMakeRange(location, dataLength)]; - - } - } - if ([postData length] == 0) { - return NPERR_INVALID_PARAM; - } - } - - // Plug-ins expect to receive uncached data when doing a POST (3347134). - [request setCachePolicy:NSURLRequestReloadIgnoringCacheData]; - [request setHTTPBody:postData]; - - return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification]; -} - -- (NPError)postURLNotify:(const char *)URLCString - target:(const char *)target - len:(UInt32)len - buf:(const char *)buf - file:(NPBool)file - notifyData:(void *)notifyData -{ - LOG(Plugins, "NPN_PostURLNotify: %s", URLCString); - return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES]; -} - --(NPError)postURL:(const char *)URLCString - target:(const char *)target - len:(UInt32)len - buf:(const char *)buf - file:(NPBool)file -{ - LOG(Plugins, "NPN_PostURL: %s", URLCString); - // As documented, only allow headers to be specified via NPP_PostURL when using a file. - return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file]; -} - --(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream -{ - LOG(Plugins, "NPN_NewStream"); - return NPERR_GENERIC_ERROR; -} - --(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer -{ - LOG(Plugins, "NPN_Write"); - return NPERR_GENERIC_ERROR; -} - --(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason -{ - LOG(Plugins, "NPN_DestroyStream"); - // This function does a sanity check to ensure that the NPStream provided actually - // belongs to the plug-in that provided it, which fixes a crash in the DivX - // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203 - if (!stream || WebNetscapePluginStream::ownerForStream(stream) != plugin) { - LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream); - return NPERR_INVALID_INSTANCE_ERROR; - } - - WebNetscapePluginStream* browserStream = static_cast<WebNetscapePluginStream*>(stream->ndata); - browserStream->cancelLoadAndDestroyStreamWithError(browserStream->errorForReason(reason)); - - return NPERR_NO_ERROR; -} - -- (const char *)userAgent -{ - NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()]; - - if (_isSilverlight) { - // Silverlight has a workaround for a leak in Safari 2. This workaround is - // applied when the user agent does not contain "Version/3" so we append it - // at the end of the user agent. - userAgent = [userAgent stringByAppendingString:@" Version/3.2.1"]; - } - - return [userAgent UTF8String]; -} - --(void)status:(const char *)message -{ - CFStringRef status = CFStringCreateWithCString(NULL, message ? message : "", kCFStringEncodingUTF8); - if (!status) { - LOG_ERROR("NPN_Status: the message was not valid UTF-8"); - return; - } - - LOG(Plugins, "NPN_Status: %@", status); - WebView *wv = [self webView]; - [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status]; - CFRelease(status); -} - --(void)invalidateRect:(NPRect *)invalidRect -{ - LOG(Plugins, "NPN_InvalidateRect"); - [self invalidatePluginContentRect:NSMakeRect(invalidRect->left, invalidRect->top, - (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)]; -} - -- (void)invalidateRegion:(NPRegion)invalidRegion -{ - LOG(Plugins, "NPN_InvalidateRegion"); - NSRect invalidRect = NSZeroRect; - switch (drawingModel) { -#ifndef NP_NO_QUICKDRAW - case NPDrawingModelQuickDraw: - { - ::Rect qdRect; - GetRegionBounds((NPQDRegion)invalidRegion, &qdRect); - invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top); - } - break; -#endif /* NP_NO_QUICKDRAW */ - - case NPDrawingModelCoreGraphics: - { - CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion); - invalidRect = *(NSRect*)&cgRect; - break; - } - default: - ASSERT_NOT_REACHED(); - break; - } - - [self invalidatePluginContentRect:invalidRect]; -} - --(void)forceRedraw -{ - LOG(Plugins, "forceRedraw"); - [self invalidatePluginContentRect:[self bounds]]; - [[self window] displayIfNeeded]; -} - -- (NPError)getVariable:(NPNVariable)variable value:(void *)value -{ - switch (variable) { - case NPNVWindowNPObject: - { - Frame* frame = core([self webFrame]); - NPObject* windowScriptObject = frame ? frame->script()->windowScriptNPObject() : 0; - - // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess> - if (windowScriptObject) - _NPN_RetainObject(windowScriptObject); - - void **v = (void **)value; - *v = windowScriptObject; - - return NPERR_NO_ERROR; - } - - case NPNVPluginElementNPObject: - { - if (!_element) - return NPERR_GENERIC_ERROR; - - NPObject *plugInScriptObject = _element->getNPObject(); - - // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess> - if (plugInScriptObject) - _NPN_RetainObject(plugInScriptObject); - - void **v = (void **)value; - *v = plugInScriptObject; - - return NPERR_NO_ERROR; - } - - case NPNVpluginDrawingModel: - { - *(NPDrawingModel *)value = drawingModel; - return NPERR_NO_ERROR; - } - -#ifndef NP_NO_QUICKDRAW - case NPNVsupportsQuickDrawBool: - { - *(NPBool *)value = TRUE; - return NPERR_NO_ERROR; - } -#endif /* NP_NO_QUICKDRAW */ - - case NPNVsupportsCoreGraphicsBool: - { - *(NPBool *)value = TRUE; - return NPERR_NO_ERROR; - } - - case NPNVsupportsOpenGLBool: - { - *(NPBool *)value = FALSE; - return NPERR_NO_ERROR; - } - - case NPNVsupportsCoreAnimationBool: - { -#ifdef BUILDING_ON_TIGER - *(NPBool *)value = FALSE; -#else - *(NPBool *)value = TRUE; -#endif - return NPERR_NO_ERROR; - } - -#ifndef NP_NO_CARBON - case NPNVsupportsCarbonBool: - { - *(NPBool *)value = TRUE; - return NPERR_NO_ERROR; - } -#endif /* NP_NO_CARBON */ - - case NPNVsupportsCocoaBool: - { - *(NPBool *)value = TRUE; - return NPERR_NO_ERROR; - } - - case NPNVprivateModeBool: - { - *(NPBool *)value = _isPrivateBrowsingEnabled; - return NPERR_NO_ERROR; - } - - case WKNVBrowserContainerCheckFuncs: - { - *(WKNBrowserContainerCheckFuncs **)value = browserContainerCheckFuncs(); - return NPERR_NO_ERROR; - } -#if USE(ACCELERATED_COMPOSITING) - case WKNVSupportsCompositingCoreAnimationPluginsBool: - { - *(NPBool *)value = [[[self webView] preferences] acceleratedCompositingEnabled]; - return NPERR_NO_ERROR; - } -#endif - default: - break; - } - - return NPERR_GENERIC_ERROR; -} - -- (NPError)setVariable:(NPPVariable)variable value:(void *)value -{ - switch (variable) { - case NPPVpluginDrawingModel: - { - // Can only set drawing model inside NPP_New() - if (self != [[self class] currentPluginView]) - return NPERR_GENERIC_ERROR; - - // Check for valid, supported drawing model - NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value; - switch (newDrawingModel) { - // Supported drawing models: -#ifndef NP_NO_QUICKDRAW - case NPDrawingModelQuickDraw: -#endif - case NPDrawingModelCoreGraphics: -#ifndef BUILDING_ON_TIGER - case NPDrawingModelCoreAnimation: -#endif - drawingModel = newDrawingModel; - return NPERR_NO_ERROR; - - - // Unsupported (or unknown) drawing models: - default: - LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", _eventHandler.get(), drawingModel); - return NPERR_GENERIC_ERROR; - } - } - - case NPPVpluginEventModel: - { - // Can only set event model inside NPP_New() - if (self != [[self class] currentPluginView]) - return NPERR_GENERIC_ERROR; - - // Check for valid, supported event model - NPEventModel newEventModel = (NPEventModel)(uintptr_t)value; - switch (newEventModel) { - // Supported event models: -#ifndef NP_NO_CARBON - case NPEventModelCarbon: -#endif - case NPEventModelCocoa: - eventModel = newEventModel; - return NPERR_NO_ERROR; - - // Unsupported (or unknown) event models: - default: - LOG(Plugins, "Plugin %@ uses unsupported event model: %d", _eventHandler.get(), eventModel); - return NPERR_GENERIC_ERROR; - } - } - - default: - return NPERR_GENERIC_ERROR; - } -} - -- (uint32_t)scheduleTimerWithInterval:(uint32_t)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32_t timerID))timerFunc -{ - if (!timerFunc) - return 0; - - if (!timers) - timers = new HashMap<uint32_t, PluginTimer*>; - - uint32_t timerID; - - do { - timerID = ++currentTimerID; - } while (timers->contains(timerID) || timerID == 0); - - PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc); - timers->set(timerID, timer); - - if (_shouldFireTimers) - timer->start(_isCompletelyObscured); - - return timerID; -} - -- (void)unscheduleTimer:(uint32_t)timerID -{ - if (!timers) - return; - - if (PluginTimer* timer = timers->take(timerID)) - delete timer; -} - -- (NPError)popUpContextMenu:(NPMenu *)menu -{ - NSEvent *currentEvent = [NSApp currentEvent]; - - // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent. - if (!currentEvent) - return NPERR_GENERIC_ERROR; - - [NSMenu popUpContextMenu:(NSMenu *)menu withEvent:currentEvent forView:self]; - return NPERR_NO_ERROR; -} - -- (NPError)getVariable:(NPNURLVariable)variable forURL:(const char*)url value:(char**)value length:(uint32_t*)length -{ - switch (variable) { - case NPNURLVCookie: { - if (!value) - break; - - NSURL *URL = [self URLWithCString:url]; - if (!URL) - break; - - if (Frame* frame = core([self webFrame])) { - String cookieString = cookies(frame->document(), URL); - CString cookieStringUTF8 = cookieString.utf8(); - if (cookieStringUTF8.isNull()) - return NPERR_GENERIC_ERROR; - - *value = static_cast<char*>(NPN_MemAlloc(cookieStringUTF8.length())); - memcpy(*value, cookieStringUTF8.data(), cookieStringUTF8.length()); - - if (length) - *length = cookieStringUTF8.length(); - return NPERR_NO_ERROR; - } - break; - } - case NPNURLVProxy: { -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - if (!value) - break; - - NSURL *URL = [self URLWithCString:url]; - if (!URL) - break; - - Vector<ProxyServer> proxyServers = proxyServersForURL(URL, 0); - CString proxiesUTF8 = toString(proxyServers).utf8(); - - *value = static_cast<char*>(NPN_MemAlloc(proxiesUTF8.length())); - memcpy(*value, proxiesUTF8.data(), proxiesUTF8.length()); - - if (length) - *length = proxiesUTF8.length(); - - return NPERR_NO_ERROR; -#else - break; -#endif - } - } - return NPERR_GENERIC_ERROR; -} - -- (NPError)setVariable:(NPNURLVariable)variable forURL:(const char*)url value:(const char*)value length:(uint32_t)length -{ - switch (variable) { - case NPNURLVCookie: { - NSURL *URL = [self URLWithCString:url]; - if (!URL) - break; - - String cookieString = String::fromUTF8(value, length); - if (!cookieString) - break; - - if (Frame* frame = core([self webFrame])) { - setCookies(frame->document(), URL, cookieString); - return NPERR_NO_ERROR; - } - - break; - } - case NPNURLVProxy: - // Can't set the proxy for a URL. - break; - } - return NPERR_GENERIC_ERROR; -} - -- (NPError)getAuthenticationInfoWithProtocol:(const char*)protocolStr host:(const char*)hostStr port:(int32_t)port scheme:(const char*)schemeStr realm:(const char*)realmStr - username:(char**)usernameStr usernameLength:(uint32_t*)usernameLength - password:(char**)passwordStr passwordLength:(uint32_t*)passwordLength -{ - if (!protocolStr || !hostStr || !schemeStr || !realmStr || !usernameStr || !usernameLength || !passwordStr || !passwordLength) - return NPERR_GENERIC_ERROR; - - CString username; - CString password; - if (!getAuthenticationInfo(protocolStr, hostStr, port, schemeStr, realmStr, username, password)) - return NPERR_GENERIC_ERROR; - - *usernameLength = username.length(); - *usernameStr = static_cast<char*>(NPN_MemAlloc(username.length())); - memcpy(*usernameStr, username.data(), username.length()); - - *passwordLength = password.length(); - *passwordStr = static_cast<char*>(NPN_MemAlloc(password.length())); - memcpy(*passwordStr, password.data(), password.length()); - - return NPERR_NO_ERROR; -} - -- (char*)resolveURL:(const char*)url forTarget:(const char*)target -{ - CString location = [self resolvedURLStringForURL:url target:target]; - - if (location.isNull()) - return 0; - - // We use strdup here because the caller needs to free it with NPN_MemFree (which calls free). - return strdup(location.data()); -} - -@end - -@implementation WebNetscapePluginView (Internal) - -- (BOOL)_shouldCancelSrcStream -{ - ASSERT(_isStarted); - - // Check if we should cancel the load - NPBool cancelSrcStream = 0; - if ([_pluginPackage.get() pluginFuncs]->getvalue && - [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCancelSrcStream, &cancelSrcStream) == NPERR_NO_ERROR && cancelSrcStream) - return YES; - - return NO; -} - -// Work around Silverlight full screen performance issue by maintaining an accelerated GL pixel format. -// We can safely remove it at some point in the future when both: -// 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 -{ -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - ASSERT(_isSilverlight); - NPBool isFullscreenPerformanceIssueFixed = 0; - NPPluginFuncs *pluginFuncs = [_pluginPackage.get() pluginFuncs]; - if (pluginFuncs->getvalue && pluginFuncs->getvalue(plugin, static_cast<NPPVariable>(WKNVSilverlightFullscreenPerformanceIssueFixed), &isFullscreenPerformanceIssueFixed) == NPERR_NO_ERROR && isFullscreenPerformanceIssueFixed) - return; - - static CGLPixelFormatObj pixelFormatObject = 0; - static unsigned refCount = 0; - - if (initializedPlugin) { - refCount++; - if (refCount == 1) { - const CGLPixelFormatAttribute attributes[] = { kCGLPFAAccelerated, static_cast<CGLPixelFormatAttribute>(0) }; - GLint npix; - CGLChoosePixelFormat(attributes, &pixelFormatObject, &npix); - } - } else { - ASSERT(pixelFormatObject); - refCount--; - if (!refCount) - CGLReleasePixelFormat(pixelFormatObject); - } -#endif -} - -- (NPError)_createPlugin -{ - plugin = (NPP)calloc(1, sizeof(NPP_t)); - plugin->ndata = self; - - ASSERT([_pluginPackage.get() pluginFuncs]->newp); - - // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance. - ASSERT(pluginFunctionCallDepth == 0); - - PluginMainThreadScheduler::scheduler().registerPlugin(plugin); - - _isFlash = [_pluginPackage.get() bundleIdentifier] == "com.macromedia.Flash Player.plugin"; - _isSilverlight = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.SilverlightPlugin"; - - [[self class] setCurrentPluginView:self]; - 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]; - LOG(Plugins, "NPP_New: %d", npErr); - return npErr; -} - -- (void)_destroyPlugin -{ - PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin); - - if (_isSilverlight) - [self _workaroundSilverlightFullscreenBug:NO]; - - NPError npErr; - npErr = ![_pluginPackage.get() pluginFuncs]->destroy(plugin, NULL); - LOG(Plugins, "NPP_Destroy: %d", npErr); - - if (Frame* frame = core([self webFrame])) - frame->script()->cleanupScriptObjectsForPlugin(self); - - free(plugin); - plugin = NULL; -} - -- (NSBitmapImageRep *)_printedPluginBitmap -{ -#ifdef NP_NO_QUICKDRAW - return nil; -#else - // Cannot print plugins that do not implement NPP_Print - if (![_pluginPackage.get() pluginFuncs]->print) - return nil; - - // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into. - // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format. - NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:window.width - pixelsHigh:window.height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:NSAlphaFirstBitmapFormat - bytesPerRow:0 - bitsPerPixel:0] autorelease]; - ASSERT(bitmap); - - // Create a GWorld with the same underlying buffer into which the plugin can draw - ::Rect printGWorldBounds; - SetRect(&printGWorldBounds, 0, 0, window.width, window.height); - GWorldPtr printGWorld; - if (NewGWorldFromPtr(&printGWorld, - k32ARGBPixelFormat, - &printGWorldBounds, - NULL, - NULL, - 0, - (Ptr)[bitmap bitmapData], - [bitmap bytesPerRow]) != noErr) { - LOG_ERROR("Could not create GWorld for printing"); - return nil; - } - - /// Create NPWindow for the GWorld - NPWindow printNPWindow; - printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr - printNPWindow.x = 0; - printNPWindow.y = 0; - printNPWindow.width = window.width; - printNPWindow.height = window.height; - printNPWindow.clipRect.top = 0; - printNPWindow.clipRect.left = 0; - printNPWindow.clipRect.right = window.width; - printNPWindow.clipRect.bottom = window.height; - printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window - - // Create embed-mode NPPrint - NPPrint npPrint; - npPrint.mode = NP_EMBED; - npPrint.print.embedPrint.window = printNPWindow; - npPrint.print.embedPrint.platformPrint = printGWorld; - - // Tell the plugin to print into the GWorld - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); - [_pluginPackage.get() pluginFuncs]->print(plugin, &npPrint); - } - [self didCallPlugInFunction]; - - // Don't need the GWorld anymore - DisposeGWorld(printGWorld); - - return bitmap; -#endif -} - -- (void)_redeliverStream -{ - if ([self dataSource] && _isStarted) { - // Deliver what has not been passed to the plug-in up to this point. - if (_dataLengthReceived > 0) { - NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)]; - _dataLengthReceived = 0; - [self pluginView:self receivedData:data]; - if (![[self dataSource] isLoading]) { - if (_error) - [self pluginView:self receivedError:_error.get()]; - else - [self pluginViewFinishedLoading:self]; - } - } - } -} - -@end - -#endif |