diff options
Diffstat (limited to 'WebKit/mac/Plugins')
20 files changed, 2955 insertions, 2886 deletions
diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginStream.h b/WebKit/mac/Plugins/WebBaseNetscapePluginStream.h index c2e8a21..a28793a 100644 --- a/WebKit/mac/Plugins/WebBaseNetscapePluginStream.h +++ b/WebKit/mac/Plugins/WebBaseNetscapePluginStream.h @@ -32,20 +32,19 @@ #import <WebCore/Timer.h> #import <WebCore/NetscapePlugInStreamLoader.h> #import <WebKit/npfunctions.h> -#import <WebKit/WebPlugInStreamLoaderDelegate.h> #import <wtf/PassRefPtr.h> #import <wtf/RefCounted.h> #import <wtf/RefPtr.h> #import <wtf/RetainPtr.h> -#import "WebBaseNetscapePluginView.h" +#import "WebNetscapePluginView.h" namespace WebCore { class FrameLoader; class NetscapePlugInStreamLoader; } -@class WebBaseNetscapePluginView; +@class WebNetscapePluginView; @class NSURLResponse; class WebNetscapePluginStream : public RefCounted<WebNetscapePluginStream> @@ -113,7 +112,7 @@ private: BOOL m_sendNotification; void *m_notifyData; char *m_headers; - RetainPtr<WebBaseNetscapePluginView> m_pluginView; + RetainPtr<WebNetscapePluginView> m_pluginView; NPReason m_reason; bool m_isTerminated; bool m_newStreamSuccessful; diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginStream.mm b/WebKit/mac/Plugins/WebBaseNetscapePluginStream.mm index 246a3ca..a29be2d 100644 --- a/WebKit/mac/Plugins/WebBaseNetscapePluginStream.mm +++ b/WebKit/mac/Plugins/WebBaseNetscapePluginStream.mm @@ -29,7 +29,7 @@ #if ENABLE(NETSCAPE_PLUGIN_API) #import "WebBaseNetscapePluginStream.h" -#import "WebBaseNetscapePluginView.h" +#import "WebNetscapePluginView.h" #import "WebFrameInternal.h" #import "WebKitErrorsPrivate.h" #import "WebKitLogging.h" @@ -45,6 +45,7 @@ #import <WebCore/WebCoreObjCExtras.h> #import <WebKitSystemInterface.h> #import <wtf/HashMap.h> +#import <wtf/StdLibExtras.h> using namespace WebCore; @@ -55,7 +56,7 @@ static NSString *CarbonPathFromPOSIXPath(NSString *posixPath); typedef HashMap<NPStream*, NPP> StreamMap; static StreamMap& streams() { - static StreamMap staticStreams; + DEFINE_STATIC_LOCAL(StreamMap, staticStreams, ()); return staticStreams; } @@ -134,7 +135,7 @@ WebNetscapePluginStream::WebNetscapePluginStream(NSURLRequest *request, NPP plug { memset(&m_stream, 0, sizeof(NPStream)); - WebBaseNetscapePluginView *view = (WebBaseNetscapePluginView *)plugin->ndata; + WebNetscapePluginView *view = (WebNetscapePluginView *)plugin->ndata; // This check has already been done by the plug-in view. ASSERT(FrameLoader::canLoad([request URL], String(), core([view webFrame])->document())); @@ -148,9 +149,6 @@ WebNetscapePluginStream::WebNetscapePluginStream(NSURLRequest *request, NPP plug if (core([view webFrame])->loader()->shouldHideReferrer([request URL], core([view webFrame])->loader()->outgoingReferrer())) [m_request.get() _web_setHTTPReferrer:nil]; - - m_loader = NetscapePlugInStreamLoader::create(core([view webFrame]), this); - m_loader->setShouldBufferData(false); } WebNetscapePluginStream::~WebNetscapePluginStream() @@ -173,13 +171,13 @@ void WebNetscapePluginStream::setPlugin(NPP plugin) { if (plugin) { m_plugin = plugin; - m_pluginView = static_cast<WebBaseNetscapePluginView *>(m_plugin->ndata); + m_pluginView = static_cast<WebNetscapePluginView *>(m_plugin->ndata); WebNetscapePluginPackage *pluginPackage = [m_pluginView.get() pluginPackage]; m_pluginFuncs = [pluginPackage pluginFuncs]; } else { - WebBaseNetscapePluginView *view = m_pluginView.get(); + WebNetscapePluginView *view = m_pluginView.get(); m_plugin = 0; m_pluginFuncs = 0; @@ -256,6 +254,10 @@ void WebNetscapePluginStream::start() { ASSERT(m_request); ASSERT(!m_frameLoader); + ASSERT(!m_loader); + + m_loader = NetscapePlugInStreamLoader::create(core([m_pluginView.get() webFrame]), this); + m_loader->setShouldBufferData(false); m_loader->documentLoader()->addPlugInStreamLoader(m_loader.get()); m_loader->load(m_request.get()); @@ -434,6 +436,8 @@ void WebNetscapePluginStream::destroyStreamWithReason(NPReason reason) // There is more data to be streamed, don't destroy the stream now. return; } + + RefPtr<WebNetscapePluginStream> protect(this); destroyStream(); ASSERT(!m_stream.ndata); } diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginView.h b/WebKit/mac/Plugins/WebBaseNetscapePluginView.h index 909196b..b2ea2b1 100644 --- a/WebKit/mac/Plugins/WebBaseNetscapePluginView.h +++ b/WebKit/mac/Plugins/WebBaseNetscapePluginView.h @@ -29,118 +29,37 @@ #if ENABLE(NETSCAPE_PLUGIN_API) #import <Cocoa/Cocoa.h> -#import <WebKit/npfunctions.h> -#import <WebKit/npapi.h> -#import <WebKit/WebBasePluginPackage.h> -#import <wtf/HashMap.h> -#import <wtf/HashSet.h> +#import "WebNetscapePluginPackage.h" + +#import <wtf/RetainPtr.h> @class DOMElement; @class WebDataSource; @class WebFrame; -@class WebNetscapePluginPackage; @class WebView; -class PluginTimer; -class WebNetscapePluginStream; -class WebNetscapePluginEventHandler; - -typedef union PluginPort { -#ifndef NP_NO_QUICKDRAW - NP_Port qdPort; -#endif - NP_CGContext cgPort; -} PluginPort; - -typedef struct _NPPluginTextInputFuncs NPPluginTextInputFuncs; - -// Because the Adobe 7.x Acrobat plug-in has a hard coded check for a view named -// "WebNetscapePluginDocumentView", this class must retain the old name in order -// for the plug-in to function correctly. (rdar://problem/4699455) -#define WebBaseNetscapePluginView WebNetscapePluginDocumentView - -@interface WebBaseNetscapePluginView : NSView <WebPluginManualLoader, NSTextInput> +@interface WebBaseNetscapePluginView : NSView { - WebNetscapePluginPackage *pluginPackage; + RetainPtr<WebNetscapePluginPackage> _pluginPackage; - NSURL *sourceURL; WebFrame *_webFrame; - BOOL _loadManually; - RefPtr<WebNetscapePluginStream> _manualStream; -#ifndef BUILDING_ON_TIGER - CALayer *_layer; -#endif - unsigned _dataLengthReceived; - NSError *_error; - - int mode; - - unsigned argsCount; - char **cAttributes; - char **cValues; - - NPP plugin; - NPWindow window; - NPWindow lastSetWindow; - PluginPort nPort; - PluginPort lastSetPort; - NPDrawingModel drawingModel; - NPEventModel eventModel; + int _mode; - -#ifndef NP_NO_QUICKDRAW - // This is only valid when drawingModel is NPDrawingModelQuickDraw - GWorldPtr offscreenGWorld; -#endif - - WebNetscapePluginEventHandler *eventHandler; - - BOOL isStarted; - BOOL inSetWindow; - BOOL hasFocus; - BOOL isTransparent; - BOOL isCompletelyObscured; - BOOL shouldStopSoon; - - BOOL shouldFireTimers; - uint32 currentTimerID; - HashMap<uint32, PluginTimer*>* timers; - - unsigned pluginFunctionCallDepth; - - DOMElement *element; - - int32 specifiedHeight; - int32 specifiedWidth; - - NSString *MIMEType; - NSURL *baseURL; - NSTrackingRectTag trackingTag; - - HashSet<RefPtr<WebNetscapePluginStream> > streams; - NSMutableDictionary *pendingFrameLoads; + BOOL _loadManually; + BOOL _shouldFireTimers; + BOOL _isStarted; + BOOL _hasFocus; + BOOL _isCompletelyObscured; - NPPluginTextInputFuncs *textInputFuncs; + RetainPtr<DOMElement> _element; + RetainPtr<NSString> _MIMEType; + RetainPtr<NSURL> _baseURL; + RetainPtr<NSURL> _sourceURL; - NPP_NewProcPtr NPP_New; - NPP_DestroyProcPtr NPP_Destroy; - NPP_SetWindowProcPtr NPP_SetWindow; - NPP_NewStreamProcPtr NPP_NewStream; - NPP_DestroyStreamProcPtr NPP_DestroyStream; - NPP_StreamAsFileProcPtr NPP_StreamAsFile; - NPP_WriteReadyProcPtr NPP_WriteReady; - NPP_WriteProcPtr NPP_Write; - NPP_PrintProcPtr NPP_Print; - NPP_HandleEventProcPtr NPP_HandleEvent; - NPP_URLNotifyProcPtr NPP_URLNotify; - NPP_GetValueProcPtr NPP_GetValue; - NPP_SetValueProcPtr NPP_SetValue; + NSTrackingRectTag _trackingTag; } -+ (WebBaseNetscapePluginView *)currentPluginView; - - - (id)initWithFrame:(NSRect)r pluginPackage:(WebNetscapePluginPackage *)thePluginPackage URL:(NSURL *)URL @@ -151,74 +70,31 @@ typedef struct _NPPluginTextInputFuncs NPPluginTextInputFuncs; loadManually:(BOOL)loadManually DOMElement:(DOMElement *)anElement; +- (WebNetscapePluginPackage *)pluginPackage; -- (BOOL)start; -- (BOOL)isStarted; -- (void)stop; -- (void)stopTimers; -- (void)restartTimers; +- (NSMutableURLRequest *)requestWithURLCString:(const char *)URLCString; + +// Subclasses must override these. +- (void)handleMouseMoved:(NSEvent *)event; +- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values; +- (void)focusChanged; - (WebFrame *)webFrame; - (WebDataSource *)dataSource; - (WebView *)webView; - (NSWindow *)currentWindow; -- (NPP)plugin; +- (void)removeTrackingRect; +- (void)resetTrackingRect; -- (WebNetscapePluginPackage *)pluginPackage; -- (void)setPluginPackage:(WebNetscapePluginPackage *)thePluginPackage; -- (void)setMIMEType:(NSString *)theMIMEType; -- (void)setBaseURL:(NSURL *)theBaseURL; -- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values; -- (void)setMode:(int)theMode; -- (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow; -- (void)viewDidMoveToHostWindow; -- (void)disconnectStream:(WebNetscapePluginStream*)stream; - -// Returns the NPObject that represents the plugin interface. -// The return value is expected to be retained. -- (NPObject *)createPluginScriptableObject; - -// -willCallPlugInFunction must be called before calling any of the NPP_* functions for this view's plugin. -// This is necessary to ensure that plug-ins are not destroyed while WebKit calls into them. Some plug-ins (Flash -// at least) are written with the assumption that nothing they do in their plug-in functions can cause NPP_Destroy() -// to be called. Unfortunately, this is not true, especially if the plug-in uses NPN_Invoke() to execute a -// document.write(), which clears the document and destroys the plug-in. -// See <rdar://problem/4480737>. -- (void)willCallPlugInFunction; - -// -didCallPlugInFunction should be called after returning from a plug-in function. It should be called exactly -// once for every call to -willCallPlugInFunction. -// See <rdar://problem/4480737>. -- (void)didCallPlugInFunction; - -- (void)handleMouseMoved:(NSEvent *)event; - -@end +- (void)stopTimers; +- (void)startTimers; +- (void)restartTimers; -@interface WebBaseNetscapePluginView (WebInternal) -- (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect; -- (NPEventModel)eventModel; - -- (NPError)loadRequest:(NSURLRequest *)request inTarget:(NSString *)target withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification; -- (NPError)getURLNotify:(const char *)URL target:(const char *)target notifyData:(void *)notifyData; -- (NPError)getURL:(const char *)URL target:(const char *)target; -- (NPError)postURLNotify:(const char *)URL target:(const char *)target len:(UInt32)len buf:(const char *)buf file:(NPBool)file notifyData:(void *)notifyData; -- (NPError)postURL:(const char *)URL target:(const char *)target len:(UInt32)len buf:(const char *)buf file:(NPBool)file; -- (NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream; -- (NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer; -- (NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason; -- (void)status:(const char *)message; -- (const char *)userAgent; -- (void)invalidateRect:(NPRect *)invalidRect; -- (void)invalidateRegion:(NPRegion)invalidateRegion; -- (void)forceRedraw; -- (NPError)getVariable:(NPNVariable)variable value:(void *)value; -- (NPError)setVariable:(NPPVariable)variable value:(void *)value; -- (uint32)scheduleTimerWithInterval:(uint32)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32 timerID))timerFunc; -- (void)unscheduleTimer:(uint32)timerID; -- (NPError)popUpContextMenu:(NPMenu *)menu; +- (void)stop; +- (void)addWindowObservers; +- (void)removeWindowObservers; @end #endif diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm b/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm index 2097673..a2a8b50 100644 --- a/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm +++ b/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,1100 +30,250 @@ #import "WebBaseNetscapePluginView.h" -#import "WebDataSourceInternal.h" -#import "WebDefaultUIDelegate.h" -#import "WebFrameInternal.h" -#import "WebFrameView.h" -#import "WebGraphicsExtras.h" +#import "WebFrameInternal.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 "WebNetscapePluginPackage.h" -#import "WebBaseNetscapePluginStream.h" -#import "WebNetscapePluginEventHandler.h" -#import "WebNullPluginView.h" -#import "WebPreferences.h" +#import "WebView.h" #import "WebViewInternal.h" -#import "WebUIDelegatePrivate.h" -#import <Carbon/Carbon.h> -#import <runtime/JSLock.h> -#import <WebCore/npruntime_impl.h> + +#import <WebCore/WebCoreObjCExtras.h> #import <WebCore/Document.h> -#import <WebCore/DocumentLoader.h> #import <WebCore/Element.h> -#import <WebCore/Frame.h> -#import <WebCore/FrameLoader.h> -#import <WebCore/FrameTree.h> -#import <WebCore/Page.h> -#import <WebCore/PluginMainThreadScheduler.h> -#import <WebCore/ScriptController.h> -#import <WebCore/SoftLinking.h> -#import <WebCore/WebCoreObjCExtras.h> -#import <WebKit/nptextinput.h> +#import <WebCore/Frame.h> +#import <WebCore/FrameLoader.h> +#import <WebCore/Page.h> #import <WebKit/DOMPrivate.h> -#import <WebKit/WebUIDelegate.h> +#import <runtime/InitializeThreading.h> #import <wtf/Assertions.h> -#import <objc/objc-runtime.h> - -using namespace WebCore; #define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification" #define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification" -static inline bool isDrawingModelQuickDraw(NPDrawingModel drawingModel) -{ -#ifndef NP_NO_QUICKDRAW - return drawingModel == NPDrawingModelQuickDraw; -#else - return false; -#endif -}; - -@interface WebBaseNetscapePluginView (Internal) -- (void)_viewHasMoved; -- (NPError)_createPlugin; -- (void)_destroyPlugin; -- (NSBitmapImageRep *)_printedPluginBitmap; -- (void)_redeliverStream; -@end - -static WebBaseNetscapePluginView *currentPluginView = nil; - -typedef struct OpaquePortState* PortState; - -static const double ThrottledTimerInterval = 0.25; - -class PluginTimer : public TimerBase { -public: - typedef void (*TimerFunc)(NPP npp, uint32 timerID); - - PluginTimer(NPP npp, uint32 timerID, uint32 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 = throttle ? ThrottledTimerInterval : m_interval / 1000.0; - 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 m_timerID; - uint32 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 WebPluginRequest : NSObject -{ - NSURLRequest *_request; - NSString *_frameName; - void *_notifyData; - BOOL _didStartFromUserGesture; - BOOL _sendNotification; -} - -- (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture; - -- (NSURLRequest *)request; -- (NSString *)frameName; -- (void *)notifyData; -- (BOOL)isCurrentEventUserGesture; -- (BOOL)sendNotification; - -@end - -@interface NSData (WebPluginDataExtras) -- (BOOL)_web_startsWithBlankLine; -- (NSInteger)_web_locationAfterFirstBlankLine; -@end - -@interface WebBaseNetscapePluginView (ForwardDeclarations) -- (void)setWindowIfNecessary; -- (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification; -@end +using namespace WebCore; @implementation WebBaseNetscapePluginView + (void)initialize { + JSC::initializeThreading(); #ifndef BUILDING_ON_TIGER WebCoreObjCFinalizeOnMainThread(self); #endif WKSendUserChangeNotifications(); } -#pragma mark EVENTS - -- (BOOL)superviewsHaveSuperviews -{ - NSView *contentView = [[self window] contentView]; - NSView *view; - for (view = self; view != nil; view = [view superview]) { - if (view == contentView) { - return YES; - } - } - return NO; -} - - -// 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 +- (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 + DOMElement:(DOMElement *)anElement { -#ifndef NP_NO_QUICKDRAW - ASSERT(isDrawingModelQuickDraw(drawingModel)); - - NSWindow *currentWindow = [self currentWindow]; - if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")]) - return; + self = [super initWithFrame:frame]; + if (!self) + return nil; - float windowHeight = [currentWindow frame].size.height; - NSView *contentView = [currentWindow contentView]; - NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates + _pluginPackage = pluginPackage; + _element = anElement; + _sourceURL.adoptNS([URL copy]); + _baseURL.adoptNS([baseURL copy]); + _MIMEType.adoptNS([MIME copy]); - CGrafPtr oldPort; - GetPort(&oldPort); - SetPort(GetWindowPort((WindowRef)[currentWindow windowRef])); + [self setAttributeKeys:keys andValues:values]; + if (loadManually) + _mode = NP_FULL; + else + _mode = NP_EMBED; - 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)); + _loadManually = loadManually; - SetPort(oldPort); -#endif + return self; } -#ifndef NP_NO_QUICKDRAW -static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context) +- (void)dealloc { - 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; -} + ASSERT(!_isStarted); -static inline void getNPRect(const CGRect& cgr, NPRect& npr) -{ - npr.top = static_cast<uint16>(cgr.origin.y); - npr.left = static_cast<uint16>(cgr.origin.x); - npr.bottom = static_cast<uint16>(CGRectGetMaxY(cgr)); - npr.right = static_cast<uint16>(CGRectGetMaxX(cgr)); + [super dealloc]; } -#endif - -static inline void getNPRect(const NSRect& nr, NPRect& npr) +- (void)finalize { - npr.top = static_cast<uint16>(nr.origin.y); - npr.left = static_cast<uint16>(nr.origin.x); - npr.bottom = static_cast<uint16>(NSMaxY(nr)); - npr.right = static_cast<uint16>(NSMaxX(nr)); -} + ASSERT_MAIN_THREAD(); + ASSERT(!_isStarted); -- (NSRect)visibleRect -{ - // WebCore may impose an additional clip (via CSS overflow or clip properties). Fetch - // that clip now. - return NSIntersectionRect([self convertRect:[element _windowClipRect] fromView:nil], [super visibleRect]); + [super finalize]; } -- (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate +- (WebNetscapePluginPackage *)pluginPackage { - ASSERT(drawingModel != NPDrawingModelCoreAnimation); - ASSERT([self currentWindow] != nil); - - // 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. - if (isDrawingModelQuickDraw(drawingModel)) - [self fixWindowPort]; - - // Use AppKit to convert view coordinates to NSWindow coordinates. - NSRect boundsInWindow = [self convertRect:[self bounds] toView:nil]; - NSRect visibleRectInWindow = [self convertRect:[self visibleRect] toView:nil]; - - // Flip Y to convert NSWindow 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)) { - ::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.x = (int32)boundsInWindow.origin.x; - window.y = (int32)boundsInWindow.origin.y; - window.width = static_cast<uint32>(NSWidth(boundsInWindow)); - window.height = static_cast<uint32>(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. - NSWindow *realWindow = [self window]; - if (window.width <= 0 || window.height <= 0 || window.x < -100000 - || realWindow == nil || [realWindow isMiniaturized] - || [NSApp isHidden] - || ![self superviewsHaveSuperviews] - || [self isHiddenOrHasHiddenAncestor]) { - - // 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; - } 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)-boundsInWindow.origin.x; - nPort.qdPort.porty = (int32)-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 && !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>(-boundsInWindow.origin.x + origin.x); - nPort.qdPort.porty = static_cast<int32>(-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: { - 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; - - // Update the plugin's window/context -#ifdef NP_NO_CARBON - nPort.cgPort.window = (NPNSWindow *)[self currentWindow]; -#else - nPort.cgPort.window = eventHandler->platformWindow([self currentWindow]); -#endif /* NP_NO_CARBON */ - nPort.cgPort.context = context; - window.window = &nPort.cgPort; - - // 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; - } - - default: - ASSERT_NOT_REACHED(); - portState = NULL; - break; - } - - return portState; + return _pluginPackage.get(); } - -- (PortState)saveAndSetNewPortState + +- (BOOL)isFlipped { - return [self saveAndSetNewPortStateForUpdate:NO]; + return YES; } -- (void)restorePortState:(PortState)portState +- (NSMutableURLRequest *)requestWithURLCString:(const char *)URLCString { - if (drawingModel == NPDrawingModelCoreAnimation) - return; - - ASSERT([self currentWindow]); - ASSERT(portState); + if (!URLCString) + return nil; - 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); - ASSERT(((PortState_CG *)portState)->context == nPort.cgPort.context); - CGContextRestoreGState(nPort.cgPort.context); - 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(NPP_HandleEvent); + CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, URLCString, kCFStringEncodingISOLatin1); + ASSERT(string); // All strings should be representable in ISO Latin 1 - // 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; - + NSString *URLString = [(NSString *)string _web_stringByStrippingReturnCharacters]; + NSURL *URL = [NSURL _web_URLWithDataAsString:URLString relativeToURL:_baseURL.get()]; + CFRelease(string); + if (!URL) + return nil; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; Frame* frame = core([self webFrame]); if (!frame) - return NO; - Page* page = frame->page(); - if (!page) - return NO; - - bool wasDeferring = page->defersLoading(); - if (!wasDeferring) - page->setDefersLoading(true); - - // 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) && !isTransparent && 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]; - { - JSC::JSLock::DropAllLocks dropAllLocks(false); - acceptedEvent = NPP_HandleEvent(plugin, event); - } - [self didCallPlugInFunction]; - - if (portState) { - if ([self currentWindow]) - [self restorePortState:portState]; - free(portState); - } - - if (!wasDeferring) - page->setDefersLoading(false); - - return acceptedEvent; + return nil; + [request _web_setHTTPReferrer:frame->loader()->outgoingReferrer()]; + return request; } -- (void)sendActivateEvent:(BOOL)activate +// Methods that subclasses must override +- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values { - if (!isStarted) - return; - - eventHandler->windowFocusChanged(activate); + ASSERT_NOT_REACHED(); } -- (void)sendDrawRectEvent:(NSRect)rect +- (void)handleMouseMoved:(NSEvent *)event { - ASSERT(eventHandler); - - eventHandler->drawRect(rect); + ASSERT_NOT_REACHED(); } -- (void)stopTimers +- (void)focusChanged { - if (eventHandler) - eventHandler->stopTimers(); - - shouldFireTimers = NO; - - if (!timers) - return; - - HashMap<uint32, PluginTimer*>::const_iterator end = timers->end(); - for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) { - PluginTimer* timer = it->second; - timer->stop(); - } + ASSERT_NOT_REACHED(); } -- (void)restartTimers +- (void)windowFocusChanged:(BOOL)hasFocus { - ASSERT([self window]); - - if (shouldFireTimers) - [self stopTimers]; - - if (!isStarted || [[self window] isMiniaturized]) - return; - - shouldFireTimers = YES; - - // 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, PluginTimer*>::const_iterator end = timers->end(); - for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) { - PluginTimer* timer = it->second; - ASSERT(!timer->isActive()); - timer->start(isCompletelyObscured); - } + ASSERT_NOT_REACHED(); } -- (BOOL)acceptsFirstResponder +- (BOOL)createPlugin { - return YES; + ASSERT_NOT_REACHED(); + return NO; } -- (void)setHasFocus:(BOOL)flag +- (void)loadStream { - if (!isStarted) - return; - - if (hasFocus == flag) - return; - - hasFocus = flag; - - // 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); + ASSERT_NOT_REACHED(); } -- (BOOL)becomeFirstResponder +- (BOOL)shouldStop { - [self setHasFocus:YES]; + ASSERT_NOT_REACHED(); return YES; } -- (BOOL)resignFirstResponder +- (void)destroyPlugin { - [self setHasFocus:NO]; - return YES; + ASSERT_NOT_REACHED(); } -// AppKit doesn't call mouseDown or mouseUp on right-click. Simulate control-click -// mouseDown and mouseUp so plug-ins get the right-click event as they do in Carbon (3125743). -- (void)rightMouseDown:(NSEvent *)theEvent +- (void)updateAndSetWindow { - [self mouseDown:theEvent]; + ASSERT_NOT_REACHED(); } -- (void)rightMouseUp:(NSEvent *)theEvent +- (void)removeTrackingRect { - [self mouseUp:theEvent]; + if (_trackingTag) { + [self removeTrackingRect:_trackingTag]; + _trackingTag = 0; + + // Do the following after setting trackingTag to 0 so we don't re-enter. + + // Balance the retain in resetTrackingRect. Use autorelease in case we hold + // the last reference to the window during tear-down, to avoid crashing AppKit. + [[self window] autorelease]; + } } -- (void)mouseDown:(NSEvent *)theEvent +- (void)resetTrackingRect { - if (!isStarted) - return; - - eventHandler->mouseDown(theEvent); + [self removeTrackingRect]; + if (_isStarted) { + // Retain the window so that removeTrackingRect can work after the window is closed. + [[self window] retain]; + _trackingTag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO]; + } } -- (void)mouseUp:(NSEvent *)theEvent +- (void)stopTimers { - if (!isStarted) - return; - - eventHandler->mouseUp(theEvent); + _shouldFireTimers = NO; } -- (void)mouseEntered:(NSEvent *)theEvent +- (void)startTimers { - if (!isStarted) - return; - - eventHandler->mouseEntered(theEvent); + _shouldFireTimers = YES; } -- (void)mouseExited:(NSEvent *)theEvent +- (void)restartTimers { - if (!isStarted) - return; - - eventHandler->mouseExited(theEvent); + ASSERT([self window]); - // 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]; -} - -// We can't name this method mouseMoved because we don't want to override -// the NSView mouseMoved implementation. -- (void)handleMouseMoved:(NSEvent *)theEvent -{ - if (!isStarted) - return; - - eventHandler->mouseMoved(theEvent); -} + [self stopTimers]; -- (void)mouseDragged:(NSEvent *)theEvent -{ - if (!isStarted) + if (!_isStarted || [[self window] isMiniaturized]) 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)cut:(id)sender -{ - if (!isStarted) - return; - - eventHandler->keyDown([NSApp currentEvent]); -} - -- (void)copy:(id)sender -{ - if (!isStarted) - return; - - eventHandler->keyDown([NSApp currentEvent]); -} - -- (void)paste:(id)sender -{ - if (!isStarted) - return; - - eventHandler->keyDown([NSApp currentEvent]); + + [self startTimers]; } -- (void)selectAll:(id)sender +- (NSRect)visibleRect { - if (!isStarted) - return; - - eventHandler->keyDown([NSApp currentEvent]); + // WebCore may impose an additional clip (via CSS overflow or clip properties). Fetch + // that clip now. + return NSIntersectionRect([self convertRect:[_element.get() _windowClipRect] fromView:nil], [super visibleRect]); } -#pragma mark WEB_NETSCAPE_PLUGIN - -- (BOOL)isNewWindowEqualToOldWindow +- (BOOL)acceptsFirstResponder { - ASSERT(drawingModel != NPDrawingModelCoreAnimation); - - 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; - - default: - ASSERT_NOT_REACHED(); - break; - } - return YES; } -- (void)updateAndSetWindow +- (void)sendActivateEvent:(BOOL)activate { - ASSERT(drawingModel != NPDrawingModelCoreAnimation); - - // 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. QuickDraw plug-ins are an important - // excpetion to rule (3) because they manually must be 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. - if (!isStarted) - return; -#ifdef NP_NO_QUICKDRAW - if (![self canDraw]) - return; -#else - if (drawingModel != NPDrawingModelQuickDraw && ![self canDraw]) + if (!_isStarted) return; -#endif // NP_NO_QUICKDRAW - BOOL didLockFocus = [NSView focusView] != self && [self lockFocusIfCanDraw]; - - if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel)) { - [self setWindowIfNecessary]; - if (didLockFocus) - [self unlockFocus]; - - return; - } - - PortState portState = [self saveAndSetNewPortState]; - if (portState) { - [self setWindowIfNecessary]; - [self restorePortState:portState]; - free(portState); - } - if (didLockFocus) - [self unlockFocus]; + [self windowFocusChanged:activate]; } -- (void)setWindowIfNecessary +- (void)setHasFocus:(BOOL)flag { - ASSERT(drawingModel != NPDrawingModelCoreAnimation); - - if (!isStarted) { + 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; - - // A CoreGraphics plugin's window may only be set while the plugin is being updated - ASSERT((drawingModel != NPDrawingModelCoreGraphics) || [NSView focusView] == self); - - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(false); - npErr = NPP_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", - npErr, nPort.cgPort.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)removeTrackingRect -{ - if (trackingTag) { - [self removeTrackingRect:trackingTag]; - trackingTag = 0; - - // Do the following after setting trackingTag to 0 so we don't re-enter. - - // Balance the retain in resetTrackingRect. Use autorelease in case we hold - // the last reference to the window during tear-down, to avoid crashing AppKit. - [[self window] autorelease]; - } -} - -- (void)resetTrackingRect -{ - [self removeTrackingRect]; - if (isStarted) { - // Retain the window so that removeTrackingRect can work after the window is closed. - [[self window] retain]; - trackingTag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO]; - } -} - -+ (void)setCurrentPluginView:(WebBaseNetscapePluginView *)view -{ - currentPluginView = view; -} - -+ (WebBaseNetscapePluginView *)currentPluginView -{ - return currentPluginView; -} - -- (BOOL)canStart -{ - return YES; -} - -- (void)didStart -{ - if (_loadManually) { - [self _redeliverStream]; + if (_hasFocus == flag) 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 != nil && ![sourceURL _web_isEmpty]) { - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:sourceURL]; - [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()]; - [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO]; - } + _hasFocus = flag; + + [self focusChanged]; } - (void)addWindowObservers { ASSERT([self window]); - + NSWindow *theWindow = [self window]; NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; @@ -1156,106 +306,42 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) [notificationCenter removeObserver:self name:LoginWindowDidSwitchToUserNotification object:nil]; } -- (BOOL)start +- (void)start { ASSERT([self currentWindow]); - if (isStarted) - return YES; - - if (![self canStart]) - return NO; + if (_isStarted) + return; ASSERT([self webView]); if (![[[self webView] preferences] arePlugInsEnabled]) - return NO; - - // Open the plug-in package so it remains loaded while our plugin uses it - [pluginPackage 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; - - // Plug-ins are "windowed" by default. On MacOS, windowed plug-ins share the same window and graphics port as the main - // browser window. Windowless plug-ins are rendered off-screen, then copied into the main browser window. - window.type = NPWindowTypeWindow; - - NPError npErr = [self _createPlugin]; - if (npErr != NPERR_NO_ERROR) { - LOG_ERROR("NPP_New failed with error: %d", npErr); - [self _destroyPlugin]; - [pluginPackage close]; - return NO; - } + return; + + Frame* frame = core([self webFrame]); + if (!frame) + return; + Page* page = frame->page(); + if (!page) + return; - 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 - } + bool wasDeferring = page->defersLoading(); + if (!wasDeferring) + page->setDefersLoading(true); -#ifndef NP_NO_CARBON - if (eventModel == NPEventModelCocoa && isDrawingModelQuickDraw(drawingModel)) { - LOG(Plugins, "Plugin can't use use Cocoa event model with QuickDraw drawing model: %@", pluginPackage); - [self _destroyPlugin]; - [pluginPackage close]; - - return NO; - } -#endif // NP_NO_CARBON + BOOL result = [self createPlugin]; -#ifndef BUILDING_ON_TIGER - if (drawingModel == NPDrawingModelCoreAnimation) { - void *value = 0; - if (NPP_GetValue(plugin, NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) { - _layer = (CALayer *)value; - [self setWantsLayer:YES]; - [self setLayer:_layer]; - LOG(Plugins, "%@ is using Core Animation drawing model with layer %@", pluginPackage, _layer); - } + if (!wasDeferring) + page->setDefersLoading(false); - ASSERT(_layer); - } -#endif + if (!result) + return; - // Create the event handler - eventHandler = WebNetscapePluginEventHandler::create(self); + _isStarted = YES; + [[self webView] addPluginInstanceView:self]; - // Get the text input vtable - if (eventModel == NPEventModelCocoa) { - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(false); - NPPluginTextInputFuncs *value; - if (NPP_GetValue(plugin, NPPVpluginTextInputFuncs, &value) == NPERR_NO_ERROR && value) - textInputFuncs = value; - } - [self didCallPlugInFunction]; - } + [self updateAndSetWindow]; - isStarted = YES; - [[self webView] addPluginInstanceView:self]; - - if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel)) - [self updateAndSetWindow]; - if ([self window]) { [self addWindowObservers]; if ([[self window] isKeyWindow]) { @@ -1263,353 +349,37 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) } [self restartTimers]; } - - [self resetTrackingRect]; - [self didStart]; + [self resetTrackingRect]; - return YES; + [self loadStream]; } - (void)stop { - // 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; + if (![self shouldStop]) return; - } [self removeTrackingRect]; - - if (!isStarted) + + if (!_isStarted) return; - isStarted = NO; + _isStarted = NO; [[self webView] removePluginInstanceView:self]; - - // 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(); - // Stop the timers [self stopTimers]; // Stop notifications and callbacks. [self removeWindowObservers]; - [[pendingFrameLoads 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; - - [self _destroyPlugin]; - [pluginPackage close]; - - delete eventHandler; - eventHandler = 0; - - textInputFuncs = 0; -} - -- (BOOL)isStarted -{ - return isStarted; -} - -- (NPEventModel)eventModel -{ - return eventModel; -} - -- (WebDataSource *)dataSource -{ - WebFrame *webFrame = kit(core(element)->document()->frame()); - return [webFrame _dataSource]; -} - -- (WebFrame *)webFrame -{ - return [[self dataSource] webFrame]; -} - -- (WebView *)webView -{ - return [[self webFrame] webView]; -} - -- (NSWindow *)currentWindow -{ - return [self window] ? [self window] : [[self webView] hostWindow]; -} - -- (NPP)plugin -{ - return plugin; -} - -- (WebNetscapePluginPackage *)pluginPackage -{ - return pluginPackage; -} - -- (void)setPluginPackage:(WebNetscapePluginPackage *)thePluginPackage; -{ - [thePluginPackage retain]; - [pluginPackage release]; - pluginPackage = thePluginPackage; - - NPP_New = [pluginPackage NPP_New]; - NPP_Destroy = [pluginPackage NPP_Destroy]; - NPP_SetWindow = [pluginPackage NPP_SetWindow]; - NPP_NewStream = [pluginPackage NPP_NewStream]; - NPP_WriteReady = [pluginPackage NPP_WriteReady]; - NPP_Write = [pluginPackage NPP_Write]; - NPP_StreamAsFile = [pluginPackage NPP_StreamAsFile]; - NPP_DestroyStream = [pluginPackage NPP_DestroyStream]; - NPP_HandleEvent = [pluginPackage NPP_HandleEvent]; - NPP_URLNotify = [pluginPackage NPP_URLNotify]; - NPP_GetValue = [pluginPackage NPP_GetValue]; - NPP_SetValue = [pluginPackage NPP_SetValue]; - NPP_Print = [pluginPackage NPP_Print]; -} - -- (void)setMIMEType:(NSString *)theMIMEType -{ - NSString *type = [theMIMEType copy]; - [MIMEType release]; - MIMEType = type; -} - -- (void)setBaseURL:(NSURL *)theBaseURL -{ - [theBaseURL retain]; - [baseURL release]; - baseURL = theBaseURL; -} - -- (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 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 _web_URLCString]); - argsCount++; - } else { - cAttributes = (char **)malloc([keys count] * sizeof(char *)); - cValues = (char **)malloc([values count] * sizeof(char *)); - } - - BOOL isWMP = [[[pluginPackage bundle] bundleIdentifier] isEqualToString:@"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++; - } -} - -- (void)setMode:(int)theMode -{ - mode = theMode; -} - -#pragma mark NSVIEW - -- (id)initWithFrame:(NSRect)frame - pluginPackage:(WebNetscapePluginPackage *)thePluginPackage - URL:(NSURL *)theURL - baseURL:(NSURL *)theBaseURL - MIMEType:(NSString *)MIME - attributeKeys:(NSArray *)keys - attributeValues:(NSArray *)values - loadManually:(BOOL)loadManually - DOMElement:(DOMElement *)anElement -{ - [super initWithFrame:frame]; - - pendingFrameLoads = [[NSMutableDictionary alloc] init]; - - // load the plug-in if it is not already loaded - if (![thePluginPackage load]) { - [self release]; - return nil; - } - [self setPluginPackage:thePluginPackage]; - - element = [anElement retain]; - sourceURL = [theURL retain]; - - [self setMIMEType:MIME]; - [self setBaseURL:theBaseURL]; - [self setAttributeKeys:keys andValues:values]; - if (loadManually) - [self setMode:NP_FULL]; - else - [self setMode:NP_EMBED]; - - _loadManually = loadManually; - return self; -} - -- (id)initWithFrame:(NSRect)frame -{ - ASSERT_NOT_REACHED(); - return nil; -} - -- (void)fini -{ -#ifndef NP_NO_QUICKDRAW - if (offscreenGWorld) - DisposeGWorld(offscreenGWorld); -#endif - - unsigned i; - for (i = 0; i < argsCount; i++) { - free(cAttributes[i]); - free(cValues[i]); - } - free(cAttributes); - free(cValues); - - ASSERT(!eventHandler); - - if (timers) { - deleteAllValues(*timers); - delete timers; - } -} - -- (void)disconnectStream:(WebNetscapePluginStream*)stream -{ - streams.remove(stream); -} - -- (void)dealloc -{ - ASSERT(!isStarted); - - [sourceURL release]; - [_error release]; - [pluginPackage release]; - [MIMEType release]; - [baseURL release]; - [pendingFrameLoads release]; - [element release]; - - ASSERT(!plugin); - - [self fini]; - - [super dealloc]; -} - -- (void)finalize -{ - ASSERT_MAIN_THREAD(); - ASSERT(!isStarted); - - [self fini]; - - [super finalize]; -} - -- (void)drawRect:(NSRect)rect -{ - if (drawingModel == NPDrawingModelCoreAnimation) - return; - - if (!isStarted) - return; - - if ([NSGraphicsContext currentContextDrawingToScreen]) - [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); - } - } -} - -- (BOOL)isFlipped -{ - return YES; -} - -- (void)renewGState -{ - [super renewGState]; - - // -renewGState is called whenever the view's geometry changes. It's a little hacky to override this method, but - // much safer than walking up the view hierarchy and observing frame/bounds changed notifications, since you don't - // have to track subsequent changes to the view hierarchy and add/remove notification observers. - // NSOpenGLView uses the exact same technique to reshape its OpenGL surface. - [self _viewHasMoved]; -} - --(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 */ + [self destroyPlugin]; } - (void)viewWillMoveToWindow:(NSWindow *)newWindow { - if (isDrawingModelQuickDraw(drawingModel)) - [self tellQuickTimeToChill]; - // We must remove the tracking rect before we move to the new window. // Once we move to the new window, it will be too late. [self removeTrackingRect]; @@ -1617,7 +387,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) // Workaround for: <rdar://problem/3822871> resignFirstResponder is not sent to first responder view when it is removed from the window [self setHasFocus:NO]; - + if (!newWindow) { if ([[self webView] hostWindow]) { // View will be moved out of the actual window but it still has a host window. @@ -1625,7 +395,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) } else { // View will have no associated windows. [self stop]; - + // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy. // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed. [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil]; @@ -1655,10 +425,10 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) // While in the view hierarchy, observe WebPreferencesChangedNotification so that we can start/stop depending // on whether plugins are enabled. [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(preferencesHaveChanged:) - name:WebPreferencesChangedNotification - object:nil]; - + selector:@selector(preferencesHaveChanged:) + name:WebPreferencesChangedNotification + object:nil]; + // View moved to an actual window. Start it if not already started. [self start]; [self restartTimers]; @@ -1676,7 +446,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) if (!hostWindow && ![self window]) { // View will have no associated windows. [self stop]; - + // Remove WebPreferencesChangedNotification observer -- we will observe once again when we move back into the window [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil]; } @@ -1702,9 +472,6 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) [self sendActivateEvent:YES]; [self setNeedsDisplay:YES]; [self restartTimers]; -#ifndef NP_NO_CARBON - SetUserFocusWindow((WindowRef)[[self window] windowRef]); -#endif // NP_NO_CARBON } - (void)windowResignedKey:(NSNotification *)notification @@ -1721,7 +488,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) - (void)windowDidDeminiaturize:(NSNotification *)notification { - [self stopTimers]; + [self restartTimers]; } - (void)loginWindowDidSwitchFromUser:(NSNotification *)notification @@ -1739,7 +506,7 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) WebPreferences *preferences = [[self webView] preferences]; BOOL arePlugInsEnabled = [preferences arePlugInsEnabled]; - if ([notification object] == preferences && isStarted != arePlugInsEnabled) { + if ([notification object] == preferences && _isStarted != arePlugInsEnabled) { if (arePlugInsEnabled) { if ([self currentWindow]) { [self start]; @@ -1751,1198 +518,100 @@ static inline void getNPRect(const NSRect& nr, NPRect& npr) } } -- (NPObject *)createPluginScriptableObject -{ - if (!NPP_GetValue || ![self isStarted]) - return NULL; - - NPObject *value = NULL; - NPError error; - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(false); - error = NPP_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 (![self isStarted]) - return; - - if (!_manualStream->plugin()) { - - _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 retain]; - [_error release]; - _error = error; - - if (![self isStarted]) { - return; - } - - _manualStream->destroyStreamWithError(error); -} - -- (void)pluginViewFinishedLoading:(NSView *)pluginView -{ - ASSERT(_loadManually); - ASSERT(_manualStream); - - if ([self isStarted]) - _manualStream->didFinishLoading(0); -} - -#pragma mark NSTextInput implementation - -- (NSTextInputContext *)inputContext -{ -#ifndef NP_NO_CARBON - if (![self isStarted] || eventModel == NPEventModelCarbon) - return nil; -#endif - - return [super inputContext]; -} - -- (BOOL)hasMarkedText -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->hasMarkedText) - return textInputFuncs->hasMarkedText(plugin); - - return NO; -} - -- (void)insertText:(id)aString -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->insertText) - textInputFuncs->insertText(plugin, aString); -} - -- (NSRange)markedRange -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->markedRange) - return textInputFuncs->markedRange(plugin); - - return NSMakeRange(NSNotFound, 0); -} - -- (NSRange)selectedRange -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->selectedRange) - return textInputFuncs->selectedRange(plugin); - - return NSMakeRange(NSNotFound, 0); -} - -- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->setMarkedText) - textInputFuncs->setMarkedText(plugin, aString, selRange); -} - -- (void)unmarkText -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->unmarkText) - textInputFuncs->unmarkText(plugin); -} - -- (NSArray *)validAttributesForMarkedText -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->validAttributesForMarkedText) - return textInputFuncs->validAttributesForMarkedText(plugin); - - return [NSArray array]; -} - -- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->attributedSubstringFromRange) - return textInputFuncs->attributedSubstringFromRange(plugin, theRange); - - return nil; -} - -- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->characterIndexForPoint) { - // Convert the point to window coordinates - NSPoint point = [[self window] convertScreenToBase:thePoint]; - - // And view coordinates - point = [self convertPoint:point fromView:nil]; - - return textInputFuncs->characterIndexForPoint(plugin, point); - } - - return NSNotFound; -} - -- (void)doCommandBySelector:(SEL)aSelector -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->doCommandBySelector) - textInputFuncs->doCommandBySelector(plugin, aSelector); -} - -- (NSRect)firstRectForCharacterRange:(NSRange)theRange -{ - ASSERT(eventModel == NPEventModelCocoa); - ASSERT([self isStarted]); - - if (textInputFuncs && textInputFuncs->firstRectForCharacterRange) { - NSRect rect = textInputFuncs->firstRectForCharacterRange(plugin, theRange); - - // Convert the rect to window coordinates - rect = [self convertRect:rect toView:nil]; - - // Convert the rect location to screen coordinates - rect.origin = [[self window] convertBaseToScreen:rect.origin]; - - return rect; - } - - return NSZeroRect; -} - -// test for 10.4 because of <rdar://problem/4243463> -#ifdef BUILDING_ON_TIGER -- (long)conversationIdentifier -{ - return (long)self; -} -#else -- (NSInteger)conversationIdentifier -{ - return (NSInteger)self; -} -#endif - -@end - -@implementation WebBaseNetscapePluginView (WebNPPCallbacks) - -- (NSMutableURLRequest *)requestWithURLCString:(const char *)URLCString -{ - if (!URLCString) - return nil; - - CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, URLCString, kCFStringEncodingISOLatin1); - ASSERT(string); // All strings should be representable in ISO Latin 1 - - NSString *URLString = [(NSString *)string _web_stringByStrippingReturnCharacters]; - NSURL *URL = [NSURL _web_URLWithDataAsString:URLString relativeToURL:baseURL]; - CFRelease(string); - if (!URL) - return nil; - - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; - Frame* frame = core([self webFrame]); - if (!frame) - return nil; - [request _web_setHTTPReferrer:frame->loader()->outgoingReferrer()]; - return request; -} - -- (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest +- (void)renewGState { - // 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); + [super renewGState]; - NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]]; + // -renewGState is called whenever the view's geometry changes. It's a little hacky to override this method, but + // much safer than walking up the view hierarchy and observing frame/bounds changed notifications, since you don't + // have to track subsequent changes to the view hierarchy and add/remove notification observers. + // NSOpenGLView uses the exact same technique to reshape its OpenGL surface. - // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop. - if (!isStarted) { + // All of the work this method does may safely be skipped if the view is not in a window. When the view + // is moved back into a window, everything should be set up correctly. + if (![self window]) 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(false); - NPP_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 objectForKey:webFrame]; - ASSERT(pluginRequest != nil); - ASSERT([pluginRequest sendNotification]); - - [self willCallPlugInFunction]; - { - JSC::JSLock::DropAllLocks dropAllLocks(false); - NPP_URLNotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]); - } - [self didCallPlugInFunction]; + [self updateAndSetWindow]; - [pendingFrameLoads 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(false); - NPP_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. - WebBaseNetscapePluginView *view = [frame _internalLoadDelegate]; - if (view != nil) { - ASSERT([view isKindOfClass:[WebBaseNetscapePluginView class]]); - [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK]; - } - [pendingFrameLoads _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 (!FrameLoader::canLoad(URL, String(), core([self webFrame])->document())) - 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 -{ - return [[[self webView] userAgentForURL:baseURL] UTF8String]; -} - --(void)status:(const char *)message -{ - if (!message) { - LOG_ERROR("NPN_Status passed a NULL status message"); - return; - } - - CFStringRef status = CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8); - if (!status) { - LOG_ERROR("NPN_Status: the message was not valid UTF-8"); - return; - } + [self resetTrackingRect]; - 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 setNeedsDisplayInRect:NSMakeRect(invalidRect->left, invalidRect->top, - (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)]; + // Check to see if the plugin view is completely obscured (scrolled out of view, for example). + // For performance reasons, we send null events at a lower rate to plugins which are obscured. + BOOL oldIsObscured = _isCompletelyObscured; + _isCompletelyObscured = NSIsEmptyRect([self visibleRect]); + if (_isCompletelyObscured != oldIsObscured) + [self restartTimers]; } --(BOOL)isOpaque +- (BOOL)becomeFirstResponder { + [self setHasFocus:YES]; return YES; } -- (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 setNeedsDisplayInRect:invalidRect]; -} - --(void)forceRedraw -{ - LOG(Plugins, "forceRedraw"); - [self setNeedsDisplay:YES]; - [[self window] displayIfNeeded]; -} - -static NPBrowserTextInputFuncs *browserTextInputFuncs() -{ - static NPBrowserTextInputFuncs inputFuncs = { - 0, - sizeof(NPBrowserTextInputFuncs), - NPN_MarkedTextAbandoned, - NPN_MarkedTextSelectionChanged - }; - - return &inputFuncs; -} - -- (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 = (NPObject *)[element _NPObject]; - - // 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 NPNVbrowserTextInputFuncs: - { - if (eventModel == NPEventModelCocoa) { - *(NPBrowserTextInputFuncs **)value = browserTextInputFuncs(); - return NPERR_NO_ERROR; - } - } - default: - break; - } - - return NPERR_GENERIC_ERROR; -} - -- (NPError)setVariable:(NPPVariable)variable value:(void *)value -{ - switch (variable) { - case NPPVpluginWindowBool: - { - NPWindowType newWindowType = (value ? NPWindowTypeWindow : NPWindowTypeDrawable); - - // Redisplay if window type is changing (some drawing models can only have their windows set while updating). - if (newWindowType != window.type) - [self setNeedsDisplay:YES]; - - window.type = newWindowType; - } - - case NPPVpluginTransparentBool: - { - BOOL newTransparent = (value != 0); - - // Redisplay if transparency is changing - if (isTransparent != newTransparent) - [self setNeedsDisplay:YES]; - - isTransparent = newTransparent; - - return NPERR_NO_ERROR; - } - - 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: - drawingModel = newDrawingModel; - return NPERR_NO_ERROR; - - case NPDrawingModelCoreAnimation: - drawingModel = newDrawingModel; - return NPERR_NO_ERROR; - - - // Unsupported (or unknown) drawing models: - default: - LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", pluginPackage, 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", pluginPackage, eventModel); - return NPERR_GENERIC_ERROR; - } - } - - default: - return NPERR_GENERIC_ERROR; - } -} - -- (uint32)scheduleTimerWithInterval:(uint32)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32 timerID))timerFunc -{ - if (!timerFunc) - return 0; - - if (!timers) - timers = new HashMap<uint32, PluginTimer*>; - - uint32 timerID = ++currentTimerID; - - PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc); - timers->set(timerID, timer); - - if (shouldFireTimers) - timer->start(isCompletelyObscured); - - return 0; -} - -- (void)unscheduleTimer:(uint32)timerID -{ - if (!timers) - return; - - if (PluginTimer* timer = timers->take(timerID)) - delete timer; -} - -- (NPError)popUpContextMenu:(NPMenu *)menu +- (BOOL)resignFirstResponder { - 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; + [self setHasFocus:NO]; + return YES; } -@end - -@implementation WebPluginRequest - -- (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture +- (WebDataSource *)dataSource { - [super init]; - _didStartFromUserGesture = currentEventIsUserGesture; - _request = [request retain]; - _frameName = [frameName retain]; - _notifyData = notifyData; - _sendNotification = sendNotification; - return self; + WebFrame *webFrame = kit(core(_element.get())->document()->frame()); + return [webFrame _dataSource]; } -- (void)dealloc +- (WebFrame *)webFrame { - [_request release]; - [_frameName release]; - [super dealloc]; + return [[self dataSource] webFrame]; } -- (NSURLRequest *)request +- (WebView *)webView { - return _request; + return [[self webFrame] webView]; } -- (NSString *)frameName +- (NSWindow *)currentWindow { - return _frameName; + return [self window] ? [self window] : [[self webView] hostWindow]; } -- (BOOL)isCurrentEventUserGesture -{ - return _didStartFromUserGesture; -} +// We want to treat these as regular keyboard events. -- (BOOL)sendNotification +- (void)cut:(id)sender { - return _sendNotification; + [self keyDown:[NSApp currentEvent]]; } -- (void *)notifyData +- (void)copy:(id)sender { - return _notifyData; + [self keyDown:[NSApp currentEvent]]; } -@end - -@implementation WebBaseNetscapePluginView (Internal) - -- (NPError)_createPlugin -{ - plugin = (NPP)calloc(1, sizeof(NPP_t)); - plugin->ndata = self; - - ASSERT(NPP_New); - - // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance. - ASSERT(pluginFunctionCallDepth == 0); - - Frame* frame = core([self webFrame]); - if (!frame) - return NPERR_GENERIC_ERROR; - Page* page = frame->page(); - if (!page) - return NPERR_GENERIC_ERROR; - - bool wasDeferring = page->defersLoading(); - if (!wasDeferring) - page->setDefersLoading(true); - - PluginMainThreadScheduler::scheduler().registerPlugin(plugin); - - [[self class] setCurrentPluginView:self]; - NPError npErr = NPP_New((char *)[MIMEType cString], plugin, mode, argsCount, cAttributes, cValues, NULL); - [[self class] setCurrentPluginView:nil]; - - if (!wasDeferring) - page->setDefersLoading(false); - - LOG(Plugins, "NPP_New: %d", npErr); - return npErr; -} - -- (void)_destroyPlugin +- (void)paste:(id)sender { - PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin); - - NPError npErr; - npErr = NPP_Destroy(plugin, NULL); - LOG(Plugins, "NPP_Destroy: %d", npErr); - - if (Frame* frame = core([self webFrame])) - frame->script()->cleanupScriptObjectsForPlugin(self); - - free(plugin); - plugin = NULL; + [self keyDown:[NSApp currentEvent]]; } -- (void)_viewHasMoved +- (void)selectAll:(id)sender { - // All of the work this method does may safely be skipped if the view is not in a window. When the view - // is moved back into a window, everything should be set up correctly. - if (![self window]) - return; - - if (isDrawingModelQuickDraw(drawingModel)) - [self tellQuickTimeToChill]; - - if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel)) - [self updateAndSetWindow]; - - [self resetTrackingRect]; - - // Check to see if the plugin view is completely obscured (scrolled out of view, for example). - // For performance reasons, we send null events at a lower rate to plugins which are obscured. - BOOL oldIsObscured = isCompletelyObscured; - isCompletelyObscured = NSIsEmptyRect([self visibleRect]); - if (isCompletelyObscured != oldIsObscured) - [self restartTimers]; + [self keyDown:[NSApp currentEvent]]; } -- (NSBitmapImageRep *)_printedPluginBitmap +// AppKit doesn't call mouseDown or mouseUp on right-click. Simulate control-click +// mouseDown and mouseUp so plug-ins get the right-click event as they do in Carbon (3125743). +- (void)rightMouseDown:(NSEvent *)theEvent { -#ifdef NP_NO_QUICKDRAW - return nil; -#else - // Cannot print plugins that do not implement NPP_Print - if (!NPP_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(false); - NPP_Print(plugin, &npPrint); - } - [self didCallPlugInFunction]; - - // Don't need the GWorld anymore - DisposeGWorld(printGWorld); - - return bitmap; -#endif + [self mouseDown:theEvent]; } -- (void)_redeliverStream +- (void)rightMouseUp:(NSEvent *)theEvent { - if ([self dataSource] && [self 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]; - else - [self pluginViewFinishedLoading:self]; - } - } - } + [self mouseUp:theEvent]; } @end -@implementation NSData (PluginExtras) +#endif // ENABLE(NETSCAPE_PLUGIN_API) -- (BOOL)_web_startsWithBlankLine -{ - return [self length] > 0 && ((const char *)[self bytes])[0] == '\n'; -} - - -- (NSInteger)_web_locationAfterFirstBlankLine -{ - const char *bytes = (const char *)[self bytes]; - unsigned length = [self length]; - - unsigned i; - for (i = 0; i < length - 4; i++) { - - // Support for Acrobat. It sends "\n\n". - if (bytes[i] == '\n' && bytes[i+1] == '\n') { - return i+2; - } - - // Returns the position after 2 CRLF's or 1 CRLF if it is the first line. - if (bytes[i] == '\r' && bytes[i+1] == '\n') { - i += 2; - if (i == 2) { - return i; - } else if (bytes[i] == '\n') { - // Support for Director. It sends "\r\n\n" (3880387). - return i+1; - } else if (bytes[i] == '\r' && bytes[i+1] == '\n') { - // Support for Flash. It sends "\r\n\r\n" (3758113). - return i+2; - } - } - } - return NSNotFound; -} - -@end -#endif diff --git a/WebKit/mac/Plugins/WebBasePluginPackage.m b/WebKit/mac/Plugins/WebBasePluginPackage.mm index 03d438b..7b5ef8e 100644 --- a/WebKit/mac/Plugins/WebBasePluginPackage.m +++ b/WebKit/mac/Plugins/WebBasePluginPackage.mm @@ -33,6 +33,7 @@ #import <WebKit/WebNSObjectExtras.h> #import <WebKit/WebPluginPackage.h> #import <WebCore/WebCoreObjCExtras.h> +#import <runtime/InitializeThreading.h> #import <wtf/Assertions.h> #import <wtf/Vector.h> @@ -59,12 +60,13 @@ @implementation WebBasePluginPackage -#ifndef BUILDING_ON_TIGER + (void)initialize { + JSC::initializeThreading(); +#ifndef BUILDING_ON_TIGER WebCoreObjCFinalizeOnMainThread(self); -} #endif +} + (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath { diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandler.h b/WebKit/mac/Plugins/WebNetscapePluginEventHandler.h index 54402bb..d00796f 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginEventHandler.h +++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandler.h @@ -26,18 +26,18 @@ #ifndef WebNetscapePluginEventHandler_h #define WebNetscapePluginEventHandler_h -#import "WebBaseNetscapePluginView.h" +#import "WebNetscapePluginView.h" #if ENABLE(NETSCAPE_PLUGIN_API) @class NSEvent; -@class WebBaseNetscapePluginView; +@class WebNetscapePluginView; struct CGRect; class WebNetscapePluginEventHandler { public: - static WebNetscapePluginEventHandler* create(WebBaseNetscapePluginView*); + static WebNetscapePluginEventHandler* create(WebNetscapePluginView*); virtual ~WebNetscapePluginEventHandler() { } virtual void drawRect(const NSRect&) = 0; @@ -65,13 +65,13 @@ public: bool currentEventIsUserGesture() const { return m_currentEventIsUserGesture; } protected: - WebNetscapePluginEventHandler(WebBaseNetscapePluginView* pluginView) + WebNetscapePluginEventHandler(WebNetscapePluginView* pluginView) : m_pluginView(pluginView) , m_currentEventIsUserGesture(false) { } - WebBaseNetscapePluginView* m_pluginView; + WebNetscapePluginView* m_pluginView; bool m_currentEventIsUserGesture; }; diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandler.mm b/WebKit/mac/Plugins/WebNetscapePluginEventHandler.mm index e8e6d8a..c886d7b 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginEventHandler.mm +++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandler.mm @@ -28,11 +28,11 @@ #import "WebNetscapePluginEventHandler.h" #import <wtf/Assertions.h> -#import "WebBaseNetscapePluginView.h" +#import "WebNetscapePluginView.h" #import "WebNetscapePluginEventHandlerCarbon.h" #import "WebNetscapePluginEventHandlerCocoa.h" -WebNetscapePluginEventHandler* WebNetscapePluginEventHandler::create(WebBaseNetscapePluginView* pluginView) +WebNetscapePluginEventHandler* WebNetscapePluginEventHandler::create(WebNetscapePluginView* pluginView) { switch ([pluginView eventModel]) { #ifndef NP_NO_CARBON diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.h b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.h index cf26276..b01922a 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.h +++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.h @@ -35,7 +35,7 @@ class WebNetscapePluginEventHandlerCarbon : public WebNetscapePluginEventHandler { public: - WebNetscapePluginEventHandlerCarbon(WebBaseNetscapePluginView*); + WebNetscapePluginEventHandlerCarbon(WebNetscapePluginView*); virtual void drawRect(const NSRect&); diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm index bfdd91c..7612322 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm +++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm @@ -27,7 +27,7 @@ #import "WebNetscapePluginEventHandlerCarbon.h" -#import "WebBaseNetscapePluginView.h" +#import "WebNetscapePluginView.h" #import "WebKitLogging.h" #import "WebKitSystemInterface.h" @@ -35,7 +35,7 @@ #define NullEventIntervalActive 0.02 #define NullEventIntervalNotActive 0.25 -WebNetscapePluginEventHandlerCarbon::WebNetscapePluginEventHandlerCarbon(WebBaseNetscapePluginView* pluginView) +WebNetscapePluginEventHandlerCarbon::WebNetscapePluginEventHandlerCarbon(WebNetscapePluginView* pluginView) : WebNetscapePluginEventHandler(pluginView) , m_keyEventHandler(0) , m_suspendKeyUpEvents(false) @@ -265,11 +265,14 @@ void WebNetscapePluginEventHandlerCarbon::focusChanged(bool hasFocus) void WebNetscapePluginEventHandlerCarbon::windowFocusChanged(bool hasFocus) { + WindowRef windowRef = (WindowRef)[[m_pluginView window] windowRef]; + + SetUserFocusWindow(windowRef); + EventRecord event; getCarbonEvent(&event); event.what = activateEvt; - WindowRef windowRef = (WindowRef)[[m_pluginView window] windowRef]; event.message = (unsigned long)windowRef; if (hasFocus) event.modifiers |= activeFlag; diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.h b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.h index e22ff3d..8b6f6e7 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.h +++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.h @@ -33,7 +33,7 @@ class WebNetscapePluginEventHandlerCocoa : public WebNetscapePluginEventHandler { public: - WebNetscapePluginEventHandlerCocoa(WebBaseNetscapePluginView*); + WebNetscapePluginEventHandlerCocoa(WebNetscapePluginView*); virtual void drawRect(const NSRect&); diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.mm b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.mm index fb13a12..288a356 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.mm +++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.mm @@ -27,9 +27,9 @@ #import "WebNetscapePluginEventHandlerCocoa.h" -#import "WebBaseNetscapePluginView.h" +#import "WebNetscapePluginView.h" -WebNetscapePluginEventHandlerCocoa::WebNetscapePluginEventHandlerCocoa(WebBaseNetscapePluginView* pluginView) +WebNetscapePluginEventHandlerCocoa::WebNetscapePluginEventHandlerCocoa(WebNetscapePluginView* pluginView) : WebNetscapePluginEventHandler(pluginView) { } diff --git a/WebKit/mac/Plugins/WebNetscapePluginPackage.h b/WebKit/mac/Plugins/WebNetscapePluginPackage.h index 6ccbfdb..010956d 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginPackage.h +++ b/WebKit/mac/Plugins/WebNetscapePluginPackage.h @@ -52,26 +52,16 @@ typedef enum { ResFileRefNum resourceRef; - NPP_NewProcPtr NPP_New; - NPP_DestroyProcPtr NPP_Destroy; - NPP_SetWindowProcPtr NPP_SetWindow; - NPP_NewStreamProcPtr NPP_NewStream; - NPP_DestroyStreamProcPtr NPP_DestroyStream; - NPP_StreamAsFileProcPtr NPP_StreamAsFile; - NPP_WriteReadyProcPtr NPP_WriteReady; - NPP_WriteProcPtr NPP_Write; - NPP_PrintProcPtr NPP_Print; - NPP_HandleEventProcPtr NPP_HandleEvent; - NPP_URLNotifyProcPtr NPP_URLNotify; - NPP_GetValueProcPtr NPP_GetValue; - NPP_SetValueProcPtr NPP_SetValue; - NPP_ShutdownProcPtr NPP_Shutdown; - NPP_GetJavaClassProcPtr NPP_GetJavaClass; + NPP_ShutdownProcPtr NP_Shutdown; BOOL isLoaded; BOOL needsUnload; unsigned int instanceCount; - + +#if USE(PLUGIN_HOST_PROCESS) + cpu_type_t pluginHostArchitecture; +#endif + #ifdef SUPPORT_CFM BOOL isBundle; BOOL isCFM; @@ -85,21 +75,11 @@ typedef enum { - (void)close; - (WebExecutableType)executableType; - -- (NPP_NewProcPtr)NPP_New; -- (NPP_DestroyProcPtr)NPP_Destroy; -- (NPP_SetWindowProcPtr)NPP_SetWindow; -- (NPP_NewStreamProcPtr)NPP_NewStream; -- (NPP_WriteReadyProcPtr)NPP_WriteReady; -- (NPP_WriteProcPtr)NPP_Write; -- (NPP_StreamAsFileProcPtr)NPP_StreamAsFile; -- (NPP_DestroyStreamProcPtr)NPP_DestroyStream; -- (NPP_HandleEventProcPtr)NPP_HandleEvent; -- (NPP_URLNotifyProcPtr)NPP_URLNotify; -- (NPP_GetValueProcPtr)NPP_GetValue; -- (NPP_SetValueProcPtr)NPP_SetValue; -- (NPP_PrintProcPtr)NPP_Print; - (NPPluginFuncs *)pluginFuncs; +#if USE(PLUGIN_HOST_PROCESS) +- (cpu_type_t)pluginHostArchitecture; +#endif + @end #endif diff --git a/WebKit/mac/Plugins/WebNetscapePluginPackage.m b/WebKit/mac/Plugins/WebNetscapePluginPackage.m index 0767c1d..b3ad0bd 100644 --- a/WebKit/mac/Plugins/WebNetscapePluginPackage.m +++ b/WebKit/mac/Plugins/WebNetscapePluginPackage.m @@ -236,9 +236,20 @@ static TransitionVector tVectorForFunctionPointer(FunctionPointer); if (hasCFMHeader) return NO; #endif + +#if USE(PLUGIN_HOST_PROCESS) + NSArray *archs = [bundle executableArchitectures]; + if ([archs containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureX86_64]]) + pluginHostArchitecture = CPU_TYPE_X86_64; + else if ([archs containsObject:[NSNumber numberWithInteger:NSBundleExecutableArchitectureI386]]) + pluginHostArchitecture = CPU_TYPE_X86; + else + return NO; +#else if (![self isNativeLibraryData:data]) return NO; +#endif } if (![self getPluginInfoFromPLists] && ![self getPluginInfoFromResources]) @@ -272,6 +283,13 @@ static TransitionVector tVectorForFunctionPointer(FunctionPointer); return WebMachOExecutableType; } +#if USE(PLUGIN_HOST_PROCESS) +- (cpu_type_t)pluginHostArchitecture +{ + return pluginHostArchitecture; +} +#endif + - (void)launchRealPlayer { CFURLRef appURL = NULL; @@ -346,8 +364,8 @@ static TransitionVector tVectorForFunctionPointer(FunctionPointer); #endif NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Initialize")); NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_GetEntryPoints")); - NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Shutdown")); - if (!NP_Initialize || !NP_GetEntryPoints || !NPP_Shutdown) + NP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Shutdown")); + if (!NP_Initialize || !NP_GetEntryPoints || !NP_Shutdown) goto abort; #ifdef SUPPORT_CFM } @@ -439,9 +457,11 @@ static TransitionVector tVectorForFunctionPointer(FunctionPointer); browserFuncs.createobject = (NPN_CreateObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_CreateObject); browserFuncs.retainobject = (NPN_RetainObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RetainObject); browserFuncs.releaseobject = (NPN_ReleaseObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseObject); + browserFuncs.hasmethod = (NPN_HasMethodProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_HasProperty); browserFuncs.invoke = (NPN_InvokeProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Invoke); browserFuncs.invokeDefault = (NPN_InvokeDefaultProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_InvokeDefault); browserFuncs.evaluate = (NPN_EvaluateProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Evaluate); + browserFuncs.hasproperty = (NPN_HasPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_HasProperty); browserFuncs.getproperty = (NPN_GetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetProperty); browserFuncs.setproperty = (NPN_SetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetProperty); browserFuncs.removeproperty = (NPN_RemovePropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RemoveProperty); @@ -457,7 +477,7 @@ static TransitionVector tVectorForFunctionPointer(FunctionPointer); LOG(Plugins, "%f main timing started", mainStart); NPP_ShutdownProcPtr shutdownFunction; npErr = pluginMainFunc(&browserFuncs, &pluginFuncs, &shutdownFunction); - NPP_Shutdown = (NPP_ShutdownProcPtr)functionPointerForTVector((TransitionVector)shutdownFunction); + NP_Shutdown = (NPP_ShutdownProcPtr)functionPointerForTVector((TransitionVector)shutdownFunction); if (!isBundle) // Don't free pluginMainFunc if we got it from a bundle because it is owned by CFBundle in that case. free(pluginMainFunc); @@ -479,24 +499,24 @@ static TransitionVector tVectorForFunctionPointer(FunctionPointer); pluginVersion = pluginFuncs.version; LOG(Plugins, "pluginMainFunc: %d, size=%d, version=%d", npErr, pluginSize, pluginVersion); - NPP_New = (NPP_NewProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newp); - NPP_Destroy = (NPP_DestroyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroy); - NPP_SetWindow = (NPP_SetWindowProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setwindow); - NPP_NewStream = (NPP_NewStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newstream); - NPP_DestroyStream = (NPP_DestroyStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroystream); - NPP_StreamAsFile = (NPP_StreamAsFileProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.asfile); - NPP_WriteReady = (NPP_WriteReadyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.writeready); - NPP_Write = (NPP_WriteProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.write); - NPP_Print = (NPP_PrintProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.print); - NPP_HandleEvent = (NPP_HandleEventProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.event); - NPP_URLNotify = (NPP_URLNotifyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.urlnotify); - NPP_GetValue = (NPP_GetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.getvalue); - NPP_SetValue = (NPP_SetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setvalue); + pluginFuncs.newp = (NPP_NewProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newp); + pluginFuncs.destroy = (NPP_DestroyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroy); + pluginFuncs.setwindow = (NPP_SetWindowProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setwindow); + pluginFuncs.newstream = (NPP_NewStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newstream); + pluginFuncs.destroystream = (NPP_DestroyStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroystream); + pluginFuncs.asfile = (NPP_StreamAsFileProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.asfile); + pluginFuncs.writeready = (NPP_WriteReadyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.writeready); + pluginFuncs.write = (NPP_WriteProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.write); + pluginFuncs.print = (NPP_PrintProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.print); + pluginFuncs.event = (NPP_HandleEventProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.event); + pluginFuncs.urlnotify = (NPP_URLNotifyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.urlnotify); + pluginFuncs.getvalue = (NPP_GetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.getvalue); + pluginFuncs.setvalue = (NPP_SetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setvalue); // LiveConnect support - NPP_GetJavaClass = (NPP_GetJavaClassProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.javaClass); - if (NPP_GetJavaClass) { - LOG(LiveConnect, "%@: CFM entry point for NPP_GetJavaClass = %p", [self name], NPP_GetJavaClass); + pluginFuncs.javaClass = (NPP_GetJavaClassProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.javaClass); + if (pluginFuncs.javaClass) { + LOG(LiveConnect, "%@: CFM entry point for NPP_GetJavaClass = %p", [self name], pluginFuncs.javaClass); } else { LOG(LiveConnect, "%@: no entry point for NPP_GetJavaClass", [self name]); } @@ -546,9 +566,11 @@ static TransitionVector tVectorForFunctionPointer(FunctionPointer); browserFuncs.createobject = _NPN_CreateObject; browserFuncs.retainobject = _NPN_RetainObject; browserFuncs.releaseobject = _NPN_ReleaseObject; + browserFuncs.hasmethod = _NPN_HasMethod; browserFuncs.invoke = _NPN_Invoke; browserFuncs.invokeDefault = _NPN_InvokeDefault; browserFuncs.evaluate = _NPN_Evaluate; + browserFuncs.hasproperty = _NPN_HasProperty; browserFuncs.getproperty = _NPN_GetProperty; browserFuncs.setproperty = _NPN_SetProperty; browserFuncs.removeproperty = _NPN_RemoveProperty; @@ -580,27 +602,10 @@ static TransitionVector tVectorForFunctionPointer(FunctionPointer); pluginSize = pluginFuncs.size; pluginVersion = pluginFuncs.version; - NPP_New = pluginFuncs.newp; - NPP_Destroy = pluginFuncs.destroy; - NPP_SetWindow = pluginFuncs.setwindow; - NPP_NewStream = pluginFuncs.newstream; - NPP_DestroyStream = pluginFuncs.destroystream; - NPP_StreamAsFile = pluginFuncs.asfile; - NPP_WriteReady = pluginFuncs.writeready; - NPP_Write = pluginFuncs.write; - NPP_Print = pluginFuncs.print; - NPP_HandleEvent = pluginFuncs.event; - NPP_URLNotify = pluginFuncs.urlnotify; - NPP_GetValue = pluginFuncs.getvalue; - NPP_SetValue = pluginFuncs.setvalue; - - // LiveConnect support - NPP_GetJavaClass = pluginFuncs.javaClass; - if (NPP_GetJavaClass){ - LOG(LiveConnect, "%@: mach-o entry point for NPP_GetJavaClass = %p", [self name], NPP_GetJavaClass); - } else { + if (pluginFuncs.javaClass) + LOG(LiveConnect, "%@: mach-o entry point for NPP_GetJavaClass = %p", [self name], pluginFuncs.javaClass); + else LOG(LiveConnect, "%@: no entry point for NPP_GetJavaClass", [self name]); - } #ifdef SUPPORT_CFM } @@ -619,69 +624,6 @@ abort: return NO; } -- (NPP_SetWindowProcPtr)NPP_SetWindow -{ - return NPP_SetWindow; -} - -- (NPP_NewProcPtr)NPP_New -{ - return NPP_New; -} - -- (NPP_DestroyProcPtr)NPP_Destroy -{ - return NPP_Destroy; -} - -- (NPP_NewStreamProcPtr)NPP_NewStream -{ - return NPP_NewStream; -} - -- (NPP_StreamAsFileProcPtr)NPP_StreamAsFile -{ - return NPP_StreamAsFile; -} -- (NPP_DestroyStreamProcPtr)NPP_DestroyStream -{ - return NPP_DestroyStream; -} - -- (NPP_WriteReadyProcPtr)NPP_WriteReady -{ - return NPP_WriteReady; -} -- (NPP_WriteProcPtr)NPP_Write -{ - return NPP_Write; -} - -- (NPP_HandleEventProcPtr)NPP_HandleEvent -{ - return NPP_HandleEvent; -} - --(NPP_URLNotifyProcPtr)NPP_URLNotify -{ - return NPP_URLNotify; -} - --(NPP_GetValueProcPtr)NPP_GetValue -{ - return NPP_GetValue; -} - --(NPP_SetValueProcPtr)NPP_SetValue -{ - return NPP_SetValue; -} - --(NPP_PrintProcPtr)NPP_Print -{ - return NPP_Print; -} - - (NPPluginFuncs *)pluginFuncs { return &pluginFuncs; @@ -775,8 +717,8 @@ TransitionVector tVectorForFunctionPointer(FunctionPointer fp) return; } - if (shutdown && NPP_Shutdown) - NPP_Shutdown(); + if (shutdown && NP_Shutdown) + NP_Shutdown(); if (resourceRef != -1) [self closeResourceFile:resourceRef]; diff --git a/WebKit/mac/Plugins/WebNetscapePluginView.h b/WebKit/mac/Plugins/WebNetscapePluginView.h new file mode 100644 index 0000000..9d2555b --- /dev/null +++ b/WebKit/mac/Plugins/WebNetscapePluginView.h @@ -0,0 +1,174 @@ +/* + * 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. + */ + +#if ENABLE(NETSCAPE_PLUGIN_API) + +#import "WebBaseNetscapePluginView.h" + +#import <WebKit/npfunctions.h> +#import <WebKit/npapi.h> +#import <wtf/HashMap.h> +#import <wtf/HashSet.h> +#import <wtf/OwnPtr.h> + +@class WebDataSource; +@class WebFrame; +@class WebNetscapePluginPackage; +@class WebView; + +class PluginTimer; +class WebNetscapePluginStream; +class WebNetscapePluginEventHandler; + +typedef union PluginPort { +#ifndef NP_NO_QUICKDRAW + NP_Port qdPort; +#endif + NP_CGContext cgPort; +} PluginPort; + +typedef struct _NPPluginTextInputFuncs NPPluginTextInputFuncs; + +// Because the Adobe 7.x Acrobat plug-in has a hard coded check for a view named +// "WebNetscapePluginDocumentView", this class must retain the old name in order +// for the plug-in to function correctly. (rdar://problem/4699455) +#define WebNetscapePluginView WebNetscapePluginDocumentView + +@interface WebNetscapePluginView : WebBaseNetscapePluginView<WebPluginManualLoader, NSTextInput> +{ + RefPtr<WebNetscapePluginStream> _manualStream; +#ifndef BUILDING_ON_TIGER + RetainPtr<CALayer> _pluginLayer; +#endif + unsigned _dataLengthReceived; + RetainPtr<NSError> _error; + + unsigned argsCount; + char **cAttributes; + char **cValues; + + NPP plugin; + NPWindow window; + NPWindow lastSetWindow; + PluginPort nPort; + PluginPort lastSetPort; + NPDrawingModel drawingModel; + NPEventModel eventModel; + +#ifndef NP_NO_QUICKDRAW + // This is only valid when drawingModel is NPDrawingModelQuickDraw + GWorldPtr offscreenGWorld; +#endif + + OwnPtr<WebNetscapePluginEventHandler> _eventHandler; + + BOOL inSetWindow; + BOOL shouldStopSoon; + + uint32 currentTimerID; + HashMap<uint32, PluginTimer*>* timers; + + unsigned pluginFunctionCallDepth; + + int32 specifiedHeight; + int32 specifiedWidth; + + HashSet<RefPtr<WebNetscapePluginStream> > streams; + RetainPtr<NSMutableDictionary> _pendingFrameLoads; + + BOOL _isSilverlight; + + NPPluginTextInputFuncs *textInputFuncs; +} + ++ (WebNetscapePluginView *)currentPluginView; + + +- (id)initWithFrame:(NSRect)r + pluginPackage:(WebNetscapePluginPackage *)thePluginPackage + URL:(NSURL *)URL + baseURL:(NSURL *)baseURL + MIMEType:(NSString *)MIME + attributeKeys:(NSArray *)keys + attributeValues:(NSArray *)values + loadManually:(BOOL)loadManually + DOMElement:(DOMElement *)anElement; + + +- (NPP)plugin; + +- (void)disconnectStream:(WebNetscapePluginStream*)stream; + +// Returns the NPObject that represents the plugin interface. +// The return value is expected to be retained. +- (NPObject *)createPluginScriptableObject; + +// -willCallPlugInFunction must be called before calling any of the NPP_* functions for this view's plugin. +// This is necessary to ensure that plug-ins are not destroyed while WebKit calls into them. Some plug-ins (Flash +// at least) are written with the assumption that nothing they do in their plug-in functions can cause NPP_Destroy() +// to be called. Unfortunately, this is not true, especially if the plug-in uses NPN_Invoke() to execute a +// document.write(), which clears the document and destroys the plug-in. +// See <rdar://problem/4480737>. +- (void)willCallPlugInFunction; + +// -didCallPlugInFunction should be called after returning from a plug-in function. It should be called exactly +// once for every call to -willCallPlugInFunction. +// See <rdar://problem/4480737>. +- (void)didCallPlugInFunction; + +- (void)handleMouseMoved:(NSEvent *)event; + +@end + +@interface WebNetscapePluginView (WebInternal) +- (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect; +- (NPEventModel)eventModel; + +- (NPError)loadRequest:(NSURLRequest *)request inTarget:(NSString *)target withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification; +- (NPError)getURLNotify:(const char *)URL target:(const char *)target notifyData:(void *)notifyData; +- (NPError)getURL:(const char *)URL target:(const char *)target; +- (NPError)postURLNotify:(const char *)URL target:(const char *)target len:(UInt32)len buf:(const char *)buf file:(NPBool)file notifyData:(void *)notifyData; +- (NPError)postURL:(const char *)URL target:(const char *)target len:(UInt32)len buf:(const char *)buf file:(NPBool)file; +- (NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream; +- (NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer; +- (NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason; +- (void)status:(const char *)message; +- (const char *)userAgent; +- (void)invalidateRect:(NPRect *)invalidRect; +- (void)invalidateRegion:(NPRegion)invalidateRegion; +- (void)forceRedraw; +- (NPError)getVariable:(NPNVariable)variable value:(void *)value; +- (NPError)setVariable:(NPPVariable)variable value:(void *)value; +- (uint32)scheduleTimerWithInterval:(uint32)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32 timerID))timerFunc; +- (void)unscheduleTimer:(uint32)timerID; +- (NPError)popUpContextMenu:(NPMenu *)menu; + +@end + +#endif + diff --git a/WebKit/mac/Plugins/WebNetscapePluginView.mm b/WebKit/mac/Plugins/WebNetscapePluginView.mm new file mode 100644 index 0000000..a792e21 --- /dev/null +++ b/WebKit/mac/Plugins/WebNetscapePluginView.mm @@ -0,0 +1,2338 @@ +/* + * 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 "WebDataSourceInternal.h" +#import "WebDefaultUIDelegate.h" +#import "WebFrameInternal.h" +#import "WebFrameView.h" +#import "WebGraphicsExtras.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 "WebNetscapePluginPackage.h" +#import "WebBaseNetscapePluginStream.h" +#import "WebNetscapePluginEventHandler.h" +#import "WebNullPluginView.h" +#import "WebPreferences.h" +#import "WebPluginRequest.h" +#import "WebViewInternal.h" +#import "WebUIDelegatePrivate.h" +#import <Carbon/Carbon.h> +#import <runtime/JSLock.h> +#import <WebCore/npruntime_impl.h> +#import <WebCore/DocumentLoader.h> +#import <WebCore/Element.h> +#import <WebCore/Frame.h> +#import <WebCore/FrameLoader.h> +#import <WebCore/FrameTree.h> +#import <WebCore/Page.h> +#import <WebCore/PluginMainThreadScheduler.h> +#import <WebCore/ScriptController.h> +#import <WebCore/SoftLinking.h> +#import <WebCore/WebCoreObjCExtras.h> +#import <WebKit/nptextinput.h> +#import <WebKit/DOMPrivate.h> +#import <WebKit/WebUIDelegate.h> +#import <runtime/InitializeThreading.h> +#import <wtf/Assertions.h> +#import <objc/objc-runtime.h> + +#define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification" +#define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification" + +using namespace WebCore; + +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; +@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 timerID); + + PluginTimer(NPP npp, uint32 timerID, uint32 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 m_timerID; + uint32 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(); +#ifndef BUILDING_ON_TIGER + WebCoreObjCFinalizeOnMainThread(self); +#endif + WKSendUserChangeNotifications(); +} + +#pragma mark EVENTS + +- (BOOL)superviewsHaveSuperviews +{ + NSView *contentView = [[self window] contentView]; + NSView *view; + for (view = self; view != nil; view = [view superview]) { + if (view == contentView) { + return YES; + } + } + return NO; +} + + +// 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>(cgr.origin.y); + npr.left = static_cast<uint16>(cgr.origin.x); + npr.bottom = static_cast<uint16>(CGRectGetMaxY(cgr)); + npr.right = static_cast<uint16>(CGRectGetMaxX(cgr)); +} + +#endif + +static inline void getNPRect(const NSRect& nr, NPRect& npr) +{ + npr.top = static_cast<uint16>(nr.origin.y); + npr.left = static_cast<uint16>(nr.origin.x); + npr.bottom = static_cast<uint16>(NSMaxY(nr)); + npr.right = static_cast<uint16>(NSMaxX(nr)); +} + +- (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate +{ + ASSERT([self currentWindow] != nil); + + // Use AppKit to convert view coordinates to NSWindow coordinates. + NSRect boundsInWindow = [self convertRect:[self bounds] toView:nil]; + NSRect visibleRectInWindow = [self convertRect:[self visibleRect] toView:nil]; + + // Flip Y to convert NSWindow 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)boundsInWindow.origin.x; + window.y = (int32)boundsInWindow.origin.y; + window.width = static_cast<uint32>(NSWidth(boundsInWindow)); + window.height = static_cast<uint32>(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. + NSWindow *realWindow = [self window]; + if (window.width <= 0 || window.height <= 0 || window.x < -100000 + || realWindow == nil || [realWindow isMiniaturized] + || [NSApp isHidden] + || ![self superviewsHaveSuperviews] + || [self isHiddenOrHasHiddenAncestor]) { + + // 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; + } 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)-boundsInWindow.origin.x; + nPort.qdPort.porty = (int32)-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 && !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>(-boundsInWindow.origin.x + origin.x); + nPort.qdPort.porty = static_cast<int32>(-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: { + 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; + + // Update the plugin's window/context +#ifdef NP_NO_CARBON + nPort.cgPort.window = (NPNSWindow *)[self currentWindow]; +#else + nPort.cgPort.window = _eventHandler->platformWindow([self currentWindow]); +#endif /* NP_NO_CARBON */ + nPort.cgPort.context = context; + window.window = &nPort.cgPort; + + // 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: + window.window = [self currentWindow]; + // 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); + ASSERT(((PortState_CG *)portState)->context == nPort.cgPort.context); + CGContextRestoreGState(nPort.cgPort.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; + + bool wasDeferring = page->defersLoading(); + if (!wasDeferring) + page->setDefersLoading(true); + + // 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]; + { + JSC::JSLock::DropAllLocks dropAllLocks(false); + acceptedEvent = ![_pluginPackage.get() pluginFuncs]->event(plugin, event); + } + [self didCallPlugInFunction]; + + if (portState) { + if ([self currentWindow]) + [self restorePortState:portState]; + if (portState != (PortState)1) + free(portState); + } + + if (!wasDeferring) + page->setDefersLoading(false); + + return acceptedEvent; +} + +- (void)windowFocusChanged:(BOOL)hasFocus +{ + _eventHandler->windowFocusChanged(hasFocus); +} + +- (void)sendDrawRectEvent:(NSRect)rect +{ + ASSERT(_eventHandler); + + _eventHandler->drawRect(rect); +} + +- (void)stopTimers +{ + [super stopTimers]; + + if (_eventHandler) + _eventHandler->stopTimers(); + + if (!timers) + return; + + HashMap<uint32, PluginTimer*>::const_iterator end = timers->end(); + for (HashMap<uint32, 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, PluginTimer*>::const_iterator end = timers->end(); + for (HashMap<uint32, 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)mouseEntered:(NSEvent *)theEvent +{ + if (!_isStarted) + return; + + _eventHandler->mouseEntered(theEvent); +} + +- (void)mouseExited:(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]; +} + +// We can't name this method mouseMoved because we don't want to override +// the NSView mouseMoved implementation. +- (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); +} + +#pragma 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. QuickDraw plug-ins are an important + // excpetion to rule (3) because they manually must be 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. + if (!_isStarted) + return; + +#ifdef NP_NO_QUICKDRAW + if (![self canDraw]) + return; +#else + if (drawingModel == NPDrawingModelQuickDraw) + [self tellQuickTimeToChill]; + else if (drawingModel == NPDrawingModelCoreGraphics && ![self canDraw]) + 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); + } + 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; + + // A CoreGraphics plugin's window may only be set while the plugin is being updated + ASSERT((drawingModel != NPDrawingModelCoreGraphics) || [NSView focusView] == self); + + [self willCallPlugInFunction]; + { + JSC::JSLock::DropAllLocks dropAllLocks(false); + 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", + npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height); + 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); + [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)); + + // Get the text input vtable + if (eventModel == NPEventModelCocoa) { + [self willCallPlugInFunction]; + { + JSC::JSLock::DropAllLocks dropAllLocks(false); + NPPluginTextInputFuncs *value = 0; + if (![_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginTextInputFuncs, &value) == NPERR_NO_ERROR && value) + textInputFuncs = value; + } + [self didCallPlugInFunction]; + } + + return YES; +} + +#ifndef BUILDING_ON_TIGER +- (void)setLayer:(CALayer *)newLayer +{ + [super setLayer:newLayer]; + + if (_pluginLayer) + [newLayer addSublayer:_pluginLayer.get()]; +} +#endif + +- (void)loadStream +{ + 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(); + + textInputFuncs = 0; +} + +- (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() bundle] bundleIdentifier] isEqualToString:@"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++; + } +} + +#pragma 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 + DOMElement:(DOMElement *)element +{ + self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually DOMElement: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; + } +} + +- (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 (drawingModel == NPDrawingModelCoreAnimation) + return; + + if (!_isStarted) + return; + + if ([NSGraphicsContext currentContextDrawingToScreen]) + [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(false); + 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()) { + + _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); +} + +#pragma mark NSTextInput implementation + +- (NSTextInputContext *)inputContext +{ +#ifndef NP_NO_CARBON + if (!_isStarted || eventModel == NPEventModelCarbon) + return nil; +#endif + + return [super inputContext]; +} + +- (BOOL)hasMarkedText +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->hasMarkedText) + return textInputFuncs->hasMarkedText(plugin); + + return NO; +} + +- (void)insertText:(id)aString +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->insertText) + textInputFuncs->insertText(plugin, aString); +} + +- (NSRange)markedRange +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->markedRange) + return textInputFuncs->markedRange(plugin); + + return NSMakeRange(NSNotFound, 0); +} + +- (NSRange)selectedRange +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->selectedRange) + return textInputFuncs->selectedRange(plugin); + + return NSMakeRange(NSNotFound, 0); +} + +- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->setMarkedText) + textInputFuncs->setMarkedText(plugin, aString, selRange); +} + +- (void)unmarkText +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->unmarkText) + textInputFuncs->unmarkText(plugin); +} + +- (NSArray *)validAttributesForMarkedText +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->validAttributesForMarkedText) + return textInputFuncs->validAttributesForMarkedText(plugin); + + return [NSArray array]; +} + +- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->attributedSubstringFromRange) + return textInputFuncs->attributedSubstringFromRange(plugin, theRange); + + return nil; +} + +- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->characterIndexForPoint) { + // Convert the point to window coordinates + NSPoint point = [[self window] convertScreenToBase:thePoint]; + + // And view coordinates + point = [self convertPoint:point fromView:nil]; + + return textInputFuncs->characterIndexForPoint(plugin, point); + } + + return NSNotFound; +} + +- (void)doCommandBySelector:(SEL)aSelector +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->doCommandBySelector) + textInputFuncs->doCommandBySelector(plugin, aSelector); +} + +- (NSRect)firstRectForCharacterRange:(NSRange)theRange +{ + ASSERT(eventModel == NPEventModelCocoa); + ASSERT(_isStarted); + + if (textInputFuncs && textInputFuncs->firstRectForCharacterRange) { + NSRect rect = textInputFuncs->firstRectForCharacterRange(plugin, theRange); + + // Convert the rect to window coordinates + rect = [self convertRect:rect toView:nil]; + + // Convert the rect location to screen coordinates + rect.origin = [[self window] convertBaseToScreen:rect.origin]; + + return rect; + } + + return NSZeroRect; +} + +// test for 10.4 because of <rdar://problem/4243463> +#ifdef BUILDING_ON_TIGER +- (long)conversationIdentifier +{ + return (long)self; +} +#else +- (NSInteger)conversationIdentifier +{ + return (NSInteger)self; +} +#endif + +@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(false); + [_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(false); + [_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(false); + [_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 (!FrameLoader::canLoad(URL, String(), core([self webFrame])->document())) + 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 +{ + if (!message) { + LOG_ERROR("NPN_Status passed a NULL status message"); + return; + } + + CFStringRef status = CFStringCreateWithCString(NULL, 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 setNeedsDisplayInRect:NSMakeRect(invalidRect->left, invalidRect->top, + (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)]; +} + +-(BOOL)isOpaque +{ + return YES; +} + +- (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 setNeedsDisplayInRect:invalidRect]; +} + +-(void)forceRedraw +{ + LOG(Plugins, "forceRedraw"); + [self setNeedsDisplay:YES]; + [[self window] displayIfNeeded]; +} + +static NPBrowserTextInputFuncs *browserTextInputFuncs() +{ + static NPBrowserTextInputFuncs inputFuncs = { + 0, + sizeof(NPBrowserTextInputFuncs), + NPN_MarkedTextAbandoned, + NPN_MarkedTextSelectionChanged + }; + + return &inputFuncs; +} + +- (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 = (NPObject *)[_element.get() _NPObject]; + + // 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 NPNVbrowserTextInputFuncs: + { + if (eventModel == NPEventModelCocoa) { + *(NPBrowserTextInputFuncs **)value = browserTextInputFuncs(); + return NPERR_NO_ERROR; + } + } + 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)scheduleTimerWithInterval:(uint32)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32 timerID))timerFunc +{ + if (!timerFunc) + return 0; + + if (!timers) + timers = new HashMap<uint32, PluginTimer*>; + + uint32 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)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; +} + +@end + +@implementation WebNetscapePluginView (Internal) + +- (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); + + _isSilverlight = [[[_pluginPackage.get() bundle] bundleIdentifier] isEqualToString:@"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]; + LOG(Plugins, "NPP_New: %d", npErr); + return npErr; +} + +- (void)_destroyPlugin +{ + PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin); + + 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(false); + [_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 diff --git a/WebKit/mac/Plugins/WebPluginController.mm b/WebKit/mac/Plugins/WebPluginController.mm index d892d4a..b618bd6 100644 --- a/WebKit/mac/Plugins/WebPluginController.mm +++ b/WebKit/mac/Plugins/WebPluginController.mm @@ -335,7 +335,7 @@ static void cancelOutstandingCheck(const void *item, void *context) LOG_ERROR("could not load URL %@", [request URL]); return; } - core(frame)->loader()->load(request, target); + core(frame)->loader()->load(request, target, false); } } diff --git a/WebKit/mac/Plugins/WebPluginDatabase.mm b/WebKit/mac/Plugins/WebPluginDatabase.mm index 531214e..4f2bdd8 100644 --- a/WebKit/mac/Plugins/WebPluginDatabase.mm +++ b/WebKit/mac/Plugins/WebPluginDatabase.mm @@ -28,20 +28,20 @@ #import "WebPluginDatabase.h" +#import "WebBaseNetscapePluginView.h" #import "WebBasePluginPackage.h" #import "WebDataSourcePrivate.h" #import "WebFrame.h" #import "WebFrameViewInternal.h" #import "WebHTMLRepresentation.h" #import "WebHTMLView.h" +#import "WebHTMLView.h" #import "WebKitLogging.h" -#import "WebNetscapePluginPackage.h" #import "WebNSFileManagerExtras.h" +#import "WebNetscapePluginPackage.h" #import "WebPluginController.h" -#import "WebBaseNetscapePluginView.h" #import "WebPluginPackage.h" #import "WebViewPrivate.h" -#import "WebHTMLView.h" #import <WebKitSystemInterface.h> #import <wtf/Assertions.h> diff --git a/WebKit/mac/Plugins/WebPlugInStreamLoaderDelegate.h b/WebKit/mac/Plugins/WebPluginRequest.h index c21fe4c..5336dcb 100644 --- a/WebKit/mac/Plugins/WebPlugInStreamLoaderDelegate.h +++ b/WebKit/mac/Plugins/WebPluginRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * 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 @@ -26,23 +26,25 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -@class NSURLResponse; -@class NSError; -@class NSData; +#if ENABLE(NETSCAPE_PLUGIN_API) -@protocol WebPlugInStreamLoaderDelegate +@interface WebPluginRequest : NSObject +{ + NSURLRequest *_request; + NSString *_frameName; + void *_notifyData; + BOOL _didStartFromUserGesture; + BOOL _sendNotification; +} -- (void)startStreamWithResponse:(NSURLResponse *)r; +- (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture; -// destroyStreamWithError tells the plug-in that the load is completed (error == nil) or ended in error. -- (void)destroyStreamWithError:(NSError *)error; - -// cancelLoadAndDestoryStreamWithError calls cancelLoadWithError: then destroyStreamWithError:. -- (void)cancelLoadAndDestroyStreamWithError:(NSError *)error; - -- (void)receivedData:(NSData *)data; -- (void)finishedLoading; - -- (BOOL)wantsAllStreams; +- (NSURLRequest *)request; +- (NSString *)frameName; +- (void *)notifyData; +- (BOOL)isCurrentEventUserGesture; +- (BOOL)sendNotification; @end + +#endif // ENABLE(NETSCAPE_PLUGIN_API) diff --git a/WebKit/mac/Plugins/WebPluginRequest.m b/WebKit/mac/Plugins/WebPluginRequest.m new file mode 100644 index 0000000..df36d40 --- /dev/null +++ b/WebKit/mac/Plugins/WebPluginRequest.m @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#if ENABLE(NETSCAPE_PLUGIN_API) + +#import "WebPluginRequest.h" + +@implementation WebPluginRequest + +- (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture +{ + [super init]; + _didStartFromUserGesture = currentEventIsUserGesture; + _request = [request retain]; + _frameName = [frameName retain]; + _notifyData = notifyData; + _sendNotification = sendNotification; + return self; +} + +- (void)dealloc +{ + [_request release]; + [_frameName release]; + [super dealloc]; +} + +- (NSURLRequest *)request +{ + return _request; +} + +- (NSString *)frameName +{ + return _frameName; +} + +- (BOOL)isCurrentEventUserGesture +{ + return _didStartFromUserGesture; +} + +- (BOOL)sendNotification +{ + return _sendNotification; +} + +- (void *)notifyData +{ + return _notifyData; +} + +@end + +#endif // ENABLE(NETSCAPE_PLUGIN_API) diff --git a/WebKit/mac/Plugins/npapi.mm b/WebKit/mac/Plugins/npapi.mm index f85ec9f..eb32c2b 100644 --- a/WebKit/mac/Plugins/npapi.mm +++ b/WebKit/mac/Plugins/npapi.mm @@ -30,13 +30,13 @@ #import <WebKit/npapi.h> #import <WebKit/nptextinput.h> -#import "WebBaseNetscapePluginView.h" +#import "WebNetscapePluginView.h" #import "WebKitLogging.h" #import <WebCore/PluginMainThreadScheduler.h> using namespace WebCore; -WebBaseNetscapePluginView *pluginViewForInstance(NPP instance); +WebNetscapePluginView *pluginViewForInstance(NPP instance); // general plug-in to browser functions @@ -70,14 +70,14 @@ NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList) // instance-specific functions // The plugin view is always the ndata of the instance. Sometimes, plug-ins will call an instance-specific function // with a NULL instance. To workaround this, call the last plug-in view that made a call to a plug-in. -// Currently, the current plug-in view is only set before NPP_New in [WebBaseNetscapePluginView start]. +// Currently, the current plug-in view is only set before NPP_New in [WebNetscapePluginView start]. // This specifically works around Flash and Shockwave. When we call NPP_New, they call NPN_UserAgent with a NULL instance. -WebBaseNetscapePluginView *pluginViewForInstance(NPP instance) +WebNetscapePluginView *pluginViewForInstance(NPP instance) { if (instance && instance->ndata) - return (WebBaseNetscapePluginView *)instance->ndata; + return (WebNetscapePluginView *)instance->ndata; else - return [WebBaseNetscapePluginView currentPluginView]; + return [WebNetscapePluginView currentPluginView]; } NPError NPN_GetURLNotify(NPP instance, const char* URL, const char* target, void* notifyData) @@ -194,14 +194,14 @@ NPError NPN_PopUpContextMenu(NPP instance, NPMenu *menu) void NPN_MarkedTextAbandoned(NPP instance) { - WebBaseNetscapePluginView *pluginView = pluginViewForInstance(instance); + WebNetscapePluginView *pluginView = pluginViewForInstance(instance); [[NSInputManager currentInputManager] markedTextAbandoned:pluginView]; } void NPN_MarkedTextSelectionChanged(NPP instance, NSRange newSel) { - WebBaseNetscapePluginView *pluginView = pluginViewForInstance(instance); + WebNetscapePluginView *pluginView = pluginViewForInstance(instance); [[NSInputManager currentInputManager] markedTextSelectionChanged:newSel client:pluginView]; } |
