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