webengine/osswebengine/WebKit/Plugins/WebBaseNetscapePluginView.mm
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer. 
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution. 
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #ifndef __LP64__
       
    30 
       
    31 #import "WebBaseNetscapePluginView.h"
       
    32 
       
    33 #import "WebDataSourceInternal.h"
       
    34 #import "WebDefaultUIDelegate.h"
       
    35 #import "WebFrameBridge.h"
       
    36 #import "WebFrameInternal.h" 
       
    37 #import "WebFrameView.h"
       
    38 #import "WebGraphicsExtras.h"
       
    39 #import "WebKitLogging.h"
       
    40 #import "WebKitNSStringExtras.h"
       
    41 #import "WebKitSystemInterface.h"
       
    42 #import "WebNSDataExtras.h"
       
    43 #import "WebNSDictionaryExtras.h"
       
    44 #import "WebNSObjectExtras.h"
       
    45 #import "WebNSURLExtras.h"
       
    46 #import "WebNSURLRequestExtras.h"
       
    47 #import "WebNSViewExtras.h"
       
    48 #import "WebNetscapePluginPackage.h"
       
    49 #import "WebNetscapePluginStream.h"
       
    50 #import "WebNullPluginView.h"
       
    51 #import "WebPreferences.h"
       
    52 #import "WebViewInternal.h"
       
    53 #import <Carbon/Carbon.h>
       
    54 #import <JavaScriptCore/Assertions.h>
       
    55 #import <JavaScriptCore/JSLock.h>
       
    56 #import <JavaScriptCore/npruntime_impl.h>
       
    57 #import <WebCore/Document.h>
       
    58 #import <WebCore/Element.h>
       
    59 #import <WebCore/Frame.h> 
       
    60 #import <WebCore/FrameLoader.h> 
       
    61 #import <WebCore/FrameTree.h> 
       
    62 #import <WebCore/Page.h> 
       
    63 #import <WebCore/SoftLinking.h> 
       
    64 #import <WebCore/WebCoreObjCExtras.h>
       
    65 #import <WebKit/DOMPrivate.h>
       
    66 #import <WebKit/WebUIDelegate.h>
       
    67 #import <objc/objc-runtime.h>
       
    68 
       
    69 using namespace WebCore;
       
    70 
       
    71 // Send null events 50 times a second when active, so plug-ins like Flash get high frame rates.
       
    72 #define NullEventIntervalActive         0.02
       
    73 #define NullEventIntervalNotActive      0.25
       
    74 
       
    75 #define LoginWindowDidSwitchFromUserNotification    @"WebLoginWindowDidSwitchFromUserNotification"
       
    76 #define LoginWindowDidSwitchToUserNotification      @"WebLoginWindowDidSwitchToUserNotification"
       
    77 
       
    78 SOFT_LINK_FRAMEWORK(OpenGL)
       
    79 SOFT_LINK_FRAMEWORK(AGL)
       
    80 
       
    81 SOFT_LINK(OpenGL, CGLGetOffScreen, CGLError, (CGLContextObj ctx, GLsizei *width, GLsizei *height, GLint *rowbytes, void **baseaddr), (ctx, width, height, rowbytes, baseaddr))
       
    82 SOFT_LINK(OpenGL, CGLSetOffScreen, CGLError, (CGLContextObj ctx, GLsizei width, GLsizei height, GLint rowbytes, void *baseaddr), (ctx, width, height, rowbytes, baseaddr))
       
    83 SOFT_LINK(OpenGL, glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height), (x, y, width, height))
       
    84 SOFT_LINK(AGL, aglCreateContext, AGLContext, (AGLPixelFormat pix, AGLContext share), (pix, share))
       
    85 SOFT_LINK(AGL, aglSetWindowRef, GLboolean, (AGLContext ctx, WindowRef window), (ctx, window))
       
    86 SOFT_LINK(AGL, aglSetDrawable, GLboolean, (AGLContext ctx, AGLDrawable draw), (ctx, draw))
       
    87 #ifndef BUILDING_ON_TIGER
       
    88 SOFT_LINK(AGL, aglChoosePixelFormat, AGLPixelFormat, (const void *gdevs, GLint ndev, const GLint *attribs), (gdevs, ndev, attribs))
       
    89 #else
       
    90 SOFT_LINK(AGL, aglChoosePixelFormat, AGLPixelFormat, (const AGLDevice *gdevs, GLint ndev, const GLint *attribs), (gdevs, ndev, attribs))
       
    91 #endif
       
    92 SOFT_LINK(AGL, aglDestroyPixelFormat, void, (AGLPixelFormat pix), (pix))
       
    93 SOFT_LINK(AGL, aglDestroyContext, GLboolean, (AGLContext ctx), (ctx))
       
    94 SOFT_LINK(AGL, aglGetCGLContext, GLboolean, (AGLContext ctx, void **cgl_ctx), (ctx, cgl_ctx))
       
    95 SOFT_LINK(AGL, aglGetCurrentContext, AGLContext, (void), ())
       
    96 SOFT_LINK(AGL, aglSetCurrentContext, GLboolean, (AGLContext ctx), (ctx))
       
    97 SOFT_LINK(AGL, aglGetError, GLenum, (void), ())
       
    98 SOFT_LINK(AGL, aglUpdateContext, GLboolean, (AGLContext ctx), (ctx))
       
    99 SOFT_LINK(AGL, aglErrorString, const GLubyte *, (GLenum code), (code))
       
   100 
       
   101 @interface WebBaseNetscapePluginView (Internal)
       
   102 - (void)_viewHasMoved;
       
   103 - (NPError)_createPlugin;
       
   104 - (void)_destroyPlugin;
       
   105 - (NSBitmapImageRep *)_printedPluginBitmap;
       
   106 - (BOOL)_createAGLContextIfNeeded;
       
   107 - (BOOL)_createWindowedAGLContext;
       
   108 - (BOOL)_createWindowlessAGLContext;
       
   109 - (CGLContextObj)_cglContext;
       
   110 - (BOOL)_getAGLOffscreenBuffer:(GLvoid **)outBuffer width:(GLsizei *)outWidth height:(GLsizei *)outHeight;
       
   111 - (void)_destroyAGLContext;
       
   112 - (void)_reshapeAGLWindow;
       
   113 - (void)_hideAGLWindow;
       
   114 - (NSImage *)_aglOffscreenImageForDrawingInRect:(NSRect)drawingInRect;
       
   115 - (void)_redeliverStream;
       
   116 @end
       
   117 
       
   118 static WebBaseNetscapePluginView *currentPluginView = nil;
       
   119 
       
   120 typedef struct OpaquePortState* PortState;
       
   121 
       
   122 #ifndef NP_NO_QUICKDRAW
       
   123 
       
   124 // QuickDraw is not available in 64-bit
       
   125 
       
   126 typedef struct {
       
   127     GrafPtr oldPort;
       
   128     GDHandle oldDevice;
       
   129     Point oldOrigin;
       
   130     RgnHandle oldClipRegion;
       
   131     RgnHandle oldVisibleRegion;
       
   132     RgnHandle clipRegion;
       
   133     BOOL forUpdate;
       
   134 } PortState_QD;
       
   135 
       
   136 #endif /* NP_NO_QUICKDRAW */
       
   137 
       
   138 typedef struct {
       
   139     CGContextRef context;
       
   140 } PortState_CG;
       
   141 
       
   142 typedef struct {
       
   143     AGLContext oldContext;
       
   144 } PortState_GL;
       
   145 
       
   146 @interface WebPluginRequest : NSObject
       
   147 {
       
   148     NSURLRequest *_request;
       
   149     NSString *_frameName;
       
   150     void *_notifyData;
       
   151     BOOL _didStartFromUserGesture;
       
   152     BOOL _sendNotification;
       
   153 }
       
   154 
       
   155 - (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture;
       
   156 
       
   157 - (NSURLRequest *)request;
       
   158 - (NSString *)frameName;
       
   159 - (void *)notifyData;
       
   160 - (BOOL)isCurrentEventUserGesture;
       
   161 - (BOOL)sendNotification;
       
   162 
       
   163 @end
       
   164 
       
   165 @interface NSData (WebPluginDataExtras)
       
   166 - (BOOL)_web_startsWithBlankLine;
       
   167 - (NSInteger)_web_locationAfterFirstBlankLine;
       
   168 @end
       
   169 
       
   170 static OSStatus TSMEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *pluginView);
       
   171 
       
   172 @interface WebBaseNetscapePluginView (ForwardDeclarations)
       
   173 - (void)setWindowIfNecessary;
       
   174 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification;
       
   175 @end
       
   176 
       
   177 @implementation WebBaseNetscapePluginView
       
   178 
       
   179 + (void)initialize
       
   180 {
       
   181 #ifndef BUILDING_ON_TIGER
       
   182     WebCoreObjCFinalizeOnMainThread(self);
       
   183 #endif
       
   184     WKSendUserChangeNotifications();
       
   185 }
       
   186 
       
   187 #pragma mark EVENTS
       
   188 
       
   189 + (void)getCarbonEvent:(EventRecord *)carbonEvent
       
   190 {
       
   191     carbonEvent->what = nullEvent;
       
   192     carbonEvent->message = 0;
       
   193     carbonEvent->when = TickCount();
       
   194     
       
   195     GetGlobalMouse(&carbonEvent->where);
       
   196     carbonEvent->where.h = static_cast<short>(carbonEvent->where.h * HIGetScaleFactor());
       
   197     carbonEvent->where.v = static_cast<short>(carbonEvent->where.v * HIGetScaleFactor());
       
   198     carbonEvent->modifiers = GetCurrentKeyModifiers();
       
   199     if (!Button())
       
   200         carbonEvent->modifiers |= btnState;
       
   201 }
       
   202 
       
   203 - (void)getCarbonEvent:(EventRecord *)carbonEvent
       
   204 {
       
   205     [[self class] getCarbonEvent:carbonEvent];
       
   206 }
       
   207 
       
   208 - (EventModifiers)modifiersForEvent:(NSEvent *)event
       
   209 {
       
   210     EventModifiers modifiers;
       
   211     unsigned int modifierFlags = [event modifierFlags];
       
   212     NSEventType eventType = [event type];
       
   213     
       
   214     modifiers = 0;
       
   215     
       
   216     if (eventType != NSLeftMouseDown && eventType != NSRightMouseDown)
       
   217         modifiers |= btnState;
       
   218     
       
   219     if (modifierFlags & NSCommandKeyMask)
       
   220         modifiers |= cmdKey;
       
   221     
       
   222     if (modifierFlags & NSShiftKeyMask)
       
   223         modifiers |= shiftKey;
       
   224 
       
   225     if (modifierFlags & NSAlphaShiftKeyMask)
       
   226         modifiers |= alphaLock;
       
   227 
       
   228     if (modifierFlags & NSAlternateKeyMask)
       
   229         modifiers |= optionKey;
       
   230 
       
   231     if (modifierFlags & NSControlKeyMask || eventType == NSRightMouseDown)
       
   232         modifiers |= controlKey;
       
   233     
       
   234     return modifiers;
       
   235 }
       
   236 
       
   237 - (void)getCarbonEvent:(EventRecord *)carbonEvent withEvent:(NSEvent *)cocoaEvent
       
   238 {
       
   239     if (WKConvertNSEventToCarbonEvent(carbonEvent, cocoaEvent)) {
       
   240         carbonEvent->where.h = static_cast<short>(carbonEvent->where.h * HIGetScaleFactor());
       
   241         carbonEvent->where.v = static_cast<short>(carbonEvent->where.v * HIGetScaleFactor());
       
   242         return;
       
   243     }
       
   244     
       
   245     NSPoint where = [[cocoaEvent window] convertBaseToScreen:[cocoaEvent locationInWindow]];
       
   246         
       
   247     carbonEvent->what = nullEvent;
       
   248     carbonEvent->message = 0;
       
   249     carbonEvent->when = (UInt32)([cocoaEvent timestamp] * 60); // seconds to ticks
       
   250     carbonEvent->where.h = (short)where.x;
       
   251     carbonEvent->where.v = (short)(NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - where.y);
       
   252     carbonEvent->modifiers = [self modifiersForEvent:cocoaEvent];
       
   253 }
       
   254 
       
   255 - (BOOL)superviewsHaveSuperviews
       
   256 {
       
   257     NSView *contentView = [[self window] contentView];
       
   258     NSView *view;
       
   259     for (view = self; view != nil; view = [view superview]) { 
       
   260         if (view == contentView) {
       
   261             return YES;
       
   262         }
       
   263     }
       
   264     return NO;
       
   265 }
       
   266 
       
   267 #ifndef NP_NO_QUICKDRAW
       
   268 
       
   269 // The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers 
       
   270 // the entire window frame (or structure region to use the Carbon term) rather then just the window content.
       
   271 // We can remove this when <rdar://problem/4201099> is fixed.
       
   272 - (void)fixWindowPort
       
   273 {
       
   274     ASSERT(drawingModel == NPDrawingModelQuickDraw);
       
   275     
       
   276     NSWindow *currentWindow = [self currentWindow];
       
   277     if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")])
       
   278         return;
       
   279     
       
   280     float windowHeight = [currentWindow frame].size.height;
       
   281     NSView *contentView = [currentWindow contentView];
       
   282     NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates
       
   283     
       
   284     CGrafPtr oldPort;
       
   285     GetPort(&oldPort);    
       
   286     SetPort(GetWindowPort((WindowRef)[currentWindow windowRef]));
       
   287     
       
   288     MovePortTo(static_cast<short>(contentRect.origin.x), /* Flip Y */ static_cast<short>(windowHeight - NSMaxY(contentRect)));
       
   289     PortSize(static_cast<short>(contentRect.size.width), static_cast<short>(contentRect.size.height));
       
   290     
       
   291     SetPort(oldPort);
       
   292 }
       
   293 
       
   294 static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context)
       
   295 {
       
   296     UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) & kCGBitmapByteOrderMask;
       
   297     if (byteOrder == kCGBitmapByteOrderDefault)
       
   298         switch (CGBitmapContextGetBitsPerPixel(context)) {
       
   299             case 16:
       
   300                 byteOrder = kCGBitmapByteOrder16Host;
       
   301                 break;
       
   302             case 32:
       
   303                 byteOrder = kCGBitmapByteOrder32Host;
       
   304                 break;
       
   305         }
       
   306     switch (byteOrder) {
       
   307         case kCGBitmapByteOrder16Little:
       
   308             return k16LE555PixelFormat;
       
   309         case kCGBitmapByteOrder32Little:
       
   310             return k32BGRAPixelFormat;
       
   311         case kCGBitmapByteOrder16Big:
       
   312             return k16BE555PixelFormat;
       
   313         case kCGBitmapByteOrder32Big:
       
   314             return k32ARGBPixelFormat;
       
   315     }
       
   316     ASSERT_NOT_REACHED();
       
   317     return 0;
       
   318 }
       
   319 
       
   320 static inline void getNPRect(const CGRect& cgr, NPRect& npr)
       
   321 {
       
   322     npr.top = static_cast<uint16>(cgr.origin.y);
       
   323     npr.left = static_cast<uint16>(cgr.origin.x);
       
   324     npr.bottom = static_cast<uint16>(CGRectGetMaxY(cgr));
       
   325     npr.right = static_cast<uint16>(CGRectGetMaxX(cgr));
       
   326 }
       
   327 
       
   328 #endif
       
   329 
       
   330 static inline void getNPRect(const NSRect& nr, NPRect& npr)
       
   331 {
       
   332     npr.top = static_cast<uint16>(nr.origin.y);
       
   333     npr.left = static_cast<uint16>(nr.origin.x);
       
   334     npr.bottom = static_cast<uint16>(NSMaxY(nr));
       
   335     npr.right = static_cast<uint16>(NSMaxX(nr));
       
   336 }
       
   337 
       
   338 - (NSRect)visibleRect
       
   339 {
       
   340     // WebCore may impose an additional clip (via CSS overflow or clip properties).  Fetch
       
   341     // that clip now.    
       
   342     return NSIntersectionRect([self convertRect:[element _windowClipRect] fromView:nil], [super visibleRect]);
       
   343 }
       
   344 
       
   345 - (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate
       
   346 {
       
   347     ASSERT([self currentWindow] != nil);
       
   348 
       
   349 #ifndef NP_NO_QUICKDRAW
       
   350     // If drawing with QuickDraw, fix the window port so that it has the same bounds as the NSWindow's
       
   351     // content view.  This makes it easier to convert between AppKit view and QuickDraw port coordinates.
       
   352     if (drawingModel == NPDrawingModelQuickDraw)
       
   353         [self fixWindowPort];
       
   354 #endif
       
   355 
       
   356     WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
       
   357     ASSERT(windowRef);
       
   358     
       
   359     // Use AppKit to convert view coordinates to NSWindow coordinates.
       
   360     NSRect boundsInWindow = [self convertRect:[self bounds] toView:nil];
       
   361     NSRect visibleRectInWindow = [self convertRect:[self visibleRect] toView:nil];
       
   362     
       
   363     // Flip Y to convert NSWindow coordinates to top-left-based window coordinates.
       
   364     float borderViewHeight = [[self currentWindow] frame].size.height;
       
   365     boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow);
       
   366     visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow);
       
   367     
       
   368 #ifndef NP_NO_QUICKDRAW
       
   369     // Look at the Carbon port to convert top-left-based window coordinates into top-left-based content coordinates.
       
   370     if (drawingModel == NPDrawingModelQuickDraw) {
       
   371         ::Rect portBounds;
       
   372         CGrafPtr port = GetWindowPort(windowRef);
       
   373         GetPortBounds(port, &portBounds);
       
   374 
       
   375         PixMap *pix = *GetPortPixMap(port);
       
   376         boundsInWindow.origin.x += pix->bounds.left - portBounds.left;
       
   377         boundsInWindow.origin.y += pix->bounds.top - portBounds.top;
       
   378         visibleRectInWindow.origin.x += pix->bounds.left - portBounds.left;
       
   379         visibleRectInWindow.origin.y += pix->bounds.top - portBounds.top;
       
   380     }
       
   381 #endif
       
   382     
       
   383     window.x = (int32)boundsInWindow.origin.x; 
       
   384     window.y = (int32)boundsInWindow.origin.y;
       
   385     window.width = static_cast<uint32>(NSWidth(boundsInWindow));
       
   386     window.height = static_cast<uint32>(NSHeight(boundsInWindow));
       
   387     
       
   388     // "Clip-out" the plug-in when:
       
   389     // 1) it's not really in a window or off-screen or has no height or width.
       
   390     // 2) window.x is a "big negative number" which is how WebCore expresses off-screen widgets.
       
   391     // 3) the window is miniaturized or the app is hidden
       
   392     // 4) we're inside of viewWillMoveToWindow: with a nil window. In this case, superviews may already have nil 
       
   393     // superviews and nil windows and results from convertRect:toView: are incorrect.
       
   394     NSWindow *realWindow = [self window];
       
   395     if (window.width <= 0 || window.height <= 0 || window.x < -100000
       
   396             || realWindow == nil || [realWindow isMiniaturized]
       
   397             || [NSApp isHidden]
       
   398             || ![self superviewsHaveSuperviews]
       
   399             || [self isHiddenOrHasHiddenAncestor]) {
       
   400 
       
   401         // The following code tries to give plug-ins the same size they will eventually have.
       
   402         // The specifiedWidth and specifiedHeight variables are used to predict the size that
       
   403         // WebCore will eventually resize us to.
       
   404 
       
   405         // The QuickTime plug-in has problems if you give it a width or height of 0.
       
   406         // Since other plug-ins also might have the same sort of trouble, we make sure
       
   407         // to always give plug-ins a size other than 0,0.
       
   408 
       
   409         if (window.width <= 0)
       
   410             window.width = specifiedWidth > 0 ? specifiedWidth : 100;
       
   411         if (window.height <= 0)
       
   412             window.height = specifiedHeight > 0 ? specifiedHeight : 100;
       
   413 
       
   414         window.clipRect.bottom = window.clipRect.top;
       
   415         window.clipRect.left = window.clipRect.right;
       
   416     } else {
       
   417         getNPRect(visibleRectInWindow, window.clipRect);
       
   418     }
       
   419     
       
   420     // Save the port state, set up the port for entry into the plugin
       
   421     PortState portState;
       
   422     switch (drawingModel) {
       
   423 #ifndef NP_NO_QUICKDRAW
       
   424         case NPDrawingModelQuickDraw: {
       
   425             // Set up NS_Port.
       
   426             ::Rect portBounds;
       
   427             CGrafPtr port = GetWindowPort(windowRef);
       
   428             GetPortBounds(port, &portBounds);
       
   429             nPort.qdPort.port = port;
       
   430             nPort.qdPort.portx = (int32)-boundsInWindow.origin.x;
       
   431             nPort.qdPort.porty = (int32)-boundsInWindow.origin.y;
       
   432             window.window = &nPort;
       
   433 
       
   434             PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD));
       
   435             portState = (PortState)qdPortState;
       
   436             
       
   437             GetGWorld(&qdPortState->oldPort, &qdPortState->oldDevice);    
       
   438 
       
   439             qdPortState->oldOrigin.h = portBounds.left;
       
   440             qdPortState->oldOrigin.v = portBounds.top;
       
   441 
       
   442             qdPortState->oldClipRegion = NewRgn();
       
   443             GetPortClipRegion(port, qdPortState->oldClipRegion);
       
   444             
       
   445             qdPortState->oldVisibleRegion = NewRgn();
       
   446             GetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
       
   447             
       
   448             RgnHandle clipRegion = NewRgn();
       
   449             qdPortState->clipRegion = clipRegion;
       
   450 
       
   451             CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
       
   452             if (currentContext && WKCGContextIsBitmapContext(currentContext)) {
       
   453                 // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData
       
   454                 // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext
       
   455                 // returns true, it still might not be a context we need to create a GWorld for; for example
       
   456                 // transparency layers will return true, but return 0 for CGBitmapContextGetData.
       
   457                 void* offscreenData = CGBitmapContextGetData(currentContext);
       
   458                 if (offscreenData) {
       
   459                     // If the current context is an offscreen bitmap, then create a GWorld for it.
       
   460                     ::Rect offscreenBounds;
       
   461                     offscreenBounds.top = 0;
       
   462                     offscreenBounds.left = 0;
       
   463                     offscreenBounds.right = CGBitmapContextGetWidth(currentContext);
       
   464                     offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext);
       
   465                     GWorldPtr newOffscreenGWorld;
       
   466                     QDErr err = NewGWorldFromPtr(&newOffscreenGWorld,
       
   467                         getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0,
       
   468                         static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext));
       
   469                     ASSERT(newOffscreenGWorld && !err);
       
   470                     if (!err) {
       
   471                         if (offscreenGWorld)
       
   472                             DisposeGWorld(offscreenGWorld);
       
   473                         offscreenGWorld = newOffscreenGWorld;
       
   474 
       
   475                         SetGWorld(offscreenGWorld, NULL);
       
   476 
       
   477                         port = offscreenGWorld;
       
   478 
       
   479                         nPort.qdPort.port = port;
       
   480                         boundsInWindow = [self bounds];
       
   481                         
       
   482                         // Generate a QD origin based on the current affine transform for currentContext.
       
   483                         CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext);
       
   484                         CGPoint origin = {0,0};
       
   485                         CGPoint axisFlip = {1,1};
       
   486                         origin = CGPointApplyAffineTransform(origin, offscreenMatrix);
       
   487                         axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix);
       
   488                         
       
   489                         // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that.
       
   490                         origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x);
       
   491                         origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y);
       
   492                         
       
   493                         nPort.qdPort.portx = static_cast<int32>(-boundsInWindow.origin.x + origin.x);
       
   494                         nPort.qdPort.porty = static_cast<int32>(-boundsInWindow.origin.y - origin.y);
       
   495                         window.x = 0;
       
   496                         window.y = 0;
       
   497                         window.window = &nPort;
       
   498 
       
   499                         // Use the clip bounds from the context instead of the bounds we created
       
   500                         // from the window above.
       
   501                         getNPRect(CGContextGetClipBoundingBox(currentContext), window.clipRect);
       
   502                     }
       
   503                 }
       
   504             }
       
   505 
       
   506             MacSetRectRgn(clipRegion,
       
   507                 window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty,
       
   508                 window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty);
       
   509             
       
   510             // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are
       
   511             // not going to be redrawn this update.  This forces plug-ins to play nice with z-index ordering.
       
   512             if (forUpdate) {
       
   513                 RgnHandle viewClipRegion = NewRgn();
       
   514                 
       
   515                 // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
       
   516                 // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
       
   517                 // knows about the true set of dirty rects.
       
   518                 NSView *opaqueAncestor = [self opaqueAncestor];
       
   519                 const NSRect *dirtyRects;
       
   520                 NSInteger dirtyRectCount, dirtyRectIndex;
       
   521                 [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
       
   522 
       
   523                 for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) {
       
   524                     NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor];
       
   525                     if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) {
       
   526                         // Create a region for this dirty rect
       
   527                         RgnHandle dirtyRectRegion = NewRgn();
       
   528                         SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect)));
       
   529                         
       
   530                         // Union this dirty rect with the rest of the dirty rects
       
   531                         UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion);
       
   532                         DisposeRgn(dirtyRectRegion);
       
   533                     }
       
   534                 }
       
   535             
       
   536                 // Intersect the dirty region with the clip region, so that we only draw over dirty parts
       
   537                 SectRgn(clipRegion, viewClipRegion, clipRegion);
       
   538                 DisposeRgn(viewClipRegion);
       
   539             }
       
   540 
       
   541             // Switch to the port and set it up.
       
   542             SetPort(port);
       
   543             PenNormal();
       
   544             ForeColor(blackColor);
       
   545             BackColor(whiteColor);
       
   546             SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty);
       
   547             SetPortClipRegion(nPort.qdPort.port, clipRegion);
       
   548 
       
   549             if (forUpdate) {
       
   550                 // AppKit may have tried to help us by doing a BeginUpdate.
       
   551                 // But the invalid region at that level didn't include AppKit's notion of what was not valid.
       
   552                 // We reset the port's visible region to counteract what BeginUpdate did.
       
   553                 SetPortVisibleRegion(nPort.qdPort.port, clipRegion);
       
   554                 InvalWindowRgn(windowRef, clipRegion);
       
   555             }
       
   556             
       
   557             qdPortState->forUpdate = forUpdate;
       
   558             break;
       
   559         }
       
   560 #endif /* NP_NO_QUICKDRAW */
       
   561 
       
   562         case NPDrawingModelCoreGraphics: {            
       
   563             // A CoreGraphics plugin's window may only be set while the plugin view is being updated
       
   564             ASSERT(forUpdate && [NSView focusView] == self);
       
   565 
       
   566             CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
       
   567 
       
   568             PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG));
       
   569             portState = (PortState)cgPortState;
       
   570             cgPortState->context = context;
       
   571             
       
   572             // Update the plugin's window/context
       
   573             nPort.cgPort.window = windowRef;
       
   574             nPort.cgPort.context = context;
       
   575             window.window = &nPort.cgPort;
       
   576 
       
   577             // Save current graphics context's state; will be restored by -restorePortState:
       
   578             CGContextSaveGState(context);
       
   579             
       
   580             // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
       
   581             // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
       
   582             // knows about the true set of dirty rects.
       
   583             NSView *opaqueAncestor = [self opaqueAncestor];
       
   584             const NSRect *dirtyRects;
       
   585             NSInteger count;
       
   586             [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count];
       
   587             Vector<CGRect, 16> convertedDirtyRects;
       
   588             convertedDirtyRects.resize(count);
       
   589             for (int i = 0; i < count; ++i)
       
   590                 reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor];
       
   591             CGContextClipToRects(context, convertedDirtyRects.data(), count);
       
   592 
       
   593             break;
       
   594         }
       
   595 
       
   596         case NPDrawingModelOpenGL: {
       
   597             // An OpenGL plugin's window may only be set while the plugin view is being updated
       
   598             ASSERT(forUpdate && [NSView focusView] == self);
       
   599 
       
   600             // Clear the "current" window and context -- they will be assigned below (if all goes well)
       
   601             nPort.aglPort.window = NULL;
       
   602             nPort.aglPort.context = NULL;
       
   603             
       
   604             // Create AGL context if needed
       
   605             if (![self _createAGLContextIfNeeded]) {
       
   606                 LOG_ERROR("Could not create AGL context");
       
   607                 return NULL;
       
   608             }
       
   609             
       
   610             // Update the plugin's window/context
       
   611             nPort.aglPort.window = windowRef;
       
   612             nPort.aglPort.context = [self _cglContext];
       
   613             window.window = &nPort.aglPort;
       
   614             
       
   615             // Save/set current AGL context
       
   616             PortState_GL *glPortState = (PortState_GL *)malloc(sizeof(PortState_GL));
       
   617             portState = (PortState)glPortState;
       
   618             glPortState->oldContext = aglGetCurrentContext();
       
   619             aglSetCurrentContext(aglContext);
       
   620             
       
   621             // Adjust viewport according to clip
       
   622             switch (window.type) {
       
   623                 case NPWindowTypeWindow:
       
   624                     glViewport(static_cast<GLint>(NSMinX(boundsInWindow) - NSMinX(visibleRectInWindow)),
       
   625                         static_cast<GLint>(NSMaxY(visibleRectInWindow) - NSMaxY(boundsInWindow)),
       
   626                             window.width, window.height);
       
   627                     break;
       
   628                 
       
   629                 case NPWindowTypeDrawable: {
       
   630                     GLsizei width, height;
       
   631                     if ([self _getAGLOffscreenBuffer:NULL width:&width height:&height])
       
   632                         glViewport(0, 0, width, height);
       
   633                     break;
       
   634                 }
       
   635                 
       
   636                 default:
       
   637                     ASSERT_NOT_REACHED();
       
   638                     break;
       
   639             }
       
   640             break;
       
   641         }
       
   642         
       
   643         default:
       
   644             ASSERT_NOT_REACHED();
       
   645             portState = NULL;
       
   646             break;
       
   647     }
       
   648     
       
   649     return portState;
       
   650 }
       
   651 
       
   652 - (PortState)saveAndSetNewPortState
       
   653 {
       
   654     return [self saveAndSetNewPortStateForUpdate:NO];
       
   655 }
       
   656 
       
   657 - (void)restorePortState:(PortState)portState
       
   658 {
       
   659     ASSERT([self currentWindow]);
       
   660     ASSERT(portState);
       
   661     
       
   662     switch (drawingModel) {
       
   663 #ifndef NP_NO_QUICKDRAW
       
   664         case NPDrawingModelQuickDraw: {
       
   665             PortState_QD *qdPortState = (PortState_QD *)portState;
       
   666             WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
       
   667             CGrafPtr port = GetWindowPort(windowRef);
       
   668 
       
   669             SetPort(port);
       
   670 
       
   671             if (qdPortState->forUpdate)
       
   672                 ValidWindowRgn(windowRef, qdPortState->clipRegion);
       
   673 
       
   674             SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v);
       
   675 
       
   676             SetPortClipRegion(port, qdPortState->oldClipRegion);
       
   677             if (qdPortState->forUpdate)
       
   678                 SetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
       
   679 
       
   680             DisposeRgn(qdPortState->oldClipRegion);
       
   681             DisposeRgn(qdPortState->oldVisibleRegion);
       
   682             DisposeRgn(qdPortState->clipRegion);
       
   683 
       
   684             SetGWorld(qdPortState->oldPort, qdPortState->oldDevice);
       
   685             break;
       
   686         }
       
   687 #endif /* NP_NO_QUICKDRAW */
       
   688         
       
   689         case NPDrawingModelCoreGraphics:
       
   690             ASSERT([NSView focusView] == self);
       
   691             ASSERT(((PortState_CG *)portState)->context == nPort.cgPort.context);
       
   692             CGContextRestoreGState(nPort.cgPort.context);
       
   693             break;
       
   694         
       
   695         case NPDrawingModelOpenGL:
       
   696             aglSetCurrentContext(((PortState_GL *)portState)->oldContext);
       
   697             break;
       
   698         
       
   699         default:
       
   700             ASSERT_NOT_REACHED();
       
   701             break;
       
   702     }
       
   703 }
       
   704 
       
   705 - (BOOL)sendEvent:(EventRecord *)event
       
   706 {
       
   707     if (![self window])
       
   708         return NO;
       
   709     ASSERT(event);
       
   710    
       
   711     // If at any point the user clicks or presses a key from within a plugin, set the 
       
   712     // currentEventIsUserGesture flag to true. This is important to differentiate legitimate 
       
   713     // window.open() calls;  we still want to allow those.  See rdar://problem/4010765
       
   714     if (event->what == mouseDown || event->what == keyDown || event->what == mouseUp || event->what == autoKey)
       
   715         currentEventIsUserGesture = YES;
       
   716     
       
   717     suspendKeyUpEvents = NO;
       
   718     
       
   719     if (!isStarted)
       
   720         return NO;
       
   721 
       
   722     ASSERT(NPP_HandleEvent);
       
   723     
       
   724     // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
       
   725     // We probably don't want more general reentrancy protection; we are really
       
   726     // protecting only against this one case, which actually comes up when
       
   727     // you first install the SVG viewer plug-in.
       
   728     if (inSetWindow)
       
   729         return NO;
       
   730 
       
   731     Frame* frame = core([self webFrame]);
       
   732     if (!frame)
       
   733         return NO;
       
   734     Page* page = frame->page();
       
   735     if (!page)
       
   736         return NO;
       
   737 
       
   738     bool wasDeferring = page->defersLoading();
       
   739     if (!wasDeferring)
       
   740         page->setDefersLoading(true);
       
   741 
       
   742     // Can only send updateEvt to CoreGraphics and OpenGL plugins when actually drawing
       
   743     ASSERT((drawingModel != NPDrawingModelCoreGraphics && drawingModel != NPDrawingModelOpenGL) || event->what != updateEvt || [NSView focusView] == self);
       
   744     
       
   745     BOOL updating = event->what == updateEvt;
       
   746     PortState portState;
       
   747     if ((drawingModel != NPDrawingModelCoreGraphics && drawingModel != NPDrawingModelOpenGL) || event->what == updateEvt) {
       
   748         // In CoreGraphics or OpenGL mode, the port state only needs to be saved/set when redrawing the plug-in view.  The plug-in is not
       
   749         // allowed to draw at any other time.
       
   750         portState = [self saveAndSetNewPortStateForUpdate:updating];
       
   751         
       
   752         // We may have changed the window, so inform the plug-in.
       
   753         [self setWindowIfNecessary];
       
   754     } else
       
   755         portState = NULL;
       
   756     
       
   757 #if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW)
       
   758     // Draw green to help debug.
       
   759     // If we see any green we know something's wrong.
       
   760     // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined.
       
   761     if (drawingModel == NPDrawingModelQuickDraw && !isTransparent && event->what == updateEvt) {
       
   762         ForeColor(greenColor);
       
   763         const ::Rect bigRect = { -10000, -10000, 10000, 10000 };
       
   764         PaintRect(&bigRect);
       
   765         ForeColor(blackColor);
       
   766     }
       
   767 #endif
       
   768     
       
   769     // Temporarily retain self in case the plug-in view is released while sending an event. 
       
   770     [[self retain] autorelease];
       
   771     
       
   772     BOOL acceptedEvent;
       
   773     [self willCallPlugInFunction];
       
   774     {
       
   775         KJS::JSLock::DropAllLocks dropAllLocks;
       
   776         acceptedEvent = NPP_HandleEvent(plugin, event);
       
   777     }
       
   778     [self didCallPlugInFunction];
       
   779     
       
   780     currentEventIsUserGesture = NO;
       
   781     
       
   782     if (portState) {
       
   783         if ([self currentWindow])
       
   784             [self restorePortState:portState];
       
   785         free(portState);
       
   786     }
       
   787 
       
   788     if (!wasDeferring)
       
   789         page->setDefersLoading(false);
       
   790             
       
   791     return acceptedEvent;
       
   792 }
       
   793 
       
   794 - (void)sendActivateEvent:(BOOL)activate
       
   795 {
       
   796     EventRecord event;
       
   797     
       
   798     [self getCarbonEvent:&event];
       
   799     event.what = activateEvt;
       
   800     WindowRef windowRef = (WindowRef)[[self window] windowRef];
       
   801     event.message = (unsigned long)windowRef;
       
   802     if (activate) {
       
   803         event.modifiers |= activeFlag;
       
   804     }
       
   805     
       
   806     BOOL acceptedEvent;
       
   807     acceptedEvent = [self sendEvent:&event]; 
       
   808     
       
   809     LOG(PluginEvents, "NPP_HandleEvent(activateEvent): %d  isActive: %d", acceptedEvent, activate);
       
   810 }
       
   811 
       
   812 - (BOOL)sendUpdateEvent
       
   813 {
       
   814     EventRecord event;
       
   815     
       
   816     [self getCarbonEvent:&event];
       
   817     event.what = updateEvt;
       
   818     WindowRef windowRef = (WindowRef)[[self window] windowRef];
       
   819     event.message = (unsigned long)windowRef;
       
   820 
       
   821     BOOL acceptedEvent = [self sendEvent:&event];
       
   822 
       
   823     LOG(PluginEvents, "NPP_HandleEvent(updateEvt): %d", acceptedEvent);
       
   824 
       
   825     return acceptedEvent;
       
   826 }
       
   827 
       
   828 -(void)sendNullEvent
       
   829 {
       
   830     EventRecord event;
       
   831 
       
   832     [self getCarbonEvent:&event];
       
   833 
       
   834     // Plug-in should not react to cursor position when not active or when a menu is down.
       
   835     MenuTrackingData trackingData;
       
   836     OSStatus error = GetMenuTrackingData(NULL, &trackingData);
       
   837 
       
   838     // Plug-in should not react to cursor position when the actual window is not key.
       
   839     if (![[self window] isKeyWindow] || (error == noErr && trackingData.menu)) {
       
   840         // FIXME: Does passing a v and h of -1 really prevent it from reacting to the cursor position?
       
   841         event.where.v = -1;
       
   842         event.where.h = -1;
       
   843     }
       
   844     
       
   845     [self sendEvent:&event];
       
   846 }
       
   847 
       
   848 - (void)stopNullEvents
       
   849 {
       
   850     [nullEventTimer invalidate];
       
   851     [nullEventTimer release];
       
   852     nullEventTimer = nil;
       
   853 }
       
   854 
       
   855 - (void)restartNullEvents
       
   856 {
       
   857     ASSERT([self window]);
       
   858     
       
   859     if (nullEventTimer)
       
   860         [self stopNullEvents];
       
   861     
       
   862     if (!isStarted || [[self window] isMiniaturized])
       
   863         return;
       
   864 
       
   865     NSTimeInterval interval;
       
   866 
       
   867     // If the plugin is completely obscured (scrolled out of view, for example), then we will
       
   868     // send null events at a reduced rate.
       
   869     interval = !isCompletelyObscured ? NullEventIntervalActive : NullEventIntervalNotActive;    
       
   870     nullEventTimer = [[NSTimer scheduledTimerWithTimeInterval:interval
       
   871                                                        target:self
       
   872                                                      selector:@selector(sendNullEvent)
       
   873                                                      userInfo:nil
       
   874                                                       repeats:YES] retain];
       
   875 }
       
   876 
       
   877 - (BOOL)acceptsFirstResponder
       
   878 {
       
   879     return YES;
       
   880 }
       
   881 
       
   882 - (void)installKeyEventHandler
       
   883 {
       
   884     static const EventTypeSpec sTSMEvents[] =
       
   885     {
       
   886     { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }
       
   887     };
       
   888     
       
   889     if (!keyEventHandler) {
       
   890         InstallEventHandler(GetWindowEventTarget((WindowRef)[[self window] windowRef]),
       
   891                             NewEventHandlerUPP(TSMEventHandler),
       
   892                             GetEventTypeCount(sTSMEvents),
       
   893                             sTSMEvents,
       
   894                             self,
       
   895                             &keyEventHandler);
       
   896     }
       
   897 }
       
   898 
       
   899 - (void)removeKeyEventHandler
       
   900 {
       
   901     if (keyEventHandler) {
       
   902         RemoveEventHandler(keyEventHandler);
       
   903         keyEventHandler = NULL;
       
   904     }
       
   905 }
       
   906 
       
   907 - (void)setHasFocus:(BOOL)flag
       
   908 {
       
   909     if (hasFocus != flag) {
       
   910         hasFocus = flag;
       
   911         EventRecord event;
       
   912         [self getCarbonEvent:&event];
       
   913         BOOL acceptedEvent;
       
   914         if (hasFocus) {
       
   915             event.what = getFocusEvent;
       
   916             acceptedEvent = [self sendEvent:&event]; 
       
   917             LOG(PluginEvents, "NPP_HandleEvent(getFocusEvent): %d", acceptedEvent);
       
   918             [self installKeyEventHandler];
       
   919         } else {
       
   920             event.what = loseFocusEvent;
       
   921             acceptedEvent = [self sendEvent:&event]; 
       
   922             LOG(PluginEvents, "NPP_HandleEvent(loseFocusEvent): %d", acceptedEvent);
       
   923             [self removeKeyEventHandler];
       
   924         }
       
   925     }
       
   926 }
       
   927 
       
   928 - (BOOL)becomeFirstResponder
       
   929 {
       
   930     [self setHasFocus:YES];
       
   931     return YES;
       
   932 }
       
   933 
       
   934 - (BOOL)resignFirstResponder
       
   935 {
       
   936     [self setHasFocus:NO];    
       
   937     return YES;
       
   938 }
       
   939 
       
   940 // AppKit doesn't call mouseDown or mouseUp on right-click. Simulate control-click
       
   941 // mouseDown and mouseUp so plug-ins get the right-click event as they do in Carbon (3125743).
       
   942 - (void)rightMouseDown:(NSEvent *)theEvent
       
   943 {
       
   944     [self mouseDown:theEvent];
       
   945 }
       
   946 
       
   947 - (void)rightMouseUp:(NSEvent *)theEvent
       
   948 {
       
   949     [self mouseUp:theEvent];
       
   950 }
       
   951 
       
   952 - (void)mouseDown:(NSEvent *)theEvent
       
   953 {
       
   954     EventRecord event;
       
   955 
       
   956     [self getCarbonEvent:&event withEvent:theEvent];
       
   957     event.what = mouseDown;
       
   958 
       
   959     BOOL acceptedEvent;
       
   960     acceptedEvent = [self sendEvent:&event]; 
       
   961     
       
   962     LOG(PluginEvents, "NPP_HandleEvent(mouseDown): %d pt.v=%d, pt.h=%d", acceptedEvent, event.where.v, event.where.h);
       
   963 }
       
   964 
       
   965 - (void)mouseUp:(NSEvent *)theEvent
       
   966 {
       
   967     EventRecord event;
       
   968     
       
   969     [self getCarbonEvent:&event withEvent:theEvent];
       
   970     event.what = mouseUp;
       
   971 
       
   972     BOOL acceptedEvent;
       
   973     acceptedEvent = [self sendEvent:&event]; 
       
   974     
       
   975     LOG(PluginEvents, "NPP_HandleEvent(mouseUp): %d pt.v=%d, pt.h=%d", acceptedEvent, event.where.v, event.where.h);
       
   976 }
       
   977 
       
   978 - (void)mouseEntered:(NSEvent *)theEvent
       
   979 {
       
   980     EventRecord event;
       
   981     
       
   982     [self getCarbonEvent:&event withEvent:theEvent];
       
   983     event.what = adjustCursorEvent;
       
   984 
       
   985     BOOL acceptedEvent;
       
   986     acceptedEvent = [self sendEvent:&event]; 
       
   987 
       
   988     LOG(PluginEvents, "NPP_HandleEvent(mouseEntered): %d", acceptedEvent);
       
   989 }
       
   990 
       
   991 - (void)mouseExited:(NSEvent *)theEvent
       
   992 {
       
   993     EventRecord event;
       
   994     
       
   995     [self getCarbonEvent:&event withEvent:theEvent];
       
   996     event.what = adjustCursorEvent;
       
   997 
       
   998     BOOL acceptedEvent;
       
   999     acceptedEvent = [self sendEvent:&event]; 
       
  1000 
       
  1001     // 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
       
  1002     // current cursor is otherwise.  Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin.
       
  1003     [[NSCursor arrowCursor] set];
       
  1004 
       
  1005     LOG(PluginEvents, "NPP_HandleEvent(mouseExited): %d", acceptedEvent);
       
  1006 }
       
  1007 
       
  1008 - (void)mouseDragged:(NSEvent *)theEvent
       
  1009 {
       
  1010     // Do nothing so that other responders don't respond to the drag that initiated in this view.
       
  1011 }
       
  1012 
       
  1013 - (UInt32)keyMessageForEvent:(NSEvent *)event
       
  1014 {
       
  1015     NSData *data = [[event characters] dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(CFStringGetSystemEncoding())];
       
  1016     if (!data) {
       
  1017         return 0;
       
  1018     }
       
  1019     UInt8 characterCode;
       
  1020     [data getBytes:&characterCode length:1];
       
  1021     UInt16 keyCode = [event keyCode];
       
  1022     return keyCode << 8 | characterCode;
       
  1023 }
       
  1024 
       
  1025 - (void)keyUp:(NSEvent *)theEvent
       
  1026 {
       
  1027     WKSendKeyEventToTSM(theEvent);
       
  1028     
       
  1029     // TSM won't send keyUp events so we have to send them ourselves.
       
  1030     // Only send keyUp events after we receive the TSM callback because this is what plug-in expect from OS 9.
       
  1031     if (!suspendKeyUpEvents) {
       
  1032         EventRecord event;
       
  1033         
       
  1034         [self getCarbonEvent:&event withEvent:theEvent];
       
  1035         event.what = keyUp;
       
  1036         
       
  1037         if (event.message == 0) {
       
  1038             event.message = [self keyMessageForEvent:theEvent];
       
  1039         }
       
  1040         
       
  1041         [self sendEvent:&event];
       
  1042     }
       
  1043 }
       
  1044 
       
  1045 - (void)keyDown:(NSEvent *)theEvent
       
  1046 {
       
  1047     suspendKeyUpEvents = YES;
       
  1048     WKSendKeyEventToTSM(theEvent);
       
  1049 }
       
  1050 
       
  1051 static OSStatus TSMEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *pluginView)
       
  1052 {    
       
  1053     EventRef rawKeyEventRef;
       
  1054     OSStatus status = GetEventParameter(inEvent, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(EventRef), NULL, &rawKeyEventRef);
       
  1055     if (status != noErr) {
       
  1056         LOG_ERROR("GetEventParameter failed with error: %d", status);
       
  1057         return noErr;
       
  1058     }
       
  1059     
       
  1060     // Two-pass read to allocate/extract Mac charCodes
       
  1061     ByteCount numBytes;    
       
  1062     status = GetEventParameter(rawKeyEventRef, kEventParamKeyMacCharCodes, typeChar, NULL, 0, &numBytes, NULL);
       
  1063     if (status != noErr) {
       
  1064         LOG_ERROR("GetEventParameter failed with error: %d", status);
       
  1065         return noErr;
       
  1066     }
       
  1067     char *buffer = (char *)malloc(numBytes);
       
  1068     status = GetEventParameter(rawKeyEventRef, kEventParamKeyMacCharCodes, typeChar, NULL, numBytes, NULL, buffer);
       
  1069     if (status != noErr) {
       
  1070         LOG_ERROR("GetEventParameter failed with error: %d", status);
       
  1071         free(buffer);
       
  1072         return noErr;
       
  1073     }
       
  1074     
       
  1075     EventRef cloneEvent = CopyEvent(rawKeyEventRef);
       
  1076     unsigned i;
       
  1077     for (i = 0; i < numBytes; i++) {
       
  1078         status = SetEventParameter(cloneEvent, kEventParamKeyMacCharCodes, typeChar, 1 /* one char code */, &buffer[i]);
       
  1079         if (status != noErr) {
       
  1080             LOG_ERROR("SetEventParameter failed with error: %d", status);
       
  1081             free(buffer);
       
  1082             return noErr;
       
  1083         }
       
  1084         
       
  1085         EventRecord eventRec;
       
  1086         if (ConvertEventRefToEventRecord(cloneEvent, &eventRec)) {
       
  1087             BOOL acceptedEvent;
       
  1088             acceptedEvent = [(WebBaseNetscapePluginView *)pluginView sendEvent:&eventRec];
       
  1089             
       
  1090             LOG(PluginEvents, "NPP_HandleEvent(keyDown): %d charCode:%c keyCode:%lu",
       
  1091                 acceptedEvent, (char) (eventRec.message & charCodeMask), (eventRec.message & keyCodeMask));
       
  1092             
       
  1093             // We originally thought that if the plug-in didn't accept this event,
       
  1094             // we should pass it along so that keyboard scrolling, for example, will work.
       
  1095             // In practice, this is not a good idea, because plug-ins tend to eat the event but return false.
       
  1096             // MacIE handles each key event twice because of this, but we will emulate the other browsers instead.
       
  1097         }
       
  1098     }
       
  1099     ReleaseEvent(cloneEvent);
       
  1100     
       
  1101     free(buffer);
       
  1102 
       
  1103     return noErr;
       
  1104 }
       
  1105 
       
  1106 // Fake up command-modified events so cut, copy, paste and select all menus work.
       
  1107 - (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character
       
  1108 {
       
  1109     EventRecord event;
       
  1110     [self getCarbonEvent:&event];
       
  1111     event.what = keyDown;
       
  1112     event.modifiers |= cmdKey;
       
  1113     event.message = keyCode << 8 | character;
       
  1114     [self sendEvent:&event];
       
  1115 }
       
  1116 
       
  1117 - (void)cut:(id)sender
       
  1118 {
       
  1119     [self sendModifierEventWithKeyCode:7 character:'x'];
       
  1120 }
       
  1121 
       
  1122 - (void)copy:(id)sender
       
  1123 {
       
  1124     [self sendModifierEventWithKeyCode:8 character:'c'];
       
  1125 }
       
  1126 
       
  1127 - (void)paste:(id)sender
       
  1128 {
       
  1129     [self sendModifierEventWithKeyCode:9 character:'v'];
       
  1130 }
       
  1131 
       
  1132 - (void)selectAll:(id)sender
       
  1133 {
       
  1134     [self sendModifierEventWithKeyCode:0 character:'a'];
       
  1135 }
       
  1136 
       
  1137 #pragma mark WEB_NETSCAPE_PLUGIN
       
  1138 
       
  1139 - (BOOL)isNewWindowEqualToOldWindow
       
  1140 {
       
  1141     if (window.x != lastSetWindow.x)
       
  1142         return NO;
       
  1143     if (window.y != lastSetWindow.y)
       
  1144         return NO;
       
  1145     if (window.width != lastSetWindow.width)
       
  1146         return NO;
       
  1147     if (window.height != lastSetWindow.height)
       
  1148         return NO;
       
  1149     if (window.clipRect.top != lastSetWindow.clipRect.top)
       
  1150         return NO;
       
  1151     if (window.clipRect.left != lastSetWindow.clipRect.left)
       
  1152         return NO;
       
  1153     if (window.clipRect.bottom  != lastSetWindow.clipRect.bottom)
       
  1154         return NO;
       
  1155     if (window.clipRect.right != lastSetWindow.clipRect.right)
       
  1156         return NO;
       
  1157     if (window.type != lastSetWindow.type)
       
  1158         return NO;
       
  1159     
       
  1160     switch (drawingModel) {
       
  1161 #ifndef NP_NO_QUICKDRAW
       
  1162         case NPDrawingModelQuickDraw:
       
  1163             if (nPort.qdPort.portx != lastSetPort.qdPort.portx)
       
  1164                 return NO;
       
  1165             if (nPort.qdPort.porty != lastSetPort.qdPort.porty)
       
  1166                 return NO;
       
  1167             if (nPort.qdPort.port != lastSetPort.qdPort.port)
       
  1168                 return NO;
       
  1169         break;
       
  1170 #endif /* NP_NO_QUICKDRAW */
       
  1171             
       
  1172         case NPDrawingModelCoreGraphics:
       
  1173             if (nPort.cgPort.window != lastSetPort.cgPort.window)
       
  1174                 return NO;
       
  1175             if (nPort.cgPort.context != lastSetPort.cgPort.context)
       
  1176                 return NO;
       
  1177         break;
       
  1178             
       
  1179         case NPDrawingModelOpenGL:
       
  1180             if (nPort.aglPort.window != lastSetPort.aglPort.window)
       
  1181                 return NO;
       
  1182             if (nPort.aglPort.context != lastSetPort.aglPort.context)
       
  1183                 return NO;
       
  1184         break;
       
  1185         
       
  1186         default:
       
  1187             ASSERT_NOT_REACHED();
       
  1188         break;
       
  1189     }
       
  1190     
       
  1191     return YES;
       
  1192 }
       
  1193 
       
  1194 - (void)updateAndSetWindow
       
  1195 {
       
  1196     if (drawingModel == NPDrawingModelCoreGraphics || drawingModel == NPDrawingModelOpenGL) {
       
  1197         // Can only update CoreGraphics and OpenGL plugins while redrawing the plugin view
       
  1198         [self setNeedsDisplay:YES];
       
  1199         return;
       
  1200     }
       
  1201     
       
  1202     // Can't update the plugin if it has not started (or has been stopped)
       
  1203     if (!isStarted)
       
  1204         return;
       
  1205         
       
  1206     PortState portState = [self saveAndSetNewPortState];
       
  1207     if (portState) {
       
  1208         [self setWindowIfNecessary];
       
  1209         [self restorePortState:portState];
       
  1210         free(portState);
       
  1211     }
       
  1212 }
       
  1213 
       
  1214 - (void)setWindowIfNecessary
       
  1215 {
       
  1216     if (!isStarted) {
       
  1217         return;
       
  1218     }
       
  1219     
       
  1220     if (![self isNewWindowEqualToOldWindow]) {        
       
  1221         // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
       
  1222         // We probably don't want more general reentrancy protection; we are really
       
  1223         // protecting only against this one case, which actually comes up when
       
  1224         // you first install the SVG viewer plug-in.
       
  1225         NPError npErr;
       
  1226         ASSERT(!inSetWindow);
       
  1227         
       
  1228         inSetWindow = YES;
       
  1229         
       
  1230         // A CoreGraphics or OpenGL plugin's window may only be set while the plugin is being updated
       
  1231         ASSERT((drawingModel != NPDrawingModelCoreGraphics && drawingModel != NPDrawingModelOpenGL) || [NSView focusView] == self);
       
  1232         
       
  1233         [self willCallPlugInFunction];
       
  1234         {
       
  1235             KJS::JSLock::DropAllLocks dropAllLocks;
       
  1236             npErr = NPP_SetWindow(plugin, &window);
       
  1237         }
       
  1238         [self didCallPlugInFunction];
       
  1239         inSetWindow = NO;
       
  1240 
       
  1241 #ifndef NDEBUG
       
  1242         switch (drawingModel) {
       
  1243 #ifndef NP_NO_QUICKDRAW
       
  1244             case NPDrawingModelQuickDraw:
       
  1245                 LOG(Plugins, "NPP_SetWindow (QuickDraw): %d, port=0x%08x, window.x:%d window.y:%d window.width:%d window.height:%d",
       
  1246                 npErr, (int)nPort.qdPort.port, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
       
  1247             break;
       
  1248 #endif /* NP_NO_QUICKDRAW */
       
  1249             
       
  1250             case NPDrawingModelCoreGraphics:
       
  1251                 LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d",
       
  1252                 npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
       
  1253             break;
       
  1254 
       
  1255             case NPDrawingModelOpenGL:
       
  1256                 LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d",
       
  1257                 npErr, nPort.aglPort.window, nPort.aglPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
       
  1258             break;
       
  1259             
       
  1260             default:
       
  1261                 ASSERT_NOT_REACHED();
       
  1262             break;
       
  1263         }
       
  1264 #endif /* !defined(NDEBUG) */
       
  1265         
       
  1266         lastSetWindow = window;
       
  1267         lastSetPort = nPort;
       
  1268     }
       
  1269 }
       
  1270 
       
  1271 - (void)removeTrackingRect
       
  1272 {
       
  1273     if (trackingTag) {
       
  1274         [self removeTrackingRect:trackingTag];
       
  1275         trackingTag = 0;
       
  1276 
       
  1277         // Do the following after setting trackingTag to 0 so we don't re-enter.
       
  1278 
       
  1279         // Balance the retain in resetTrackingRect. Use autorelease in case we hold 
       
  1280         // the last reference to the window during tear-down, to avoid crashing AppKit. 
       
  1281         [[self window] autorelease];
       
  1282     }
       
  1283 }
       
  1284 
       
  1285 - (void)resetTrackingRect
       
  1286 {
       
  1287     [self removeTrackingRect];
       
  1288     if (isStarted) {
       
  1289         // Retain the window so that removeTrackingRect can work after the window is closed.
       
  1290         [[self window] retain];
       
  1291         trackingTag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO];
       
  1292     }
       
  1293 }
       
  1294 
       
  1295 + (void)setCurrentPluginView:(WebBaseNetscapePluginView *)view
       
  1296 {
       
  1297     currentPluginView = view;
       
  1298 }
       
  1299 
       
  1300 + (WebBaseNetscapePluginView *)currentPluginView
       
  1301 {
       
  1302     return currentPluginView;
       
  1303 }
       
  1304 
       
  1305 - (BOOL)canStart
       
  1306 {
       
  1307     return YES;
       
  1308 }
       
  1309 
       
  1310 - (void)didStart
       
  1311 {
       
  1312     if (_loadManually) {
       
  1313         [self _redeliverStream];
       
  1314         return;
       
  1315     }
       
  1316     
       
  1317     // If the OBJECT/EMBED tag has no SRC, the URL is passed to us as "".
       
  1318     // Check for this and don't start a load in this case.
       
  1319     if (sourceURL != nil && ![sourceURL _web_isEmpty]) {
       
  1320         NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:sourceURL];
       
  1321         [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()];
       
  1322         [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO];
       
  1323     } 
       
  1324 }
       
  1325 
       
  1326 - (void)addWindowObservers
       
  1327 {
       
  1328     ASSERT([self window]);
       
  1329 
       
  1330     NSWindow *theWindow = [self window];
       
  1331     
       
  1332     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
       
  1333     [notificationCenter addObserver:self selector:@selector(windowWillClose:) 
       
  1334                                name:NSWindowWillCloseNotification object:theWindow]; 
       
  1335     [notificationCenter addObserver:self selector:@selector(windowBecameKey:)
       
  1336                                name:NSWindowDidBecomeKeyNotification object:theWindow];
       
  1337     [notificationCenter addObserver:self selector:@selector(windowResignedKey:)
       
  1338                                name:NSWindowDidResignKeyNotification object:theWindow];
       
  1339     [notificationCenter addObserver:self selector:@selector(windowDidMiniaturize:)
       
  1340                                name:NSWindowDidMiniaturizeNotification object:theWindow];
       
  1341     [notificationCenter addObserver:self selector:@selector(windowDidDeminiaturize:)
       
  1342                                name:NSWindowDidDeminiaturizeNotification object:theWindow];
       
  1343     
       
  1344     [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchFromUser:)
       
  1345                                name:LoginWindowDidSwitchFromUserNotification object:nil];
       
  1346     [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchToUser:)
       
  1347                                name:LoginWindowDidSwitchToUserNotification object:nil];
       
  1348 }
       
  1349 
       
  1350 - (void)removeWindowObservers
       
  1351 {
       
  1352     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
       
  1353     [notificationCenter removeObserver:self name:NSWindowWillCloseNotification        object:nil]; 
       
  1354     [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification     object:nil];
       
  1355     [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification     object:nil];
       
  1356     [notificationCenter removeObserver:self name:NSWindowDidMiniaturizeNotification   object:nil];
       
  1357     [notificationCenter removeObserver:self name:NSWindowDidDeminiaturizeNotification object:nil];
       
  1358     [notificationCenter removeObserver:self name:LoginWindowDidSwitchFromUserNotification   object:nil];
       
  1359     [notificationCenter removeObserver:self name:LoginWindowDidSwitchToUserNotification     object:nil];
       
  1360 }
       
  1361 
       
  1362 - (BOOL)start
       
  1363 {
       
  1364     ASSERT([self currentWindow]);
       
  1365     
       
  1366     if (isStarted)
       
  1367         return YES;
       
  1368 
       
  1369     if (![self canStart])
       
  1370         return NO;
       
  1371     
       
  1372     ASSERT([self webView]);
       
  1373     
       
  1374     if (![[[self webView] preferences] arePlugInsEnabled])
       
  1375         return NO;
       
  1376 
       
  1377     // Open the plug-in package so it remains loaded while our plugin uses it
       
  1378     [pluginPackage open];
       
  1379     
       
  1380     // Initialize drawingModel to an invalid value so that we can detect when the plugin does not specify a drawingModel
       
  1381     drawingModel = (NPDrawingModel)-1;
       
  1382     
       
  1383     // Plug-ins are "windowed" by default.  On MacOS, windowed plug-ins share the same window and graphics port as the main
       
  1384     // browser window.  Windowless plug-ins are rendered off-screen, then copied into the main browser window.
       
  1385     window.type = NPWindowTypeWindow;
       
  1386     
       
  1387     NPError npErr = [self _createPlugin];
       
  1388     if (npErr != NPERR_NO_ERROR) {
       
  1389         LOG_ERROR("NPP_New failed with error: %d", npErr);
       
  1390         [self _destroyPlugin];
       
  1391         [pluginPackage close];
       
  1392         return NO;
       
  1393     }
       
  1394     
       
  1395     if (drawingModel == (NPDrawingModel)-1) {
       
  1396 #ifndef NP_NO_QUICKDRAW
       
  1397         // Default to QuickDraw if the plugin did not specify a drawing model.
       
  1398         drawingModel = NPDrawingModelQuickDraw;
       
  1399 #else
       
  1400         // QuickDraw is not available, so we can't default to it.  We could default to CoreGraphics instead, but
       
  1401         // if the plugin did not specify the CoreGraphics drawing model then it must be one of the old QuickDraw
       
  1402         // plugins.  Thus, the plugin is unsupported and should not be started.  Destroy it here and bail out.
       
  1403         LOG(Plugins, "Plugin only supports QuickDraw, but QuickDraw is unavailable: %@", pluginPackage);
       
  1404         [self _destroyPlugin];
       
  1405         [pluginPackage close];
       
  1406         return NO;
       
  1407 #endif
       
  1408     }
       
  1409 
       
  1410     isStarted = YES;
       
  1411         
       
  1412     [self updateAndSetWindow];
       
  1413 
       
  1414     if ([self window]) {
       
  1415         [self addWindowObservers];
       
  1416         if ([[self window] isKeyWindow]) {
       
  1417             [self sendActivateEvent:YES];
       
  1418         }
       
  1419         [self restartNullEvents];
       
  1420     }
       
  1421 
       
  1422     [self resetTrackingRect];
       
  1423     
       
  1424     [self didStart];
       
  1425     
       
  1426     return YES;
       
  1427 }
       
  1428 
       
  1429 - (void)stop
       
  1430 {
       
  1431     // If we're already calling a plug-in function, do not call NPP_Destroy().  The plug-in function we are calling
       
  1432     // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said
       
  1433     // plugin-function returns.
       
  1434     // See <rdar://problem/4480737>.
       
  1435     if (pluginFunctionCallDepth > 0) {
       
  1436         shouldStopSoon = YES;
       
  1437         return;
       
  1438     }
       
  1439     
       
  1440     [self removeTrackingRect];
       
  1441 
       
  1442     if (!isStarted)
       
  1443         return;
       
  1444     
       
  1445     isStarted = NO;
       
  1446     // To stop active streams it's necessary to invoke makeObjectsPerformSelector on a copy 
       
  1447     // of streams. This is because calling -[WebNetscapePluginStream stop] also has the side effect
       
  1448     // of removing a stream from this collection.
       
  1449     NSArray *streamsCopy = [streams copy];
       
  1450     [streamsCopy makeObjectsPerformSelector:@selector(stop)];
       
  1451     [streamsCopy release];
       
  1452    
       
  1453     // Stop the null events
       
  1454     [self stopNullEvents];
       
  1455     
       
  1456     // Stop notifications and callbacks.
       
  1457     [self removeWindowObservers];
       
  1458     [[pendingFrameLoads allKeys] makeObjectsPerformSelector:@selector(_setInternalLoadDelegate:) withObject:nil];
       
  1459     [NSObject cancelPreviousPerformRequestsWithTarget:self];
       
  1460 
       
  1461     // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted.
       
  1462     lastSetWindow.type = (NPWindowType)0;
       
  1463     
       
  1464     [self _destroyPlugin];
       
  1465     [pluginPackage close];
       
  1466     
       
  1467     // We usually remove the key event handler in resignFirstResponder but it is possible that resignFirstResponder 
       
  1468     // may never get called so we can't completely rely on it.
       
  1469     [self removeKeyEventHandler];
       
  1470     
       
  1471     if (drawingModel == NPDrawingModelOpenGL)
       
  1472         [self _destroyAGLContext];
       
  1473 }
       
  1474 
       
  1475 - (BOOL)isStarted
       
  1476 {
       
  1477     return isStarted;
       
  1478 }
       
  1479 
       
  1480 - (WebDataSource *)dataSource
       
  1481 {
       
  1482     WebFrame *webFrame = kit(core(element)->document()->frame());
       
  1483     return [webFrame _dataSource];
       
  1484 }
       
  1485 
       
  1486 - (WebFrame *)webFrame
       
  1487 {
       
  1488     return [[self dataSource] webFrame];
       
  1489 }
       
  1490 
       
  1491 - (WebView *)webView
       
  1492 {
       
  1493     return [[self webFrame] webView];
       
  1494 }
       
  1495 
       
  1496 - (NSWindow *)currentWindow
       
  1497 {
       
  1498     return [self window] ? [self window] : [[self webView] hostWindow];
       
  1499 }
       
  1500 
       
  1501 - (NPP)plugin
       
  1502 {
       
  1503     return plugin;
       
  1504 }
       
  1505 
       
  1506 - (WebNetscapePluginPackage *)pluginPackage
       
  1507 {
       
  1508     return pluginPackage;
       
  1509 }
       
  1510 
       
  1511 - (void)setPluginPackage:(WebNetscapePluginPackage *)thePluginPackage;
       
  1512 {
       
  1513     [thePluginPackage retain];
       
  1514     [pluginPackage release];
       
  1515     pluginPackage = thePluginPackage;
       
  1516 
       
  1517     NPP_New =           [pluginPackage NPP_New];
       
  1518     NPP_Destroy =       [pluginPackage NPP_Destroy];
       
  1519     NPP_SetWindow =     [pluginPackage NPP_SetWindow];
       
  1520     NPP_NewStream =     [pluginPackage NPP_NewStream];
       
  1521     NPP_WriteReady =    [pluginPackage NPP_WriteReady];
       
  1522     NPP_Write =         [pluginPackage NPP_Write];
       
  1523     NPP_StreamAsFile =  [pluginPackage NPP_StreamAsFile];
       
  1524     NPP_DestroyStream = [pluginPackage NPP_DestroyStream];
       
  1525     NPP_HandleEvent =   [pluginPackage NPP_HandleEvent];
       
  1526     NPP_URLNotify =     [pluginPackage NPP_URLNotify];
       
  1527     NPP_GetValue =      [pluginPackage NPP_GetValue];
       
  1528     NPP_SetValue =      [pluginPackage NPP_SetValue];
       
  1529     NPP_Print =         [pluginPackage NPP_Print];
       
  1530 }
       
  1531 
       
  1532 - (void)setMIMEType:(NSString *)theMIMEType
       
  1533 {
       
  1534     NSString *type = [theMIMEType copy];
       
  1535     [MIMEType release];
       
  1536     MIMEType = type;
       
  1537 }
       
  1538 
       
  1539 - (void)setBaseURL:(NSURL *)theBaseURL
       
  1540 {
       
  1541     [theBaseURL retain];
       
  1542     [baseURL release];
       
  1543     baseURL = theBaseURL;
       
  1544 }
       
  1545 
       
  1546 - (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values;
       
  1547 {
       
  1548     ASSERT([keys count] == [values count]);
       
  1549     
       
  1550     // Convert the attributes to 2 C string arrays.
       
  1551     // These arrays are passed to NPP_New, but the strings need to be
       
  1552     // modifiable and live the entire life of the plugin.
       
  1553 
       
  1554     // The Java plug-in requires the first argument to be the base URL
       
  1555     if ([MIMEType isEqualToString:@"application/x-java-applet"]) {
       
  1556         cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *));
       
  1557         cValues = (char **)malloc(([values count] + 1) * sizeof(char *));
       
  1558         cAttributes[0] = strdup("DOCBASE");
       
  1559         cValues[0] = strdup([baseURL _web_URLCString]);
       
  1560         argsCount++;
       
  1561     } else {
       
  1562         cAttributes = (char **)malloc([keys count] * sizeof(char *));
       
  1563         cValues = (char **)malloc([values count] * sizeof(char *));
       
  1564     }
       
  1565 
       
  1566     BOOL isWMP = [[[pluginPackage bundle] bundleIdentifier] isEqualToString:@"com.microsoft.WMP.defaultplugin"];
       
  1567     
       
  1568     unsigned i;
       
  1569     unsigned count = [keys count];
       
  1570     for (i = 0; i < count; i++) {
       
  1571         NSString *key = [keys objectAtIndex:i];
       
  1572         NSString *value = [values objectAtIndex:i];
       
  1573         if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) {
       
  1574             specifiedHeight = [value intValue];
       
  1575         } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) {
       
  1576             specifiedWidth = [value intValue];
       
  1577         }
       
  1578         // Avoid Window Media Player crash when these attributes are present.
       
  1579         if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) {
       
  1580             continue;
       
  1581         }
       
  1582         cAttributes[argsCount] = strdup([key UTF8String]);
       
  1583         cValues[argsCount] = strdup([value UTF8String]);
       
  1584         LOG(Plugins, "%@ = %@", key, value);
       
  1585         argsCount++;
       
  1586     }
       
  1587 }
       
  1588 
       
  1589 - (void)setMode:(int)theMode
       
  1590 {
       
  1591     mode = theMode;
       
  1592 }
       
  1593 
       
  1594 #pragma mark NSVIEW
       
  1595 
       
  1596 - (id)initWithFrame:(NSRect)frame
       
  1597       pluginPackage:(WebNetscapePluginPackage *)thePluginPackage
       
  1598                 URL:(NSURL *)theURL
       
  1599             baseURL:(NSURL *)theBaseURL
       
  1600            MIMEType:(NSString *)MIME
       
  1601       attributeKeys:(NSArray *)keys
       
  1602     attributeValues:(NSArray *)values
       
  1603        loadManually:(BOOL)loadManually
       
  1604          DOMElement:(DOMElement *)anElement
       
  1605 {
       
  1606     [super initWithFrame:frame];
       
  1607  
       
  1608     streams = [[NSMutableArray alloc] init];
       
  1609     pendingFrameLoads = [[NSMutableDictionary alloc] init];    
       
  1610     
       
  1611     // load the plug-in if it is not already loaded
       
  1612     if (![thePluginPackage load]) {
       
  1613         [self release];
       
  1614         return nil;
       
  1615     }
       
  1616     [self setPluginPackage:thePluginPackage];
       
  1617     
       
  1618     element = [anElement retain];
       
  1619     sourceURL = [theURL retain];
       
  1620     
       
  1621     [self setMIMEType:MIME];
       
  1622     [self setBaseURL:theBaseURL];
       
  1623     [self setAttributeKeys:keys andValues:values];
       
  1624     if (loadManually)
       
  1625         [self setMode:NP_FULL];
       
  1626     else
       
  1627         [self setMode:NP_EMBED];
       
  1628     
       
  1629     _loadManually = loadManually;
       
  1630     
       
  1631     return self;
       
  1632 }
       
  1633 
       
  1634 - (id)initWithFrame:(NSRect)frame
       
  1635 {
       
  1636     ASSERT_NOT_REACHED();
       
  1637     return nil;
       
  1638 }
       
  1639 
       
  1640 - (void)fini
       
  1641 {
       
  1642 #ifndef NP_NO_QUICKDRAW
       
  1643     if (offscreenGWorld)
       
  1644         DisposeGWorld(offscreenGWorld);
       
  1645 #endif
       
  1646 
       
  1647     unsigned i;
       
  1648     for (i = 0; i < argsCount; i++) {
       
  1649         free(cAttributes[i]);
       
  1650         free(cValues[i]);
       
  1651     }
       
  1652     free(cAttributes);
       
  1653     free(cValues);
       
  1654 }
       
  1655 
       
  1656 - (void)disconnectStream:(WebBaseNetscapePluginStream*)stream
       
  1657 {
       
  1658     [streams removeObjectIdenticalTo:stream];    
       
  1659 }
       
  1660 
       
  1661 - (void)dealloc
       
  1662 {
       
  1663     ASSERT(!isStarted);
       
  1664 
       
  1665     [sourceURL release];
       
  1666     [_manualStream release];
       
  1667     [_error release];
       
  1668     
       
  1669     [pluginPackage release];
       
  1670     [streams release];
       
  1671     [MIMEType release];
       
  1672     [baseURL release];
       
  1673     [pendingFrameLoads release];
       
  1674     [element release];
       
  1675     
       
  1676     ASSERT(!plugin);
       
  1677     ASSERT(!aglWindow);
       
  1678     ASSERT(!aglContext);
       
  1679 
       
  1680     [self fini];
       
  1681 
       
  1682     [super dealloc];
       
  1683 }
       
  1684 
       
  1685 - (void)finalize
       
  1686 {
       
  1687     ASSERT_MAIN_THREAD();
       
  1688     ASSERT(!isStarted);
       
  1689 
       
  1690     [self fini];
       
  1691 
       
  1692     [super finalize];
       
  1693 }
       
  1694 
       
  1695 - (void)drawRect:(NSRect)rect
       
  1696 {
       
  1697     if (!isStarted) {
       
  1698         return;
       
  1699     }
       
  1700     
       
  1701     if ([NSGraphicsContext currentContextDrawingToScreen])
       
  1702         [self sendUpdateEvent];
       
  1703     else {
       
  1704         NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap];
       
  1705         if (printedPluginBitmap) {
       
  1706             // Flip the bitmap before drawing because the QuickDraw port is flipped relative
       
  1707             // to this view.
       
  1708             CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
       
  1709             CGContextSaveGState(cgContext);
       
  1710             NSRect bounds = [self bounds];
       
  1711             CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds));
       
  1712             CGContextScaleCTM(cgContext, 1.0f, -1.0f);
       
  1713             [printedPluginBitmap drawInRect:bounds];
       
  1714             CGContextRestoreGState(cgContext);
       
  1715         }
       
  1716     }
       
  1717     
       
  1718     // If this is a windowless OpenGL plugin, blit its contents back into this view.  The plug-in just drew into the offscreen context.
       
  1719     if (drawingModel == NPDrawingModelOpenGL && window.type == NPWindowTypeDrawable) {
       
  1720         NSImage *aglOffscreenImage = [self _aglOffscreenImageForDrawingInRect:rect];
       
  1721         if (aglOffscreenImage) {
       
  1722             // Flip the context before drawing because the CGL context is flipped relative to this view.
       
  1723             CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
       
  1724             CGContextSaveGState(cgContext);
       
  1725             NSRect bounds = [self bounds];
       
  1726             CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds));
       
  1727             CGContextScaleCTM(cgContext, 1.0f, -1.0f);
       
  1728             
       
  1729             // Copy 'rect' from the offscreen buffer to this view (the flip above makes this sort of tricky)
       
  1730             NSRect flippedRect = rect;
       
  1731             flippedRect.origin.y = NSMaxY(bounds) - NSMaxY(flippedRect);
       
  1732             [aglOffscreenImage drawInRect:flippedRect fromRect:flippedRect operation:NSCompositeSourceOver fraction:1.0f];
       
  1733             CGContextRestoreGState(cgContext);
       
  1734         }
       
  1735     }
       
  1736 }
       
  1737 
       
  1738 - (BOOL)isFlipped
       
  1739 {
       
  1740     return YES;
       
  1741 }
       
  1742 
       
  1743 - (void)renewGState
       
  1744 {
       
  1745     [super renewGState];
       
  1746     
       
  1747     // -renewGState is called whenever the view's geometry changes.  It's a little hacky to override this method, but
       
  1748     // much safer than walking up the view hierarchy and observing frame/bounds changed notifications, since you don't
       
  1749     // have to track subsequent changes to the view hierarchy and add/remove notification observers.
       
  1750     // NSOpenGLView uses the exact same technique to reshape its OpenGL surface.
       
  1751     [self _viewHasMoved];
       
  1752 }
       
  1753 
       
  1754 #ifndef NP_NO_QUICKDRAW
       
  1755 -(void)tellQuickTimeToChill
       
  1756 {
       
  1757     ASSERT(drawingModel == NPDrawingModelQuickDraw);
       
  1758     
       
  1759     // Make a call to the secret QuickDraw API that makes QuickTime calm down.
       
  1760     WindowRef windowRef = (WindowRef)[[self window] windowRef];
       
  1761     if (!windowRef) {
       
  1762         return;
       
  1763     }
       
  1764     CGrafPtr port = GetWindowPort(windowRef);
       
  1765     ::Rect bounds;
       
  1766     GetPortBounds(port, &bounds);
       
  1767     WKCallDrawingNotification(port, &bounds);
       
  1768 }
       
  1769 #endif /* NP_NO_QUICKDRAW */
       
  1770 
       
  1771 - (void)viewWillMoveToWindow:(NSWindow *)newWindow
       
  1772 {
       
  1773 #ifndef NP_NO_QUICKDRAW
       
  1774     if (drawingModel == NPDrawingModelQuickDraw)
       
  1775         [self tellQuickTimeToChill];
       
  1776 #endif
       
  1777 
       
  1778     // We must remove the tracking rect before we move to the new window.
       
  1779     // Once we move to the new window, it will be too late.
       
  1780     [self removeTrackingRect];
       
  1781     [self removeWindowObservers];
       
  1782     
       
  1783     // Workaround for: <rdar://problem/3822871> resignFirstResponder is not sent to first responder view when it is removed from the window
       
  1784     [self setHasFocus:NO];
       
  1785 
       
  1786     if (!newWindow) {
       
  1787         // Hide the AGL child window
       
  1788         if (drawingModel == NPDrawingModelOpenGL)
       
  1789             [self _hideAGLWindow];
       
  1790         
       
  1791         if ([[self webView] hostWindow]) {
       
  1792             // View will be moved out of the actual window but it still has a host window.
       
  1793             [self stopNullEvents];
       
  1794         } else {
       
  1795             // View will have no associated windows.
       
  1796             [self stop];
       
  1797 
       
  1798             // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy.
       
  1799             // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed.
       
  1800             [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
       
  1801         }
       
  1802     }
       
  1803 }
       
  1804 
       
  1805 - (void)viewWillMoveToSuperview:(NSView *)newSuperview
       
  1806 {
       
  1807     if (!newSuperview) {
       
  1808         // Stop the plug-in when it is removed from its superview.  It is not sufficient to do this in -viewWillMoveToWindow:nil, because
       
  1809         // the WebView might still has a hostWindow at that point, which prevents the plug-in from being destroyed.
       
  1810         // There is no need to start the plug-in when moving into a superview.  -viewDidMoveToWindow takes care of that.
       
  1811         [self stop];
       
  1812         
       
  1813         // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy.
       
  1814         // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed.
       
  1815         [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
       
  1816     }
       
  1817 }
       
  1818 
       
  1819 - (void)viewDidMoveToWindow
       
  1820 {
       
  1821     [self resetTrackingRect];
       
  1822     
       
  1823     if ([self window]) {
       
  1824         // While in the view hierarchy, observe WebPreferencesChangedNotification so that we can start/stop depending
       
  1825         // on whether plugins are enabled.
       
  1826         [[NSNotificationCenter defaultCenter] addObserver:self
       
  1827                                               selector:@selector(preferencesHaveChanged:)
       
  1828                                               name:WebPreferencesChangedNotification
       
  1829                                               object:nil];
       
  1830 
       
  1831         // View moved to an actual window. Start it if not already started.
       
  1832         [self start];
       
  1833         [self restartNullEvents];
       
  1834         [self addWindowObservers];
       
  1835     } else if ([[self webView] hostWindow]) {
       
  1836         // View moved out of an actual window, but still has a host window.
       
  1837         // Call setWindow to explicitly "clip out" the plug-in from sight.
       
  1838         // FIXME: It would be nice to do this where we call stopNullEvents in viewWillMoveToWindow.
       
  1839         [self updateAndSetWindow];
       
  1840     }
       
  1841 }
       
  1842 
       
  1843 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
       
  1844 {
       
  1845     if (!hostWindow && ![self window]) {
       
  1846         // View will have no associated windows.
       
  1847         [self stop];
       
  1848 
       
  1849         // Remove WebPreferencesChangedNotification observer -- we will observe once again when we move back into the window
       
  1850         [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
       
  1851     }
       
  1852 }
       
  1853 
       
  1854 - (void)viewDidMoveToHostWindow
       
  1855 {
       
  1856     if ([[self webView] hostWindow]) {
       
  1857         // View now has an associated window. Start it if not already started.
       
  1858         [self start];
       
  1859     }
       
  1860 }
       
  1861 
       
  1862 #pragma mark NOTIFICATIONS
       
  1863 
       
  1864 - (void)windowWillClose:(NSNotification *)notification 
       
  1865 {
       
  1866     [self stop]; 
       
  1867 } 
       
  1868 
       
  1869 - (void)windowBecameKey:(NSNotification *)notification
       
  1870 {
       
  1871     [self sendActivateEvent:YES];
       
  1872     [self setNeedsDisplay:YES];
       
  1873     [self restartNullEvents];
       
  1874     SetUserFocusWindow((WindowRef)[[self window] windowRef]);
       
  1875 }
       
  1876 
       
  1877 - (void)windowResignedKey:(NSNotification *)notification
       
  1878 {
       
  1879     [self sendActivateEvent:NO];
       
  1880     [self setNeedsDisplay:YES];
       
  1881     [self restartNullEvents];
       
  1882 }
       
  1883 
       
  1884 - (void)windowDidMiniaturize:(NSNotification *)notification
       
  1885 {
       
  1886     [self stopNullEvents];
       
  1887 }
       
  1888 
       
  1889 - (void)windowDidDeminiaturize:(NSNotification *)notification
       
  1890 {
       
  1891     [self restartNullEvents];
       
  1892 }
       
  1893 
       
  1894 - (void)loginWindowDidSwitchFromUser:(NSNotification *)notification
       
  1895 {
       
  1896     [self stopNullEvents];
       
  1897 }
       
  1898 
       
  1899 -(void)loginWindowDidSwitchToUser:(NSNotification *)notification
       
  1900 {
       
  1901     [self restartNullEvents];
       
  1902 }
       
  1903 
       
  1904 - (void)preferencesHaveChanged:(NSNotification *)notification
       
  1905 {
       
  1906     WebPreferences *preferences = [[self webView] preferences];
       
  1907     BOOL arePlugInsEnabled = [preferences arePlugInsEnabled];
       
  1908     
       
  1909     if ([notification object] == preferences && isStarted != arePlugInsEnabled) {
       
  1910         if (arePlugInsEnabled) {
       
  1911             if ([self currentWindow]) {
       
  1912                 [self start];
       
  1913             }
       
  1914         } else {
       
  1915             [self stop];
       
  1916             [self setNeedsDisplay:YES];
       
  1917         }
       
  1918     }
       
  1919 }
       
  1920 
       
  1921 - (NPObject *)createPluginScriptableObject
       
  1922 {
       
  1923     if (!NPP_GetValue || ![self isStarted])
       
  1924         return NULL;
       
  1925         
       
  1926     NPObject *value = NULL;
       
  1927     NPError error;
       
  1928     [self willCallPlugInFunction];
       
  1929     {
       
  1930         KJS::JSLock::DropAllLocks dropAllLocks;
       
  1931         error = NPP_GetValue(plugin, NPPVpluginScriptableNPObject, &value);
       
  1932     }
       
  1933     [self didCallPlugInFunction];
       
  1934     if (error != NPERR_NO_ERROR)
       
  1935         return NULL;
       
  1936     
       
  1937     return value;
       
  1938 }
       
  1939 
       
  1940 - (void)willCallPlugInFunction
       
  1941 {
       
  1942     ASSERT(plugin);
       
  1943 
       
  1944     // Could try to prevent infinite recursion here, but it's probably not worth the effort.
       
  1945     pluginFunctionCallDepth++;
       
  1946 }
       
  1947 
       
  1948 - (void)didCallPlugInFunction
       
  1949 {
       
  1950     ASSERT(pluginFunctionCallDepth > 0);
       
  1951     pluginFunctionCallDepth--;
       
  1952     
       
  1953     // If -stop was called while we were calling into a plug-in function, and we're no longer
       
  1954     // inside a plug-in function, stop now.
       
  1955     if (pluginFunctionCallDepth == 0 && shouldStopSoon) {
       
  1956         shouldStopSoon = NO;
       
  1957         [self stop];
       
  1958     }
       
  1959 }
       
  1960 
       
  1961 -(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
       
  1962 {
       
  1963     ASSERT(_loadManually);
       
  1964     ASSERT(!_manualStream);
       
  1965     
       
  1966     _manualStream = [[WebNetscapePluginStream alloc] initWithFrameLoader:core([self webFrame])->loader()];
       
  1967 }
       
  1968 
       
  1969 - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
       
  1970 {
       
  1971     ASSERT(_loadManually);
       
  1972     ASSERT(_manualStream);
       
  1973     
       
  1974     _dataLengthReceived += [data length];
       
  1975     
       
  1976     if (![self isStarted])
       
  1977         return;
       
  1978     
       
  1979     if ([_manualStream plugin] == NULL) {
       
  1980         [_manualStream setRequestURL:[[[self dataSource] request] URL]];
       
  1981         [_manualStream setPlugin:[self plugin]];
       
  1982         ASSERT([_manualStream plugin]);
       
  1983         [_manualStream startStreamWithResponse:[[self dataSource] response]];
       
  1984     }
       
  1985     
       
  1986     if ([_manualStream plugin])
       
  1987         [_manualStream receivedData:data];
       
  1988 }
       
  1989 
       
  1990 - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
       
  1991 {
       
  1992     ASSERT(_loadManually);
       
  1993     
       
  1994     [error retain];
       
  1995     [_error release];
       
  1996     _error = error;
       
  1997     
       
  1998     if (![self isStarted]) {
       
  1999         return;
       
  2000     }
       
  2001     
       
  2002     [_manualStream destroyStreamWithError:error];
       
  2003 }
       
  2004 
       
  2005 - (void)pluginViewFinishedLoading:(NSView *)pluginView 
       
  2006 {
       
  2007     ASSERT(_loadManually);
       
  2008     ASSERT(_manualStream);
       
  2009     
       
  2010     if ([self isStarted])
       
  2011         [_manualStream finishedLoadingWithData:[[self dataSource] data]];    
       
  2012 }
       
  2013 
       
  2014 @end
       
  2015 
       
  2016 @implementation WebBaseNetscapePluginView (WebNPPCallbacks)
       
  2017 
       
  2018 - (NSMutableURLRequest *)requestWithURLCString:(const char *)URLCString
       
  2019 {
       
  2020     if (!URLCString)
       
  2021         return nil;
       
  2022     
       
  2023     CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, URLCString, kCFStringEncodingISOLatin1);
       
  2024     ASSERT(string); // All strings should be representable in ISO Latin 1
       
  2025     
       
  2026     NSString *URLString = [(NSString *)string _web_stringByStrippingReturnCharacters];
       
  2027     NSURL *URL = [NSURL _web_URLWithDataAsString:URLString relativeToURL:baseURL];
       
  2028     CFRelease(string);
       
  2029     if (!URL)
       
  2030         return nil;
       
  2031 
       
  2032     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
       
  2033     Frame* frame = core([self webFrame]);
       
  2034     if (!frame)
       
  2035         return nil;
       
  2036     [request _web_setHTTPReferrer:frame->loader()->outgoingReferrer()];
       
  2037     return request;
       
  2038 }
       
  2039 
       
  2040 - (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest
       
  2041 {
       
  2042     // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called
       
  2043     // if we are stopped since this method is called after a delay and we call 
       
  2044     // cancelPreviousPerformRequestsWithTarget inside of stop.
       
  2045     if (!isStarted) {
       
  2046         return;
       
  2047     }
       
  2048     
       
  2049     NSURL *URL = [[JSPluginRequest request] URL];
       
  2050     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
       
  2051     ASSERT(JSString);
       
  2052     
       
  2053     NSString *result = [[[self webFrame] _bridge] stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]];
       
  2054     
       
  2055     // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
       
  2056     if (!isStarted) {
       
  2057         return;
       
  2058     }
       
  2059         
       
  2060     if ([JSPluginRequest frameName] != nil) {
       
  2061         // FIXME: If the result is a string, we probably want to put that string into the frame.
       
  2062         if ([JSPluginRequest sendNotification]) {
       
  2063             [self willCallPlugInFunction];
       
  2064             {
       
  2065                 KJS::JSLock::DropAllLocks dropAllLocks;
       
  2066                 NPP_URLNotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]);
       
  2067             }
       
  2068             [self didCallPlugInFunction];
       
  2069         }
       
  2070     } else if ([result length] > 0) {
       
  2071         // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
       
  2072         NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
       
  2073         WebBaseNetscapePluginStream *stream = [[WebBaseNetscapePluginStream alloc] initWithRequestURL:URL
       
  2074                                                                                                plugin:plugin
       
  2075                                                                                            notifyData:[JSPluginRequest notifyData]
       
  2076                                                                                      sendNotification:[JSPluginRequest sendNotification]];
       
  2077         [stream startStreamResponseURL:URL
       
  2078                  expectedContentLength:[JSData length]
       
  2079                       lastModifiedDate:nil
       
  2080                               MIMEType:@"text/plain"
       
  2081                                headers:nil];
       
  2082         [stream receivedData:JSData];
       
  2083         [stream finishedLoadingWithData:JSData];
       
  2084         [stream release];
       
  2085     }
       
  2086 }
       
  2087 
       
  2088 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason
       
  2089 {
       
  2090     ASSERT(isStarted);
       
  2091     
       
  2092     WebPluginRequest *pluginRequest = [pendingFrameLoads objectForKey:webFrame];
       
  2093     ASSERT(pluginRequest != nil);
       
  2094     ASSERT([pluginRequest sendNotification]);
       
  2095         
       
  2096     [self willCallPlugInFunction];
       
  2097     {
       
  2098         KJS::JSLock::DropAllLocks dropAllLocks;
       
  2099         NPP_URLNotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]);
       
  2100     }
       
  2101     [self didCallPlugInFunction];
       
  2102     
       
  2103     [pendingFrameLoads removeObjectForKey:webFrame];
       
  2104     [webFrame _setInternalLoadDelegate:nil];
       
  2105 }
       
  2106 
       
  2107 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error
       
  2108 {
       
  2109     NPReason reason = NPRES_DONE;
       
  2110     if (error != nil) {
       
  2111         reason = [WebBaseNetscapePluginStream reasonForError:error];
       
  2112     }    
       
  2113     [self webFrame:webFrame didFinishLoadWithReason:reason];
       
  2114 }
       
  2115 
       
  2116 - (void)loadPluginRequest:(WebPluginRequest *)pluginRequest
       
  2117 {
       
  2118     NSURLRequest *request = [pluginRequest request];
       
  2119     NSString *frameName = [pluginRequest frameName];
       
  2120     WebFrame *frame = nil;
       
  2121     
       
  2122     NSURL *URL = [request URL];
       
  2123     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
       
  2124     
       
  2125     ASSERT(frameName || JSString);
       
  2126     
       
  2127     if (frameName) {
       
  2128         // FIXME - need to get rid of this window creation which
       
  2129         // bypasses normal targeted link handling
       
  2130         frame = [[self webFrame] findFrameNamed:frameName];
       
  2131     
       
  2132         if (frame == nil) {
       
  2133             WebView *currentWebView = [self webView];
       
  2134             WebView *newWebView = CallUIDelegate(currentWebView, @selector(webView:createWebViewWithRequest:), nil);
       
  2135 
       
  2136             if (!newWebView) {
       
  2137                 if ([pluginRequest sendNotification]) {
       
  2138                     [self willCallPlugInFunction];
       
  2139                     {
       
  2140                         KJS::JSLock::DropAllLocks dropAllLocks;
       
  2141                         NPP_URLNotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]);
       
  2142                     }
       
  2143                     [self didCallPlugInFunction];
       
  2144                 }
       
  2145                 return;
       
  2146             }
       
  2147             
       
  2148             frame = [newWebView mainFrame];
       
  2149             core(frame)->tree()->setName(frameName);
       
  2150             [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
       
  2151         }
       
  2152     }
       
  2153 
       
  2154     if (JSString) {
       
  2155         ASSERT(frame == nil || [self webFrame] == frame);
       
  2156         [self evaluateJavaScriptPluginRequest:pluginRequest];
       
  2157     } else {
       
  2158         [frame loadRequest:request];
       
  2159         if ([pluginRequest sendNotification]) {
       
  2160             // Check if another plug-in view or even this view is waiting for the frame to load.
       
  2161             // If it is, tell it that the load was cancelled because it will be anyway.
       
  2162             WebBaseNetscapePluginView *view = [frame _internalLoadDelegate];
       
  2163             if (view != nil) {
       
  2164                 ASSERT([view isKindOfClass:[WebBaseNetscapePluginView class]]);
       
  2165                 [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK];
       
  2166             }
       
  2167             [pendingFrameLoads _webkit_setObject:pluginRequest forUncopiedKey:frame];
       
  2168             [frame _setInternalLoadDelegate:self];
       
  2169         }
       
  2170     }
       
  2171 }
       
  2172 
       
  2173 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification
       
  2174 {
       
  2175     NSURL *URL = [request URL];
       
  2176 
       
  2177     if (!URL) 
       
  2178         return NPERR_INVALID_URL;
       
  2179 
       
  2180     NSString *target = nil;
       
  2181     if (cTarget) {
       
  2182         // Find the frame given the target string.
       
  2183         target = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, cTarget, kCFStringEncodingWindowsLatin1);
       
  2184     }
       
  2185     WebFrame *frame = [self webFrame];
       
  2186 
       
  2187     // don't let a plugin start any loads if it is no longer part of a document that is being 
       
  2188     // displayed unless the loads are in the same frame as the plugin.
       
  2189     if ([[self dataSource] _documentLoader] != [[self webFrame] _frameLoader]->activeDocumentLoader() &&
       
  2190         (!cTarget || [frame findFrameNamed:target] != frame)) {
       
  2191         if (target)
       
  2192             CFRelease(target);
       
  2193         return NPERR_GENERIC_ERROR; 
       
  2194     }
       
  2195     
       
  2196     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
       
  2197     if (JSString != nil) {
       
  2198         if (![[[self webView] preferences] isJavaScriptEnabled]) {
       
  2199             // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
       
  2200             return NPERR_GENERIC_ERROR;
       
  2201         } else if (cTarget == NULL && mode == NP_FULL) {
       
  2202             // Don't allow a JavaScript request from a standalone plug-in that is self-targetted
       
  2203             // because this can cause the user to be redirected to a blank page (3424039).
       
  2204             return NPERR_INVALID_PARAM;
       
  2205         }
       
  2206     }
       
  2207         
       
  2208     if (cTarget || JSString) {
       
  2209         // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
       
  2210         // want to potentially kill the plug-in inside of its URL request.
       
  2211         
       
  2212         if (JSString != nil && target != nil && [frame findFrameNamed:target] != frame) {
       
  2213             // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
       
  2214             CFRelease(target);
       
  2215             return NPERR_INVALID_PARAM;
       
  2216         }
       
  2217         
       
  2218         WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request frameName:target notifyData:notifyData sendNotification:sendNotification didStartFromUserGesture:currentEventIsUserGesture];
       
  2219         [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0];
       
  2220         [pluginRequest release];
       
  2221         if (target)
       
  2222             CFRelease(target);
       
  2223     } else {
       
  2224         WebNetscapePluginStream *stream = [[WebNetscapePluginStream alloc] initWithRequest:request 
       
  2225                                                                                     plugin:plugin 
       
  2226                                                                                 notifyData:notifyData 
       
  2227                                                                           sendNotification:sendNotification];
       
  2228         if (!stream)
       
  2229             return NPERR_INVALID_URL;
       
  2230 
       
  2231         [streams addObject:stream];
       
  2232         [stream start];
       
  2233         [stream release];
       
  2234     }
       
  2235     
       
  2236     return NPERR_NO_ERROR;
       
  2237 }
       
  2238 
       
  2239 -(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData
       
  2240 {
       
  2241     LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget);
       
  2242 
       
  2243     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
       
  2244     return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES];
       
  2245 }
       
  2246 
       
  2247 -(NPError)getURL:(const char *)URLCString target:(const char *)cTarget
       
  2248 {
       
  2249     LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget);
       
  2250 
       
  2251     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
       
  2252     return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO];
       
  2253 }
       
  2254 
       
  2255 - (NPError)_postURL:(const char *)URLCString
       
  2256              target:(const char *)target
       
  2257                 len:(UInt32)len
       
  2258                 buf:(const char *)buf
       
  2259                file:(NPBool)file
       
  2260          notifyData:(void *)notifyData
       
  2261    sendNotification:(BOOL)sendNotification
       
  2262        allowHeaders:(BOOL)allowHeaders
       
  2263 {
       
  2264     if (!URLCString || !len || !buf) {
       
  2265         return NPERR_INVALID_PARAM;
       
  2266     }
       
  2267     
       
  2268     NSData *postData = nil;
       
  2269 
       
  2270     if (file) {
       
  2271         // If we're posting a file, buf is either a file URL or a path to the file.
       
  2272         NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1);
       
  2273         if (!bufString) {
       
  2274             return NPERR_INVALID_PARAM;
       
  2275         }
       
  2276         NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString];
       
  2277         NSString *path;
       
  2278         if ([fileURL isFileURL]) {
       
  2279             path = [fileURL path];
       
  2280         } else {
       
  2281             path = bufString;
       
  2282         }
       
  2283         postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
       
  2284         CFRelease(bufString);
       
  2285         if (!postData) {
       
  2286             return NPERR_FILE_NOT_FOUND;
       
  2287         }
       
  2288     } else {
       
  2289         postData = [NSData dataWithBytes:buf length:len];
       
  2290     }
       
  2291 
       
  2292     if ([postData length] == 0) {
       
  2293         return NPERR_INVALID_PARAM;
       
  2294     }
       
  2295 
       
  2296     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
       
  2297     [request setHTTPMethod:@"POST"];
       
  2298     
       
  2299     if (allowHeaders) {
       
  2300         if ([postData _web_startsWithBlankLine]) {
       
  2301             postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)];
       
  2302         } else {
       
  2303             NSInteger location = [postData _web_locationAfterFirstBlankLine];
       
  2304             if (location != NSNotFound) {
       
  2305                 // If the blank line is somewhere in the middle of postData, everything before is the header.
       
  2306                 NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)];
       
  2307                 NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
       
  2308                 unsigned dataLength = [postData length] - location;
       
  2309 
       
  2310                 // Sometimes plugins like to set Content-Length themselves when they post,
       
  2311                 // but WebFoundation does not like that. So we will remove the header
       
  2312                 // and instead truncate the data to the requested length.
       
  2313                 NSString *contentLength = [header objectForKey:@"Content-Length"];
       
  2314 
       
  2315                 if (contentLength != nil)
       
  2316                     dataLength = MIN((unsigned)[contentLength intValue], dataLength);
       
  2317                 [header removeObjectForKey:@"Content-Length"];
       
  2318 
       
  2319                 if ([header count] > 0) {
       
  2320                     [request setAllHTTPHeaderFields:header];
       
  2321                 }
       
  2322                 // Everything after the blank line is the actual content of the POST.
       
  2323                 postData = [postData subdataWithRange:NSMakeRange(location, dataLength)];
       
  2324 
       
  2325             }
       
  2326         }
       
  2327         if ([postData length] == 0) {
       
  2328             return NPERR_INVALID_PARAM;
       
  2329         }
       
  2330     }
       
  2331 
       
  2332     // Plug-ins expect to receive uncached data when doing a POST (3347134).
       
  2333     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
       
  2334     [request setHTTPBody:postData];
       
  2335     
       
  2336     return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification];
       
  2337 }
       
  2338 
       
  2339 - (NPError)postURLNotify:(const char *)URLCString
       
  2340                   target:(const char *)target
       
  2341                      len:(UInt32)len
       
  2342                      buf:(const char *)buf
       
  2343                     file:(NPBool)file
       
  2344               notifyData:(void *)notifyData
       
  2345 {
       
  2346     LOG(Plugins, "NPN_PostURLNotify: %s", URLCString);
       
  2347     return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES];
       
  2348 }
       
  2349 
       
  2350 -(NPError)postURL:(const char *)URLCString
       
  2351            target:(const char *)target
       
  2352               len:(UInt32)len
       
  2353               buf:(const char *)buf
       
  2354              file:(NPBool)file
       
  2355 {
       
  2356     LOG(Plugins, "NPN_PostURL: %s", URLCString);        
       
  2357     // As documented, only allow headers to be specified via NPP_PostURL when using a file.
       
  2358     return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file];
       
  2359 }
       
  2360 
       
  2361 -(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream
       
  2362 {
       
  2363     LOG(Plugins, "NPN_NewStream");
       
  2364     return NPERR_GENERIC_ERROR;
       
  2365 }
       
  2366 
       
  2367 -(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer
       
  2368 {
       
  2369     LOG(Plugins, "NPN_Write");
       
  2370     return NPERR_GENERIC_ERROR;
       
  2371 }
       
  2372 
       
  2373 -(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason
       
  2374 {
       
  2375     LOG(Plugins, "NPN_DestroyStream");
       
  2376     // This function does a sanity check to ensure that the NPStream provided actually
       
  2377     // belongs to the plug-in that provided it, which fixes a crash in the DivX 
       
  2378     // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203
       
  2379     if (!stream || [WebBaseNetscapePluginStream ownerForStream:stream] != plugin) {
       
  2380         LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream);
       
  2381         return NPERR_INVALID_INSTANCE_ERROR;
       
  2382     }
       
  2383     
       
  2384     WebBaseNetscapePluginStream *browserStream = static_cast<WebBaseNetscapePluginStream *>(stream->ndata);
       
  2385     [browserStream cancelLoadAndDestroyStreamWithError:[browserStream errorForReason:reason]];
       
  2386     
       
  2387     return NPERR_NO_ERROR;
       
  2388 }
       
  2389 
       
  2390 - (const char *)userAgent
       
  2391 {
       
  2392     return [[[self webView] userAgentForURL:baseURL] UTF8String];
       
  2393 }
       
  2394 
       
  2395 -(void)status:(const char *)message
       
  2396 {    
       
  2397     if (!message) {
       
  2398         LOG_ERROR("NPN_Status passed a NULL status message");
       
  2399         return;
       
  2400     }
       
  2401 
       
  2402     CFStringRef status = CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8);
       
  2403     if (!status) {
       
  2404         LOG_ERROR("NPN_Status: the message was not valid UTF-8");
       
  2405         return;
       
  2406     }
       
  2407     
       
  2408     LOG(Plugins, "NPN_Status: %@", status);
       
  2409     WebView *wv = [self webView];
       
  2410     [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status];
       
  2411     CFRelease(status);
       
  2412 }
       
  2413 
       
  2414 -(void)invalidateRect:(NPRect *)invalidRect
       
  2415 {
       
  2416     LOG(Plugins, "NPN_InvalidateRect");
       
  2417     [self setNeedsDisplayInRect:NSMakeRect(invalidRect->left, invalidRect->top,
       
  2418         (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)];
       
  2419 }
       
  2420 
       
  2421 -(bool)isOpaque
       
  2422 {
       
  2423     return YES;
       
  2424 }
       
  2425 
       
  2426 - (void)invalidateRegion:(NPRegion)invalidRegion
       
  2427 {
       
  2428     LOG(Plugins, "NPN_InvalidateRegion");
       
  2429     NSRect invalidRect = NSZeroRect;
       
  2430     switch (drawingModel) {
       
  2431 #ifndef NP_NO_QUICKDRAW
       
  2432         case NPDrawingModelQuickDraw:
       
  2433         {
       
  2434             ::Rect qdRect;
       
  2435             GetRegionBounds((NPQDRegion)invalidRegion, &qdRect);
       
  2436             invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top);
       
  2437         }
       
  2438         break;
       
  2439 #endif /* NP_NO_QUICKDRAW */
       
  2440         
       
  2441         case NPDrawingModelCoreGraphics:
       
  2442         case NPDrawingModelOpenGL:
       
  2443         {
       
  2444             CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion);
       
  2445             invalidRect = *(NSRect *)&cgRect;
       
  2446         }
       
  2447         break;
       
  2448     
       
  2449         default:
       
  2450             ASSERT_NOT_REACHED();
       
  2451         break;
       
  2452     }
       
  2453     
       
  2454     [self setNeedsDisplayInRect:invalidRect];
       
  2455 }
       
  2456 
       
  2457 -(void)forceRedraw
       
  2458 {
       
  2459     LOG(Plugins, "forceRedraw");
       
  2460     [self setNeedsDisplay:YES];
       
  2461     [[self window] displayIfNeeded];
       
  2462 }
       
  2463 
       
  2464 - (NPError)getVariable:(NPNVariable)variable value:(void *)value
       
  2465 {
       
  2466     switch (variable) {
       
  2467         case NPNVWindowNPObject:
       
  2468         {
       
  2469             Frame* frame = core([self webFrame]);
       
  2470             NPObject* windowScriptObject = frame ? frame->windowScriptNPObject() : 0;
       
  2471 
       
  2472             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
       
  2473             if (windowScriptObject)
       
  2474                 _NPN_RetainObject(windowScriptObject);
       
  2475             
       
  2476             void **v = (void **)value;
       
  2477             *v = windowScriptObject;
       
  2478 
       
  2479             return NPERR_NO_ERROR;
       
  2480         }
       
  2481 
       
  2482         case NPNVPluginElementNPObject:
       
  2483         {
       
  2484             if (!element)
       
  2485                 return NPERR_GENERIC_ERROR;
       
  2486             
       
  2487             NPObject *plugInScriptObject = (NPObject *)[element _NPObject];
       
  2488 
       
  2489             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
       
  2490             if (plugInScriptObject)
       
  2491                 _NPN_RetainObject(plugInScriptObject);
       
  2492 
       
  2493             void **v = (void **)value;
       
  2494             *v = plugInScriptObject;
       
  2495 
       
  2496             return NPERR_NO_ERROR;
       
  2497         }
       
  2498         
       
  2499         case NPNVpluginDrawingModel:
       
  2500         {
       
  2501             *(NPDrawingModel *)value = drawingModel;
       
  2502             return NPERR_NO_ERROR;
       
  2503         }
       
  2504 
       
  2505 #ifndef NP_NO_QUICKDRAW
       
  2506         case NPNVsupportsQuickDrawBool:
       
  2507         {
       
  2508             *(NPBool *)value = TRUE;
       
  2509             return NPERR_NO_ERROR;
       
  2510         }
       
  2511 #endif /* NP_NO_QUICKDRAW */
       
  2512         
       
  2513         case NPNVsupportsCoreGraphicsBool:
       
  2514         {
       
  2515             *(NPBool *)value = TRUE;
       
  2516             return NPERR_NO_ERROR;
       
  2517         }
       
  2518 
       
  2519         case NPNVsupportsOpenGLBool:
       
  2520         {
       
  2521             *(NPBool *)value = TRUE;
       
  2522             return NPERR_NO_ERROR;
       
  2523         }
       
  2524         
       
  2525         default:
       
  2526             break;
       
  2527     }
       
  2528 
       
  2529     return NPERR_GENERIC_ERROR;
       
  2530 }
       
  2531 
       
  2532 - (NPError)setVariable:(NPPVariable)variable value:(void *)value
       
  2533 {
       
  2534     switch (variable) {
       
  2535         case NPPVpluginWindowBool:
       
  2536         {
       
  2537             NPWindowType newWindowType = (value ? NPWindowTypeWindow : NPWindowTypeDrawable);
       
  2538 
       
  2539             // Redisplay if window type is changing (some drawing models can only have their windows set while updating).
       
  2540             if (newWindowType != window.type)
       
  2541                 [self setNeedsDisplay:YES];
       
  2542             
       
  2543             window.type = newWindowType;
       
  2544         }
       
  2545         
       
  2546         case NPPVpluginTransparentBool:
       
  2547         {
       
  2548             BOOL newTransparent = (value != 0);
       
  2549             
       
  2550             // Redisplay if transparency is changing
       
  2551             if (isTransparent != newTransparent)
       
  2552                 [self setNeedsDisplay:YES];
       
  2553             
       
  2554             isTransparent = newTransparent;
       
  2555             
       
  2556             return NPERR_NO_ERROR;
       
  2557         }
       
  2558         
       
  2559         case NPNVpluginDrawingModel:
       
  2560         {
       
  2561             // Can only set drawing model inside NPP_New()
       
  2562             if (self != [[self class] currentPluginView])
       
  2563                 return NPERR_GENERIC_ERROR;
       
  2564             
       
  2565             // Check for valid, supported drawing model
       
  2566             NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value;
       
  2567             switch (newDrawingModel) {
       
  2568                 // Supported drawing models:
       
  2569 #ifndef NP_NO_QUICKDRAW
       
  2570                 case NPDrawingModelQuickDraw:
       
  2571 #endif
       
  2572                 case NPDrawingModelCoreGraphics:
       
  2573                 case NPDrawingModelOpenGL:
       
  2574                     drawingModel = newDrawingModel;
       
  2575                     return NPERR_NO_ERROR;
       
  2576                 
       
  2577                 // Unsupported (or unknown) drawing models:
       
  2578                 default:
       
  2579                     LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", pluginPackage, drawingModel);
       
  2580                     return NPERR_GENERIC_ERROR;
       
  2581             }
       
  2582         }
       
  2583         
       
  2584         default:
       
  2585             return NPERR_GENERIC_ERROR;
       
  2586     }
       
  2587 }
       
  2588 
       
  2589 @end
       
  2590 
       
  2591 @implementation WebPluginRequest
       
  2592 
       
  2593 - (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture
       
  2594 {
       
  2595     [super init];
       
  2596     _didStartFromUserGesture = currentEventIsUserGesture;
       
  2597     _request = [request retain];
       
  2598     _frameName = [frameName retain];
       
  2599     _notifyData = notifyData;
       
  2600     _sendNotification = sendNotification;
       
  2601     return self;
       
  2602 }
       
  2603 
       
  2604 - (void)dealloc
       
  2605 {
       
  2606     [_request release];
       
  2607     [_frameName release];
       
  2608     [super dealloc];
       
  2609 }
       
  2610 
       
  2611 - (NSURLRequest *)request
       
  2612 {
       
  2613     return _request;
       
  2614 }
       
  2615 
       
  2616 - (NSString *)frameName
       
  2617 {
       
  2618     return _frameName;
       
  2619 }
       
  2620 
       
  2621 - (BOOL)isCurrentEventUserGesture
       
  2622 {
       
  2623     return _didStartFromUserGesture;
       
  2624 }
       
  2625 
       
  2626 - (BOOL)sendNotification
       
  2627 {
       
  2628     return _sendNotification;
       
  2629 }
       
  2630 
       
  2631 - (void *)notifyData
       
  2632 {
       
  2633     return _notifyData;
       
  2634 }
       
  2635 
       
  2636 @end
       
  2637 
       
  2638 @implementation WebBaseNetscapePluginView (Internal)
       
  2639 
       
  2640 - (NPError)_createPlugin
       
  2641 {
       
  2642     plugin = (NPP)calloc(1, sizeof(NPP_t));
       
  2643     plugin->ndata = self;
       
  2644 
       
  2645     ASSERT(NPP_New);
       
  2646 
       
  2647     // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance.
       
  2648     ASSERT(pluginFunctionCallDepth == 0);
       
  2649 
       
  2650     [[self class] setCurrentPluginView:self];
       
  2651     NPError npErr = NPP_New((char *)[MIMEType cString], plugin, mode, argsCount, cAttributes, cValues, NULL);
       
  2652     [[self class] setCurrentPluginView:nil];
       
  2653     
       
  2654     LOG(Plugins, "NPP_New: %d", npErr);
       
  2655     return npErr;
       
  2656 }
       
  2657 
       
  2658 - (void)_destroyPlugin
       
  2659 {
       
  2660     NPError npErr;
       
  2661     npErr = NPP_Destroy(plugin, NULL);
       
  2662     LOG(Plugins, "NPP_Destroy: %d", npErr);
       
  2663     
       
  2664     if (Frame* frame = core([self webFrame]))
       
  2665         frame->cleanupScriptObjectsForPlugin(self);
       
  2666         
       
  2667     free(plugin);
       
  2668     plugin = NULL;
       
  2669 }
       
  2670 
       
  2671 - (void)_viewHasMoved
       
  2672 {
       
  2673     // All of the work this method does may safely be skipped if the view is not in a window.  When the view
       
  2674     // is moved back into a window, everything should be set up correctly.
       
  2675     if (![self window])
       
  2676         return;
       
  2677     
       
  2678     if (drawingModel == NPDrawingModelOpenGL)
       
  2679         [self _reshapeAGLWindow];
       
  2680 
       
  2681 #ifndef NP_NO_QUICKDRAW
       
  2682     if (drawingModel == NPDrawingModelQuickDraw)
       
  2683         [self tellQuickTimeToChill];
       
  2684 #endif
       
  2685     [self updateAndSetWindow];
       
  2686     [self resetTrackingRect];
       
  2687     
       
  2688     // Check to see if the plugin view is completely obscured (scrolled out of view, for example).
       
  2689     // For performance reasons, we send null events at a lower rate to plugins which are obscured.
       
  2690     BOOL oldIsObscured = isCompletelyObscured;
       
  2691     isCompletelyObscured = NSIsEmptyRect([self visibleRect]);
       
  2692     if (isCompletelyObscured != oldIsObscured)
       
  2693         [self restartNullEvents];
       
  2694 }
       
  2695 
       
  2696 - (NSBitmapImageRep *)_printedPluginBitmap
       
  2697 {
       
  2698 #ifdef NP_NO_QUICKDRAW
       
  2699     return nil;
       
  2700 #else
       
  2701     // Cannot print plugins that do not implement NPP_Print
       
  2702     if (!NPP_Print)
       
  2703         return nil;
       
  2704 
       
  2705     // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into.
       
  2706     // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format.
       
  2707     NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
       
  2708                                                          pixelsWide:window.width
       
  2709                                                          pixelsHigh:window.height
       
  2710                                                          bitsPerSample:8
       
  2711                                                          samplesPerPixel:4
       
  2712                                                          hasAlpha:YES
       
  2713                                                          isPlanar:NO
       
  2714                                                          colorSpaceName:NSDeviceRGBColorSpace
       
  2715                                                          bitmapFormat:NSAlphaFirstBitmapFormat
       
  2716                                                          bytesPerRow:0
       
  2717                                                          bitsPerPixel:0] autorelease];
       
  2718     ASSERT(bitmap);
       
  2719     
       
  2720     // Create a GWorld with the same underlying buffer into which the plugin can draw
       
  2721     ::Rect printGWorldBounds;
       
  2722     SetRect(&printGWorldBounds, 0, 0, window.width, window.height);
       
  2723     GWorldPtr printGWorld;
       
  2724     if (NewGWorldFromPtr(&printGWorld,
       
  2725                          k32ARGBPixelFormat,
       
  2726                          &printGWorldBounds,
       
  2727                          NULL,
       
  2728                          NULL,
       
  2729                          0,
       
  2730                          (Ptr)[bitmap bitmapData],
       
  2731                          [bitmap bytesPerRow]) != noErr) {
       
  2732         LOG_ERROR("Could not create GWorld for printing");
       
  2733         return nil;
       
  2734     }
       
  2735     
       
  2736     /// Create NPWindow for the GWorld
       
  2737     NPWindow printNPWindow;
       
  2738     printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr
       
  2739     printNPWindow.x = 0;
       
  2740     printNPWindow.y = 0;
       
  2741     printNPWindow.width = window.width;
       
  2742     printNPWindow.height = window.height;
       
  2743     printNPWindow.clipRect.top = 0;
       
  2744     printNPWindow.clipRect.left = 0;
       
  2745     printNPWindow.clipRect.right = window.width;
       
  2746     printNPWindow.clipRect.bottom = window.height;
       
  2747     printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window
       
  2748     
       
  2749     // Create embed-mode NPPrint
       
  2750     NPPrint npPrint;
       
  2751     npPrint.mode = NP_EMBED;
       
  2752     npPrint.print.embedPrint.window = printNPWindow;
       
  2753     npPrint.print.embedPrint.platformPrint = printGWorld;
       
  2754     
       
  2755     // Tell the plugin to print into the GWorld
       
  2756     [self willCallPlugInFunction];
       
  2757     {
       
  2758         KJS::JSLock::DropAllLocks dropAllLocks;
       
  2759         NPP_Print(plugin, &npPrint);
       
  2760     }
       
  2761     [self didCallPlugInFunction];
       
  2762 
       
  2763     // Don't need the GWorld anymore
       
  2764     DisposeGWorld(printGWorld);
       
  2765         
       
  2766     return bitmap;
       
  2767 #endif
       
  2768 }
       
  2769 
       
  2770 - (BOOL)_createAGLContextIfNeeded
       
  2771 {
       
  2772     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  2773 
       
  2774     // Do nothing (but indicate success) if the AGL context already exists
       
  2775     if (aglContext)
       
  2776         return YES;
       
  2777         
       
  2778     switch (window.type) {
       
  2779         case NPWindowTypeWindow:
       
  2780             return [self _createWindowedAGLContext];
       
  2781         
       
  2782         case NPWindowTypeDrawable:
       
  2783             return [self _createWindowlessAGLContext];
       
  2784         
       
  2785         default:
       
  2786             ASSERT_NOT_REACHED();
       
  2787             return NO;
       
  2788     }
       
  2789 }
       
  2790 
       
  2791 - (BOOL)_createWindowedAGLContext
       
  2792 {
       
  2793     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  2794     ASSERT(!aglContext);
       
  2795     ASSERT(!aglWindow);
       
  2796     ASSERT([self window]);
       
  2797     
       
  2798     GLint pixelFormatAttributes[] = {
       
  2799         AGL_RGBA,
       
  2800         AGL_RED_SIZE, 8,
       
  2801         AGL_GREEN_SIZE, 8,
       
  2802         AGL_BLUE_SIZE, 8,
       
  2803         AGL_ALPHA_SIZE, 8,
       
  2804         AGL_DEPTH_SIZE, 32,
       
  2805         AGL_WINDOW,
       
  2806         AGL_ACCELERATED,
       
  2807         0
       
  2808     };
       
  2809     
       
  2810     // Choose AGL pixel format
       
  2811     AGLPixelFormat pixelFormat = aglChoosePixelFormat(NULL, 0, pixelFormatAttributes);
       
  2812     if (!pixelFormat) {
       
  2813         LOG_ERROR("Could not find suitable AGL pixel format: %s", aglErrorString(aglGetError()));
       
  2814         return NO;
       
  2815     }
       
  2816     
       
  2817     // Create AGL context
       
  2818     aglContext = aglCreateContext(pixelFormat, NULL);
       
  2819     aglDestroyPixelFormat(pixelFormat);
       
  2820     if (!aglContext) {
       
  2821         LOG_ERROR("Could not create AGL context: %s", aglErrorString(aglGetError()));
       
  2822         return NO;
       
  2823     }
       
  2824     
       
  2825     // Create AGL window
       
  2826     aglWindow = [[NSWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
       
  2827     if (!aglWindow) {
       
  2828         LOG_ERROR("Could not create window for AGL drawable.");
       
  2829         return NO;
       
  2830     }
       
  2831     
       
  2832     // AGL window should allow clicks to go through -- mouse events are tracked by WebCore
       
  2833     [aglWindow setIgnoresMouseEvents:YES];
       
  2834     
       
  2835     // Make sure the window is not opaque -- windowed plug-ins cannot layer with other page elements
       
  2836     [aglWindow setOpaque:YES];
       
  2837 
       
  2838     // Position and order in the AGL window
       
  2839     [self _reshapeAGLWindow];
       
  2840 
       
  2841     // Attach the AGL context to its window
       
  2842     GLboolean success;
       
  2843 #ifdef AGL_VERSION_3_0
       
  2844     success = aglSetWindowRef(aglContext, (WindowRef)[aglWindow windowRef]);
       
  2845 #else
       
  2846     success = aglSetDrawable(aglContext, (AGLDrawable)GetWindowPort((WindowRef)[aglWindow windowRef]));
       
  2847 #endif
       
  2848     if (!success) {
       
  2849         LOG_ERROR("Could not set AGL drawable: %s", aglErrorString(aglGetError()));
       
  2850         aglDestroyContext(aglContext);
       
  2851         aglContext = NULL;
       
  2852         return NO;
       
  2853     }
       
  2854         
       
  2855     return YES;
       
  2856 }
       
  2857 
       
  2858 - (BOOL)_createWindowlessAGLContext
       
  2859 {
       
  2860     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  2861     ASSERT(!aglContext);
       
  2862     ASSERT(!aglWindow);
       
  2863     
       
  2864     GLint pixelFormatAttributes[] = {
       
  2865         AGL_RGBA,
       
  2866         AGL_RED_SIZE, 8,
       
  2867         AGL_GREEN_SIZE, 8,
       
  2868         AGL_BLUE_SIZE, 8,
       
  2869         AGL_ALPHA_SIZE, 8,
       
  2870         AGL_DEPTH_SIZE, 32,
       
  2871         AGL_OFFSCREEN,
       
  2872         0
       
  2873     };
       
  2874 
       
  2875     // Choose AGL pixel format
       
  2876     AGLPixelFormat pixelFormat = aglChoosePixelFormat(NULL, 0, pixelFormatAttributes);
       
  2877     if (!pixelFormat) {
       
  2878         LOG_ERROR("Could not find suitable AGL pixel format: %s", aglErrorString(aglGetError()));
       
  2879         return NO;
       
  2880     }
       
  2881     
       
  2882     // Create AGL context
       
  2883     aglContext = aglCreateContext(pixelFormat, NULL);
       
  2884     aglDestroyPixelFormat(pixelFormat);
       
  2885     if (!aglContext) {
       
  2886         LOG_ERROR("Could not create AGL context: %s", aglErrorString(aglGetError()));
       
  2887         return NO;
       
  2888     }
       
  2889     
       
  2890     // Create offscreen buffer for AGL context
       
  2891     NSSize boundsSize = [self bounds].size;
       
  2892     GLvoid *offscreenBuffer = (GLvoid *)malloc(static_cast<size_t>(boundsSize.width * boundsSize.height * 4));
       
  2893     if (!offscreenBuffer) {
       
  2894         LOG_ERROR("Could not allocate offscreen buffer for AGL context");
       
  2895         aglDestroyContext(aglContext);
       
  2896         aglContext = NULL;
       
  2897         return NO;
       
  2898     }
       
  2899     
       
  2900     // Attach AGL context to offscreen buffer
       
  2901     CGLContextObj cglContext = [self _cglContext];
       
  2902     CGLError error = CGLSetOffScreen(cglContext, static_cast<long>(boundsSize.width), static_cast<long>(boundsSize.height), static_cast<long>(boundsSize.width * 4), offscreenBuffer);
       
  2903     if (error) {
       
  2904         LOG_ERROR("Could not set offscreen buffer for AGL context: %d", error);
       
  2905         aglDestroyContext(aglContext);
       
  2906         aglContext = NULL;
       
  2907         return NO;
       
  2908     }
       
  2909     
       
  2910     return YES;
       
  2911 }
       
  2912 
       
  2913 - (CGLContextObj)_cglContext
       
  2914 {
       
  2915     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  2916 
       
  2917     CGLContextObj cglContext = NULL;
       
  2918     if (!aglGetCGLContext(aglContext, (void **)&cglContext) || !cglContext)
       
  2919         LOG_ERROR("Could not get CGL context for AGL context: %s", aglErrorString(aglGetError()));
       
  2920         
       
  2921     return cglContext;
       
  2922 }
       
  2923 
       
  2924 - (BOOL)_getAGLOffscreenBuffer:(GLvoid **)outBuffer width:(GLsizei *)outWidth height:(GLsizei *)outHeight
       
  2925 {
       
  2926     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  2927     
       
  2928     if (outBuffer)
       
  2929         *outBuffer = NULL;
       
  2930     if (outWidth)
       
  2931         *outWidth = 0;
       
  2932     if (outHeight)
       
  2933         *outHeight = 0;
       
  2934     
       
  2935     // Only windowless plug-ins have offscreen buffers
       
  2936     if (window.type != NPWindowTypeDrawable)
       
  2937         return NO;
       
  2938     
       
  2939     CGLContextObj cglContext = [self _cglContext];
       
  2940     if (!cglContext)
       
  2941         return NO;
       
  2942     
       
  2943     GLsizei width, height;
       
  2944     GLint rowBytes;
       
  2945     void *offscreenBuffer = NULL;
       
  2946     CGLError error = CGLGetOffScreen(cglContext, &width, &height, &rowBytes, &offscreenBuffer);
       
  2947     if (error || !offscreenBuffer) {
       
  2948         LOG_ERROR("Could not get offscreen buffer for AGL context: %d", error);
       
  2949         return NO;
       
  2950     }
       
  2951     
       
  2952     if (outBuffer)
       
  2953         *outBuffer = offscreenBuffer;
       
  2954     if (outWidth)
       
  2955         *outWidth = width;
       
  2956     if (outHeight)
       
  2957         *outHeight = height;
       
  2958     
       
  2959     return YES;
       
  2960 }
       
  2961 
       
  2962 - (void)_destroyAGLContext
       
  2963 {    
       
  2964     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  2965 
       
  2966     if (!aglContext)
       
  2967         return;
       
  2968 
       
  2969     if (aglContext) {
       
  2970         // If this is a windowless plug-in, free its offscreen buffer
       
  2971         GLvoid *offscreenBuffer;
       
  2972         if ([self _getAGLOffscreenBuffer:&offscreenBuffer width:NULL height:NULL])
       
  2973             free(offscreenBuffer);
       
  2974         
       
  2975         // Detach context from the AGL window
       
  2976 #ifdef AGL_VERSION_3_0
       
  2977         aglSetWindowRef(aglContext, NULL);
       
  2978 #else
       
  2979         aglSetDrawable(aglContext, NULL);
       
  2980 #endif
       
  2981         
       
  2982         // Destroy the context
       
  2983         aglDestroyContext(aglContext);
       
  2984         aglContext = NULL;
       
  2985     }
       
  2986     
       
  2987     // Destroy the AGL window
       
  2988     if (aglWindow) {
       
  2989         [self _hideAGLWindow];
       
  2990         aglWindow = nil;
       
  2991     }
       
  2992 }
       
  2993 
       
  2994 - (void)_reshapeAGLWindow
       
  2995 {
       
  2996     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  2997     
       
  2998     if (!aglContext)
       
  2999         return;
       
  3000 
       
  3001     switch (window.type) {
       
  3002         case NPWindowTypeWindow:
       
  3003         {
       
  3004             if (!aglWindow)
       
  3005                 break;
       
  3006                 
       
  3007             // The AGL window is being reshaped because the plugin view has moved.  Since the view has moved, it will soon redraw.
       
  3008             // We want the AGL window to update at the same time as its underlying view.  So, we disable screen updates until the
       
  3009             // plugin view's window flushes.
       
  3010             NSWindow *browserWindow = [self window];
       
  3011             ASSERT(browserWindow);
       
  3012             [browserWindow disableScreenUpdatesUntilFlush];
       
  3013 
       
  3014             // Add the AGL window as a child of the main window if necessary
       
  3015             if ([aglWindow parentWindow] != browserWindow)
       
  3016                 [browserWindow addChildWindow:aglWindow ordered:NSWindowAbove];
       
  3017             
       
  3018             // Update the AGL window frame
       
  3019             NSRect aglWindowFrame = [self convertRect:[self visibleRect] toView:nil];
       
  3020             aglWindowFrame.origin = [browserWindow convertBaseToScreen:aglWindowFrame.origin];
       
  3021             [aglWindow setFrame:aglWindowFrame display:NO];
       
  3022             
       
  3023             // Update the AGL context
       
  3024             aglUpdateContext(aglContext);
       
  3025         }
       
  3026         break;
       
  3027         
       
  3028         case NPWindowTypeDrawable:
       
  3029         {
       
  3030             // Get offscreen buffer; we can skip this step if we don't have one yet
       
  3031             GLvoid *offscreenBuffer;
       
  3032             GLsizei width, height;
       
  3033             if (![self _getAGLOffscreenBuffer:&offscreenBuffer width:&width height:&height] || !offscreenBuffer)
       
  3034                 break;
       
  3035             
       
  3036             // Don't resize the offscreen buffer if it's already the same size as the view bounds
       
  3037             NSSize boundsSize = [self bounds].size;
       
  3038             if (boundsSize.width == width && boundsSize.height == height)
       
  3039                 break;
       
  3040             
       
  3041             // Resize the offscreen buffer
       
  3042             offscreenBuffer = realloc(offscreenBuffer, static_cast<size_t>(boundsSize.width * boundsSize.height * 4));
       
  3043             if (!offscreenBuffer) {
       
  3044                 LOG_ERROR("Could not allocate offscreen buffer for AGL context");
       
  3045                 break;
       
  3046             }
       
  3047 
       
  3048             // Update the offscreen 
       
  3049             CGLContextObj cglContext = [self _cglContext];
       
  3050             CGLError error = CGLSetOffScreen(cglContext, static_cast<long>(boundsSize.width), static_cast<long>(boundsSize.height), static_cast<long>(boundsSize.width * 4), offscreenBuffer);
       
  3051             if (error) {
       
  3052                 LOG_ERROR("Could not set offscreen buffer for AGL context: %d", error);
       
  3053                 break;
       
  3054             }
       
  3055 
       
  3056             // Update the AGL context
       
  3057             aglUpdateContext(aglContext);
       
  3058         }
       
  3059         break;
       
  3060         
       
  3061         default:
       
  3062             ASSERT_NOT_REACHED();
       
  3063         break;
       
  3064     }
       
  3065 }
       
  3066 
       
  3067 - (void)_hideAGLWindow
       
  3068 {
       
  3069     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  3070     
       
  3071     if (!aglWindow)
       
  3072         return;
       
  3073     
       
  3074     // aglWindow should only be set for a windowed OpenGL plug-in
       
  3075     ASSERT(window.type == NPWindowTypeWindow);
       
  3076     
       
  3077     NSWindow *parentWindow = [aglWindow parentWindow];
       
  3078     if (parentWindow) {
       
  3079         // Disable screen updates so that this AGL window orders out atomically with other plugins' AGL windows
       
  3080         [parentWindow disableScreenUpdatesUntilFlush];
       
  3081         ASSERT(parentWindow == [self window]);
       
  3082         [parentWindow removeChildWindow:aglWindow];
       
  3083     }
       
  3084     [aglWindow orderOut:nil];
       
  3085 }
       
  3086 
       
  3087 - (NSImage *)_aglOffscreenImageForDrawingInRect:(NSRect)drawingInRect
       
  3088 {
       
  3089     ASSERT(drawingModel == NPDrawingModelOpenGL);
       
  3090 
       
  3091     CGLContextObj cglContext = [self _cglContext];
       
  3092     if (!cglContext)
       
  3093         return nil;
       
  3094 
       
  3095     // Get the offscreen buffer
       
  3096     GLvoid *offscreenBuffer;
       
  3097     GLsizei width, height;
       
  3098     if (![self _getAGLOffscreenBuffer:&offscreenBuffer width:&width height:&height])
       
  3099         return nil;
       
  3100 
       
  3101     unsigned char *plane = (unsigned char *)offscreenBuffer;
       
  3102 
       
  3103 #if defined(__i386__) || defined(__x86_64__)
       
  3104     // Make rect inside the offscreen buffer because we're about to directly modify the bits inside drawingInRect
       
  3105     NSRect rect = NSIntegralRect(NSIntersectionRect(drawingInRect, NSMakeRect(0, 0, width, height)));
       
  3106 
       
  3107     // The offscreen buffer, being an OpenGL framebuffer, is in BGRA format on x86.  We need to swap the blue and red channels before
       
  3108     // wrapping the buffer in an NSBitmapImageRep, which only supports RGBA and ARGB.
       
  3109     // On PowerPC, the OpenGL framebuffer is in ARGB format.  Since that is a format that NSBitmapImageRep supports, all that is
       
  3110     // needed on PowerPC is to pass the NSAlphaFirstBitmapFormat flag when creating the NSBitmapImageRep.  On x86, we need to swap the
       
  3111     // framebuffer color components such that they are in ARGB order, as they are on PowerPC.
       
  3112     // If only a small region of the plug-in is being redrawn, then it would be a waste to convert the entire image from BGRA to ARGB.
       
  3113     // Since we know what region of the image will ultimately be drawn to screen (drawingInRect), we restrict the channel swapping to
       
  3114     // just that region within the offscreen buffer.
       
  3115     if (!WebConvertBGRAToARGB(plane, width * 4, (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height))
       
  3116         return nil;
       
  3117 #endif /* defined(__i386__) || defined(__x86_64__) */
       
  3118     
       
  3119     NSBitmapImageRep *aglBitmap = [[NSBitmapImageRep alloc]
       
  3120         initWithBitmapDataPlanes:&plane
       
  3121                       pixelsWide:width
       
  3122                       pixelsHigh:height
       
  3123                    bitsPerSample:8
       
  3124                  samplesPerPixel:4
       
  3125                         hasAlpha:YES
       
  3126                         isPlanar:NO
       
  3127                   colorSpaceName:NSDeviceRGBColorSpace
       
  3128                     bitmapFormat:NSAlphaFirstBitmapFormat
       
  3129                      bytesPerRow:width * 4
       
  3130                     bitsPerPixel:32];
       
  3131     if (!aglBitmap) {
       
  3132         LOG_ERROR("Could not create bitmap for AGL offscreen buffer");
       
  3133         return nil;
       
  3134     }
       
  3135 
       
  3136     // Wrap the bitmap in an NSImage.  This allocation isn't very expensive -- the actual image data is already in the bitmap rep
       
  3137     NSImage *aglImage = [[[NSImage alloc] initWithSize:[aglBitmap size]] autorelease];
       
  3138     [aglImage addRepresentation:aglBitmap];
       
  3139     [aglBitmap release];
       
  3140     
       
  3141     return aglImage;
       
  3142 }
       
  3143 
       
  3144 - (void)_redeliverStream
       
  3145 {
       
  3146     if ([self dataSource] && [self isStarted]) {
       
  3147         // Deliver what has not been passed to the plug-in up to this point.
       
  3148         if (_dataLengthReceived > 0) {
       
  3149             NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)];
       
  3150             _dataLengthReceived = 0;
       
  3151             [self pluginView:self receivedData:data];
       
  3152             if (![[self dataSource] isLoading]) {
       
  3153                 if (_error)
       
  3154                     [self pluginView:self receivedError:_error];
       
  3155                 else
       
  3156                     [self pluginViewFinishedLoading:self];
       
  3157             }
       
  3158         }
       
  3159     }
       
  3160 }
       
  3161 
       
  3162 @end
       
  3163 
       
  3164 @implementation NSData (PluginExtras)
       
  3165 
       
  3166 - (BOOL)_web_startsWithBlankLine
       
  3167 {
       
  3168     return [self length] > 0 && ((const char *)[self bytes])[0] == '\n';
       
  3169 }
       
  3170 
       
  3171 
       
  3172 - (NSInteger)_web_locationAfterFirstBlankLine
       
  3173 {
       
  3174     const char *bytes = (const char *)[self bytes];
       
  3175     unsigned length = [self length];
       
  3176     
       
  3177     unsigned i;
       
  3178     for (i = 0; i < length - 4; i++) {
       
  3179         
       
  3180         //  Support for Acrobat. It sends "\n\n".
       
  3181         if (bytes[i] == '\n' && bytes[i+1] == '\n') {
       
  3182             return i+2;
       
  3183         }
       
  3184         
       
  3185         // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
       
  3186         if (bytes[i] == '\r' && bytes[i+1] == '\n') {
       
  3187             i += 2;
       
  3188             if (i == 2) {
       
  3189                 return i;
       
  3190             } else if (bytes[i] == '\n') {
       
  3191                 // Support for Director. It sends "\r\n\n" (3880387).
       
  3192                 return i+1;
       
  3193             } else if (bytes[i] == '\r' && bytes[i+1] == '\n') {
       
  3194                 // Support for Flash. It sends "\r\n\r\n" (3758113).
       
  3195                 return i+2;
       
  3196             }
       
  3197         }
       
  3198     }
       
  3199     return NSNotFound;
       
  3200 }
       
  3201 
       
  3202 @end
       
  3203 #endif