2011-04-25 Adam Barth <abarth@webkit.org>
[WebKit-https.git] / Source / WebKit / mac / Plugins / WebNetscapePluginView.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 #if ENABLE(NETSCAPE_PLUGIN_API)
30
31 #import "WebNetscapePluginView.h"
32
33 #import "QuickDrawCompatibility.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebDefaultUIDelegate.h"
36 #import "WebFrameInternal.h" 
37 #import "WebFrameView.h"
38 #import "WebKitErrorsPrivate.h"
39 #import "WebKitLogging.h"
40 #import "WebKitNSStringExtras.h"
41 #import "WebKitSystemInterface.h"
42 #import "WebNSDataExtras.h"
43 #import "WebNSDictionaryExtras.h"
44 #import "WebNSObjectExtras.h"
45 #import "WebNSURLExtras.h"
46 #import "WebNSURLRequestExtras.h"
47 #import "WebNSViewExtras.h"
48 #import "WebNetscapeContainerCheckContextInfo.h"
49 #import "WebNetscapeContainerCheckPrivate.h"
50 #import "WebNetscapePluginEventHandler.h"
51 #import "WebNetscapePluginPackage.h"
52 #import "WebNetscapePluginStream.h"
53 #import "WebPluginContainerCheck.h"
54 #import "WebPluginRequest.h"
55 #import "WebPreferences.h"
56 #import "WebUIDelegatePrivate.h"
57 #import "WebViewInternal.h"
58 #import <Carbon/Carbon.h>
59 #import <WebCore/CookieJar.h>
60 #import <WebCore/DocumentLoader.h>
61 #import <WebCore/Element.h>
62 #import <WebCore/Frame.h> 
63 #import <WebCore/FrameLoader.h> 
64 #import <WebCore/FrameTree.h>
65 #import <WebCore/FrameView.h>
66 #import <WebCore/HTMLPlugInElement.h>
67 #import <WebCore/Page.h> 
68 #import <WebCore/PluginMainThreadScheduler.h>
69 #import <WebCore/ProxyServer.h>
70 #import <WebCore/ScriptController.h>
71 #import <WebCore/SecurityOrigin.h>
72 #import <WebCore/SoftLinking.h> 
73 #import <WebCore/WebCoreObjCExtras.h>
74 #import <WebCore/WebCoreURLResponse.h>
75 #import <WebCore/npruntime_impl.h>
76 #import <WebKit/DOMPrivate.h>
77 #import <WebKit/WebUIDelegate.h>
78 #import <objc/objc-runtime.h>
79 #import <runtime/InitializeThreading.h>
80 #import <runtime/JSLock.h>
81 #import <wtf/Assertions.h>
82 #import <wtf/Threading.h>
83 #import <wtf/text/CString.h>
84
85 #define LoginWindowDidSwitchFromUserNotification    @"WebLoginWindowDidSwitchFromUserNotification"
86 #define LoginWindowDidSwitchToUserNotification      @"WebLoginWindowDidSwitchToUserNotification"
87 #define WKNVSupportsCompositingCoreAnimationPluginsBool 74656  /* TRUE if the browser supports hardware compositing of Core Animation plug-ins  */
88 static const int WKNVSilverlightFullscreenPerformanceIssueFixed = 7288546; /* TRUE if Siverlight addressed its underlying  bug in <rdar://problem/7288546> */
89
90 using namespace WebCore;
91 using namespace WebKit;
92 using namespace std;
93
94 static inline bool isDrawingModelQuickDraw(NPDrawingModel drawingModel)
95 {
96 #ifndef NP_NO_QUICKDRAW
97     return drawingModel == NPDrawingModelQuickDraw;
98 #else
99     return false;
100 #endif
101 };
102
103 @interface WebNetscapePluginView (Internal)
104 - (NPError)_createPlugin;
105 - (void)_destroyPlugin;
106 - (NSBitmapImageRep *)_printedPluginBitmap;
107 - (void)_redeliverStream;
108 - (BOOL)_shouldCancelSrcStream;
109 @end
110
111 static WebNetscapePluginView *currentPluginView = nil;
112
113 typedef struct OpaquePortState* PortState;
114
115 static const double ThrottledTimerInterval = 0.25;
116
117 class PluginTimer : public TimerBase {
118 public:
119     typedef void (*TimerFunc)(NPP npp, uint32_t timerID);
120     
121     PluginTimer(NPP npp, uint32_t timerID, uint32_t interval, NPBool repeat, TimerFunc timerFunc)
122         : m_npp(npp)
123         , m_timerID(timerID)
124         , m_interval(interval)
125         , m_repeat(repeat)
126         , m_timerFunc(timerFunc)
127     {
128     }
129     
130     void start(bool throttle)
131     {
132         ASSERT(!isActive());
133
134         double timeInterval = m_interval / 1000.0;
135         
136         if (throttle)
137             timeInterval = max(timeInterval, ThrottledTimerInterval);
138         
139         if (m_repeat)
140             startRepeating(timeInterval);
141         else
142             startOneShot(timeInterval);
143     }
144
145 private:
146     virtual void fired() 
147     {
148         m_timerFunc(m_npp, m_timerID);
149         if (!m_repeat)
150             delete this;
151     }
152     
153     NPP m_npp;
154     uint32_t m_timerID;
155     uint32_t m_interval;
156     NPBool m_repeat;
157     TimerFunc m_timerFunc;
158 };
159
160 #ifndef NP_NO_QUICKDRAW
161
162 // QuickDraw is not available in 64-bit
163
164 typedef struct {
165     GrafPtr oldPort;
166     GDHandle oldDevice;
167     Point oldOrigin;
168     RgnHandle oldClipRegion;
169     RgnHandle oldVisibleRegion;
170     RgnHandle clipRegion;
171     BOOL forUpdate;
172 } PortState_QD;
173
174 #endif /* NP_NO_QUICKDRAW */
175
176 typedef struct {
177     CGContextRef context;
178 } PortState_CG;
179
180 @class NSTextInputContext;
181 @interface NSResponder (AppKitDetails)
182 - (NSTextInputContext *)inputContext;
183 @end
184
185 @interface WebNetscapePluginView (ForwardDeclarations)
186 - (void)setWindowIfNecessary;
187 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification;
188 @end
189
190 @implementation WebNetscapePluginView
191
192 + (void)initialize
193 {
194     JSC::initializeThreading();
195     WTF::initializeMainThreadToProcessMainThread();
196 #ifndef BUILDING_ON_TIGER
197     WebCoreObjCFinalizeOnMainThread(self);
198 #endif
199     WKSendUserChangeNotifications();
200 }
201
202 // MARK: EVENTS
203
204 // The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers 
205 // the entire window frame (or structure region to use the Carbon term) rather then just the window content.
206 // We can remove this when <rdar://problem/4201099> is fixed.
207 - (void)fixWindowPort
208 {
209 #ifndef NP_NO_QUICKDRAW
210     ASSERT(isDrawingModelQuickDraw(drawingModel));
211     
212     NSWindow *currentWindow = [self currentWindow];
213     if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")])
214         return;
215     
216     float windowHeight = [currentWindow frame].size.height;
217     NSView *contentView = [currentWindow contentView];
218     NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates
219     
220     CGrafPtr oldPort;
221     GetPort(&oldPort);    
222     SetPort(GetWindowPort((WindowRef)[currentWindow windowRef]));
223     
224     MovePortTo(static_cast<short>(contentRect.origin.x), /* Flip Y */ static_cast<short>(windowHeight - NSMaxY(contentRect)));
225     PortSize(static_cast<short>(contentRect.size.width), static_cast<short>(contentRect.size.height));
226     
227     SetPort(oldPort);
228 #endif
229 }
230
231 #ifndef NP_NO_QUICKDRAW
232 static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context)
233 {
234     UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) & kCGBitmapByteOrderMask;
235     if (byteOrder == kCGBitmapByteOrderDefault)
236         switch (CGBitmapContextGetBitsPerPixel(context)) {
237             case 16:
238                 byteOrder = kCGBitmapByteOrder16Host;
239                 break;
240             case 32:
241                 byteOrder = kCGBitmapByteOrder32Host;
242                 break;
243         }
244     switch (byteOrder) {
245         case kCGBitmapByteOrder16Little:
246             return k16LE555PixelFormat;
247         case kCGBitmapByteOrder32Little:
248             return k32BGRAPixelFormat;
249         case kCGBitmapByteOrder16Big:
250             return k16BE555PixelFormat;
251         case kCGBitmapByteOrder32Big:
252             return k32ARGBPixelFormat;
253     }
254     ASSERT_NOT_REACHED();
255     return 0;
256 }
257
258 static inline void getNPRect(const CGRect& cgr, NPRect& npr)
259 {
260     npr.top = static_cast<uint16_t>(cgr.origin.y);
261     npr.left = static_cast<uint16_t>(cgr.origin.x);
262     npr.bottom = static_cast<uint16_t>(CGRectGetMaxY(cgr));
263     npr.right = static_cast<uint16_t>(CGRectGetMaxX(cgr));
264 }
265
266 #endif
267
268 static inline void getNPRect(const NSRect& nr, NPRect& npr)
269 {
270     npr.top = static_cast<uint16_t>(nr.origin.y);
271     npr.left = static_cast<uint16_t>(nr.origin.x);
272     npr.bottom = static_cast<uint16_t>(NSMaxY(nr));
273     npr.right = static_cast<uint16_t>(NSMaxX(nr));
274 }
275
276 - (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate
277 {
278     ASSERT([self currentWindow] != nil);
279     
280     // The base coordinates of a window and it's contentView happen to be the equal at a userSpaceScaleFactor
281     // of 1. For non-1.0 scale factors this assumption is false.
282     NSView *windowContentView = [[self window] contentView];
283     NSRect boundsInWindow = [self convertRect:[self bounds] toView:windowContentView];
284     NSRect visibleRectInWindow = [self actualVisibleRectInWindow];
285     
286     // Flip Y to convert -[NSWindow contentView] coordinates to top-left-based window coordinates.
287     float borderViewHeight = [[self currentWindow] frame].size.height;
288     boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow);
289     visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow);
290     
291 #ifndef NP_NO_QUICKDRAW
292     WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
293     ASSERT(windowRef);
294
295     // Look at the Carbon port to convert top-left-based window coordinates into top-left-based content coordinates.
296     if (isDrawingModelQuickDraw(drawingModel)) {
297         // If drawing with QuickDraw, fix the window port so that it has the same bounds as the NSWindow's
298         // content view.  This makes it easier to convert between AppKit view and QuickDraw port coordinates.
299         [self fixWindowPort];
300         
301         ::Rect portBounds;
302         CGrafPtr port = GetWindowPort(windowRef);
303         GetPortBounds(port, &portBounds);
304
305         PixMap *pix = *GetPortPixMap(port);
306         boundsInWindow.origin.x += pix->bounds.left - portBounds.left;
307         boundsInWindow.origin.y += pix->bounds.top - portBounds.top;
308         visibleRectInWindow.origin.x += pix->bounds.left - portBounds.left;
309         visibleRectInWindow.origin.y += pix->bounds.top - portBounds.top;
310     }
311 #endif
312     
313     window.type = NPWindowTypeWindow;
314     window.x = (int32_t)boundsInWindow.origin.x; 
315     window.y = (int32_t)boundsInWindow.origin.y;
316     window.width = static_cast<uint32_t>(NSWidth(boundsInWindow));
317     window.height = static_cast<uint32_t>(NSHeight(boundsInWindow));
318     
319     // "Clip-out" the plug-in when:
320     // 1) it's not really in a window or off-screen or has no height or width.
321     // 2) window.x is a "big negative number" which is how WebCore expresses off-screen widgets.
322     // 3) the window is miniaturized or the app is hidden
323     // 4) we're inside of viewWillMoveToWindow: with a nil window. In this case, superviews may already have nil 
324     // superviews and nil windows and results from convertRect:toView: are incorrect.
325     if (window.width <= 0 || window.height <= 0 || window.x < -100000 || [self shouldClipOutPlugin]) {
326
327         // The following code tries to give plug-ins the same size they will eventually have.
328         // The specifiedWidth and specifiedHeight variables are used to predict the size that
329         // WebCore will eventually resize us to.
330
331         // The QuickTime plug-in has problems if you give it a width or height of 0.
332         // Since other plug-ins also might have the same sort of trouble, we make sure
333         // to always give plug-ins a size other than 0,0.
334
335         if (window.width <= 0)
336             window.width = specifiedWidth > 0 ? specifiedWidth : 100;
337         if (window.height <= 0)
338             window.height = specifiedHeight > 0 ? specifiedHeight : 100;
339
340         window.clipRect.bottom = window.clipRect.top;
341         window.clipRect.left = window.clipRect.right;
342         
343         // Core Animation plug-ins need to be updated (with a 0,0,0,0 clipRect) when
344         // moved to a background tab. We don't do this for Core Graphics plug-ins as
345         // older versions of Flash have historical WebKit-specific code that isn't
346         // compatible with this behavior.
347         if (drawingModel == NPDrawingModelCoreAnimation)
348             getNPRect(NSZeroRect, window.clipRect);
349     } else {
350         getNPRect(visibleRectInWindow, window.clipRect);
351     }
352     
353     // Save the port state, set up the port for entry into the plugin
354     PortState portState;
355     switch (drawingModel) {
356 #ifndef NP_NO_QUICKDRAW
357         case NPDrawingModelQuickDraw: {
358             // Set up NS_Port.
359             ::Rect portBounds;
360             CGrafPtr port = GetWindowPort(windowRef);
361             GetPortBounds(port, &portBounds);
362             nPort.qdPort.port = port;
363             nPort.qdPort.portx = (int32_t)-boundsInWindow.origin.x;
364             nPort.qdPort.porty = (int32_t)-boundsInWindow.origin.y;
365             window.window = &nPort;
366
367             PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD));
368             portState = (PortState)qdPortState;
369             
370             GetGWorld(&qdPortState->oldPort, &qdPortState->oldDevice);    
371
372             qdPortState->oldOrigin.h = portBounds.left;
373             qdPortState->oldOrigin.v = portBounds.top;
374
375             qdPortState->oldClipRegion = NewRgn();
376             GetPortClipRegion(port, qdPortState->oldClipRegion);
377             
378             qdPortState->oldVisibleRegion = NewRgn();
379             GetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
380             
381             RgnHandle clipRegion = NewRgn();
382             qdPortState->clipRegion = clipRegion;
383
384             CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
385             if (currentContext && WKCGContextIsBitmapContext(currentContext)) {
386                 // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData
387                 // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext
388                 // returns true, it still might not be a context we need to create a GWorld for; for example
389                 // transparency layers will return true, but return 0 for CGBitmapContextGetData.
390                 void* offscreenData = CGBitmapContextGetData(currentContext);
391                 if (offscreenData) {
392                     // If the current context is an offscreen bitmap, then create a GWorld for it.
393                     ::Rect offscreenBounds;
394                     offscreenBounds.top = 0;
395                     offscreenBounds.left = 0;
396                     offscreenBounds.right = CGBitmapContextGetWidth(currentContext);
397                     offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext);
398                     GWorldPtr newOffscreenGWorld;
399                     QDErr err = NewGWorldFromPtr(&newOffscreenGWorld,
400                         getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0,
401                         static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext));
402                     ASSERT(newOffscreenGWorld);
403                     ASSERT(!err);
404                     if (!err) {
405                         if (offscreenGWorld)
406                             DisposeGWorld(offscreenGWorld);
407                         offscreenGWorld = newOffscreenGWorld;
408
409                         SetGWorld(offscreenGWorld, NULL);
410
411                         port = offscreenGWorld;
412
413                         nPort.qdPort.port = port;
414                         boundsInWindow = [self bounds];
415                         
416                         // Generate a QD origin based on the current affine transform for currentContext.
417                         CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext);
418                         CGPoint origin = {0,0};
419                         CGPoint axisFlip = {1,1};
420                         origin = CGPointApplyAffineTransform(origin, offscreenMatrix);
421                         axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix);
422                         
423                         // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that.
424                         origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x);
425                         origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y);
426                         
427                         nPort.qdPort.portx = static_cast<int32_t>(-boundsInWindow.origin.x + origin.x);
428                         nPort.qdPort.porty = static_cast<int32_t>(-boundsInWindow.origin.y - origin.y);
429                         window.x = 0;
430                         window.y = 0;
431                         window.window = &nPort;
432
433                         // Use the clip bounds from the context instead of the bounds we created
434                         // from the window above.
435                         getNPRect(CGRectOffset(CGContextGetClipBoundingBox(currentContext), -origin.x, origin.y), window.clipRect);
436                     }
437                 }
438             }
439
440             MacSetRectRgn(clipRegion,
441                 window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty,
442                 window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty);
443             
444             // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
445             if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
446                 // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are
447                 // not going to be redrawn this update.  This forces plug-ins to play nice with z-index ordering.
448                 if (forUpdate) {
449                     RgnHandle viewClipRegion = NewRgn();
450                     
451                     // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
452                     // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
453                     // knows about the true set of dirty rects.
454                     NSView *opaqueAncestor = [self opaqueAncestor];
455                     const NSRect *dirtyRects;
456                     NSInteger dirtyRectCount, dirtyRectIndex;
457                     [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
458
459                     for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) {
460                         NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor];
461                         if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) {
462                             // Create a region for this dirty rect
463                             RgnHandle dirtyRectRegion = NewRgn();
464                             SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect)));
465                             
466                             // Union this dirty rect with the rest of the dirty rects
467                             UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion);
468                             DisposeRgn(dirtyRectRegion);
469                         }
470                     }
471                 
472                     // Intersect the dirty region with the clip region, so that we only draw over dirty parts
473                     SectRgn(clipRegion, viewClipRegion, clipRegion);
474                     DisposeRgn(viewClipRegion);
475                 }
476             }
477
478             // Switch to the port and set it up.
479             SetPort(port);
480             PenNormal();
481             ForeColor(blackColor);
482             BackColor(whiteColor);
483             SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty);
484             SetPortClipRegion(nPort.qdPort.port, clipRegion);
485
486             if (forUpdate) {
487                 // AppKit may have tried to help us by doing a BeginUpdate.
488                 // But the invalid region at that level didn't include AppKit's notion of what was not valid.
489                 // We reset the port's visible region to counteract what BeginUpdate did.
490                 SetPortVisibleRegion(nPort.qdPort.port, clipRegion);
491                 InvalWindowRgn(windowRef, clipRegion);
492             }
493             
494             qdPortState->forUpdate = forUpdate;
495             break;
496         }
497 #endif /* NP_NO_QUICKDRAW */
498
499         case NPDrawingModelCoreGraphics: {            
500             if (![self canDraw]) {
501                 portState = NULL;
502                 break;
503             }
504             
505             ASSERT([NSView focusView] == self);
506
507             CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
508
509             PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG));
510             portState = (PortState)cgPortState;
511             cgPortState->context = context;
512             
513 #ifndef NP_NO_CARBON            
514             if (eventModel != NPEventModelCocoa) {
515                 // Update the plugin's window/context
516                 nPort.cgPort.window = windowRef;
517                 nPort.cgPort.context = context;
518                 window.window = &nPort.cgPort;
519             }                
520 #endif /* NP_NO_CARBON */
521
522             // Save current graphics context's state; will be restored by -restorePortState:
523             CGContextSaveGState(context);
524
525             // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
526             if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
527                 // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
528                 // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
529                 // knows about the true set of dirty rects.
530                 NSView *opaqueAncestor = [self opaqueAncestor];
531                 const NSRect *dirtyRects;
532                 NSInteger count;
533                 [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count];
534                 Vector<CGRect, 16> convertedDirtyRects;
535                 convertedDirtyRects.resize(count);
536                 for (int i = 0; i < count; ++i)
537                     reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor];
538                 CGContextClipToRects(context, convertedDirtyRects.data(), count);
539             }
540
541             break;
542         }
543           
544         case NPDrawingModelCoreAnimation:
545             // Just set the port state to a dummy value.
546             portState = (PortState)1;
547             break;
548         
549         default:
550             ASSERT_NOT_REACHED();
551             portState = NULL;
552             break;
553     }
554     
555     return portState;
556 }
557
558 - (PortState)saveAndSetNewPortState
559 {
560     return [self saveAndSetNewPortStateForUpdate:NO];
561 }
562
563 - (void)restorePortState:(PortState)portState
564 {
565     ASSERT([self currentWindow]);
566     ASSERT(portState);
567     
568     switch (drawingModel) {
569 #ifndef NP_NO_QUICKDRAW
570         case NPDrawingModelQuickDraw: {
571             PortState_QD *qdPortState = (PortState_QD *)portState;
572             WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
573             CGrafPtr port = GetWindowPort(windowRef);
574
575             SetPort(port);
576
577             if (qdPortState->forUpdate)
578                 ValidWindowRgn(windowRef, qdPortState->clipRegion);
579
580             SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v);
581
582             SetPortClipRegion(port, qdPortState->oldClipRegion);
583             if (qdPortState->forUpdate)
584                 SetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
585
586             DisposeRgn(qdPortState->oldClipRegion);
587             DisposeRgn(qdPortState->oldVisibleRegion);
588             DisposeRgn(qdPortState->clipRegion);
589
590             SetGWorld(qdPortState->oldPort, qdPortState->oldDevice);
591             break;
592         }
593 #endif /* NP_NO_QUICKDRAW */
594         
595         case NPDrawingModelCoreGraphics: {
596             ASSERT([NSView focusView] == self);
597             
598             CGContextRef context = ((PortState_CG *)portState)->context;
599             ASSERT(!nPort.cgPort.context || (context == nPort.cgPort.context));
600             CGContextRestoreGState(context);
601             break;
602         }
603         
604         case NPDrawingModelCoreAnimation:
605             ASSERT(portState == (PortState)1);
606             break;
607         default:
608             ASSERT_NOT_REACHED();
609             break;
610     }
611 }
612
613 - (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect
614 {
615     if (![self window])
616         return NO;
617     ASSERT(event);
618        
619     if (!_isStarted)
620         return NO;
621
622     ASSERT([_pluginPackage.get() pluginFuncs]->event);
623     
624     // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
625     // We probably don't want more general reentrancy protection; we are really
626     // protecting only against this one case, which actually comes up when
627     // you first install the SVG viewer plug-in.
628     if (inSetWindow)
629         return NO;
630
631     Frame* frame = core([self webFrame]);
632     if (!frame)
633         return NO;
634     Page* page = frame->page();
635     if (!page)
636         return NO;
637
638     // Can only send drawRect (updateEvt) to CoreGraphics plugins when actually drawing
639     ASSERT((drawingModel != NPDrawingModelCoreGraphics) || !eventIsDrawRect || [NSView focusView] == self);
640     
641     PortState portState = NULL;
642     
643     if (isDrawingModelQuickDraw(drawingModel) || (drawingModel != NPDrawingModelCoreAnimation && eventIsDrawRect)) {
644         // In CoreGraphics mode, the port state only needs to be saved/set when redrawing the plug-in view.
645         // The plug-in is not allowed to draw at any other time.
646         portState = [self saveAndSetNewPortStateForUpdate:eventIsDrawRect];
647         // We may have changed the window, so inform the plug-in.
648         [self setWindowIfNecessary];
649     }
650     
651 #if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW)
652     // Draw green to help debug.
653     // If we see any green we know something's wrong.
654     // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined.
655     if (isDrawingModelQuickDraw(drawingModel) && eventIsDrawRect) {
656         ForeColor(greenColor);
657         const ::Rect bigRect = { -10000, -10000, 10000, 10000 };
658         PaintRect(&bigRect);
659         ForeColor(blackColor);
660     }
661 #endif
662     
663     // Temporarily retain self in case the plug-in view is released while sending an event. 
664     [[self retain] autorelease];
665
666     BOOL acceptedEvent;
667     [self willCallPlugInFunction];
668     // Set the pluginAllowPopup flag.
669     ASSERT(_eventHandler);
670     bool oldAllowPopups = frame->script()->allowPopupsFromPlugin();
671     frame->script()->setAllowPopupsFromPlugin(_eventHandler->currentEventIsUserGesture());    
672     {
673         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
674         acceptedEvent = [_pluginPackage.get() pluginFuncs]->event(plugin, event);
675     }
676     // Restore the old pluginAllowPopup flag.
677     frame->script()->setAllowPopupsFromPlugin(oldAllowPopups);     
678     [self didCallPlugInFunction];
679         
680     if (portState) {
681         if ([self currentWindow])
682             [self restorePortState:portState];
683         if (portState != (PortState)1)
684             free(portState);
685     }
686
687     return acceptedEvent;
688 }
689
690 - (void)windowFocusChanged:(BOOL)hasFocus
691 {
692     _eventHandler->windowFocusChanged(hasFocus);
693 }
694
695 - (void)sendDrawRectEvent:(NSRect)rect
696 {
697     ASSERT(_eventHandler);
698     
699     CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
700     _eventHandler->drawRect(context, rect);
701 }
702
703 - (void)stopTimers
704 {
705     [super stopTimers];
706     
707     if (_eventHandler)
708         _eventHandler->stopTimers();
709     
710     if (!timers)
711         return;
712
713     HashMap<uint32_t, PluginTimer*>::const_iterator end = timers->end();
714     for (HashMap<uint32_t, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
715         PluginTimer* timer = it->second;
716         timer->stop();
717     }    
718 }
719
720 - (void)startTimers
721 {
722     [super startTimers];
723     
724     // If the plugin is completely obscured (scrolled out of view, for example), then we will
725     // send null events at a reduced rate.
726     _eventHandler->startTimers(_isCompletelyObscured);
727     
728     if (!timers)
729         return;
730     
731     HashMap<uint32_t, PluginTimer*>::const_iterator end = timers->end();
732     for (HashMap<uint32_t, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
733         PluginTimer* timer = it->second;
734         ASSERT(!timer->isActive());
735         timer->start(_isCompletelyObscured);
736     }    
737 }
738
739 - (void)focusChanged
740 {
741     // We need to null check the event handler here because
742     // the plug-in view can resign focus after it's been stopped
743     // and the event handler has been deleted.
744     if (_eventHandler)
745         _eventHandler->focusChanged(_hasFocus);
746 }
747
748 - (void)mouseDown:(NSEvent *)theEvent
749 {
750     if (!_isStarted)
751         return;
752
753     _eventHandler->mouseDown(theEvent);
754 }
755
756 - (void)mouseUp:(NSEvent *)theEvent
757 {
758     if (!_isStarted)
759         return;
760
761     _eventHandler->mouseUp(theEvent);
762 }
763
764 - (void)handleMouseEntered:(NSEvent *)theEvent
765 {
766     if (!_isStarted)
767         return;
768
769     // Set cursor to arrow. Plugins often handle cursor internally, but those that don't will just get this default one.
770     [[NSCursor arrowCursor] set];
771
772     _eventHandler->mouseEntered(theEvent);
773 }
774
775 - (void)handleMouseExited:(NSEvent *)theEvent
776 {
777     if (!_isStarted)
778         return;
779
780     _eventHandler->mouseExited(theEvent);
781     
782     // Set cursor back to arrow cursor.  Because NSCursor doesn't know about changes that the plugin made, we could get confused about what we think the
783     // current cursor is otherwise.  Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin.
784     [[NSCursor arrowCursor] set];
785 }
786
787 - (void)handleMouseMoved:(NSEvent *)theEvent
788 {
789     if (!_isStarted)
790         return;
791
792     _eventHandler->mouseMoved(theEvent);
793 }
794     
795 - (void)mouseDragged:(NSEvent *)theEvent
796 {
797     if (!_isStarted)
798         return;
799
800     _eventHandler->mouseDragged(theEvent);
801 }
802
803 - (void)scrollWheel:(NSEvent *)theEvent
804 {
805     if (!_isStarted) {
806         [super scrollWheel:theEvent];
807         return;
808     }
809
810     if (!_eventHandler->scrollWheel(theEvent))
811         [super scrollWheel:theEvent];
812 }
813
814 - (void)keyUp:(NSEvent *)theEvent
815 {
816     if (!_isStarted)
817         return;
818
819     _eventHandler->keyUp(theEvent);
820 }
821
822 - (void)keyDown:(NSEvent *)theEvent
823 {
824     if (!_isStarted)
825         return;
826
827     _eventHandler->keyDown(theEvent);
828 }
829
830 - (void)flagsChanged:(NSEvent *)theEvent
831 {
832     if (!_isStarted)
833         return;
834
835     _eventHandler->flagsChanged(theEvent);
836 }
837
838 - (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character
839 {
840     if (!_isStarted)
841         return;
842     
843     _eventHandler->syntheticKeyDownWithCommandModifier(keyCode, character);
844 }
845
846 - (void)privateBrowsingModeDidChange
847 {
848     if (!_isStarted)
849         return;
850     
851     NPBool value = _isPrivateBrowsingEnabled;
852
853     [self willCallPlugInFunction];
854     {
855         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
856         if ([_pluginPackage.get() pluginFuncs]->setvalue)
857             [_pluginPackage.get() pluginFuncs]->setvalue(plugin, NPNVprivateModeBool, &value);
858     }
859     [self didCallPlugInFunction];
860 }
861
862 // MARK: WEB_NETSCAPE_PLUGIN
863
864 - (BOOL)isNewWindowEqualToOldWindow
865 {
866     if (window.x != lastSetWindow.x)
867         return NO;
868     if (window.y != lastSetWindow.y)
869         return NO;
870     if (window.width != lastSetWindow.width)
871         return NO;
872     if (window.height != lastSetWindow.height)
873         return NO;
874     if (window.clipRect.top != lastSetWindow.clipRect.top)
875         return NO;
876     if (window.clipRect.left != lastSetWindow.clipRect.left)
877         return NO;
878     if (window.clipRect.bottom  != lastSetWindow.clipRect.bottom)
879         return NO;
880     if (window.clipRect.right != lastSetWindow.clipRect.right)
881         return NO;
882     if (window.type != lastSetWindow.type)
883         return NO;
884     
885     switch (drawingModel) {
886 #ifndef NP_NO_QUICKDRAW
887         case NPDrawingModelQuickDraw:
888             if (nPort.qdPort.portx != lastSetPort.qdPort.portx)
889                 return NO;
890             if (nPort.qdPort.porty != lastSetPort.qdPort.porty)
891                 return NO;
892             if (nPort.qdPort.port != lastSetPort.qdPort.port)
893                 return NO;
894         break;
895 #endif /* NP_NO_QUICKDRAW */
896             
897         case NPDrawingModelCoreGraphics:
898             if (nPort.cgPort.window != lastSetPort.cgPort.window)
899                 return NO;
900             if (nPort.cgPort.context != lastSetPort.cgPort.context)
901                 return NO;
902         break;
903                     
904         case NPDrawingModelCoreAnimation:
905           if (window.window != lastSetWindow.window)
906               return NO;
907           break;
908         default:
909             ASSERT_NOT_REACHED();
910         break;
911     }
912     
913     return YES;
914 }
915
916 -(void)tellQuickTimeToChill
917 {
918 #ifndef NP_NO_QUICKDRAW
919     ASSERT(isDrawingModelQuickDraw(drawingModel));
920     
921     // Make a call to the secret QuickDraw API that makes QuickTime calm down.
922     WindowRef windowRef = (WindowRef)[[self window] windowRef];
923     if (!windowRef) {
924         return;
925     }
926     CGrafPtr port = GetWindowPort(windowRef);
927     ::Rect bounds;
928     GetPortBounds(port, &bounds);
929     WKCallDrawingNotification(port, &bounds);
930 #endif /* NP_NO_QUICKDRAW */
931 }
932
933 - (void)updateAndSetWindow
934 {
935     // A plug-in can only update if it's (1) already been started (2) isn't stopped
936     // and (3) is able to draw on-screen. To meet condition (3) the plug-in must not
937     // be hidden and be attached to a window. There are two exceptions to this rule:
938     //
939     // Exception 1: QuickDraw plug-ins must be manually told when to stop writing
940     // bits to the window backing store, thus to do so requires a new call to
941     // NPP_SetWindow() with an empty NPWindow struct.
942     //
943     // Exception 2: CoreGraphics plug-ins expect to have their drawable area updated
944     // when they are moved to a background tab, via a NPP_SetWindow call. This is
945     // accomplished by allowing -saveAndSetNewPortStateForUpdate to "clip-out" the window's
946     // clipRect. Flash is curently an exception to this. See 6453738.
947     //
948     
949     if (!_isStarted)
950         return;
951     
952 #ifdef NP_NO_QUICKDRAW
953     if (![self canDraw])
954         return;
955 #else
956     if (drawingModel == NPDrawingModelQuickDraw)
957         [self tellQuickTimeToChill];
958     else if (drawingModel == NPDrawingModelCoreGraphics && ![self canDraw] && _isFlash) {
959         // The Flash plug-in does not expect an NPP_SetWindow call from WebKit in this case.
960         // See Exception 2 above.
961         return;
962     }
963 #endif // NP_NO_QUICKDRAW
964     
965     BOOL didLockFocus = [NSView focusView] != self && [self lockFocusIfCanDraw];
966
967     PortState portState = [self saveAndSetNewPortState];
968     if (portState) {
969         [self setWindowIfNecessary];
970         [self restorePortState:portState];
971         if (portState != (PortState)1)
972             free(portState);
973     } else if (drawingModel == NPDrawingModelCoreGraphics)
974         [self setWindowIfNecessary];        
975
976     if (didLockFocus)
977         [self unlockFocus];
978 }
979
980 - (void)setWindowIfNecessary
981 {
982     if (!_isStarted) 
983         return;
984     
985     if (![self isNewWindowEqualToOldWindow]) {        
986         // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
987         // We probably don't want more general reentrancy protection; we are really
988         // protecting only against this one case, which actually comes up when
989         // you first install the SVG viewer plug-in.
990         NPError npErr;
991         
992         BOOL wasInSetWindow = inSetWindow;
993         inSetWindow = YES;        
994         [self willCallPlugInFunction];
995         {
996             JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
997             npErr = [_pluginPackage.get() pluginFuncs]->setwindow(plugin, &window);
998         }
999         [self didCallPlugInFunction];
1000         inSetWindow = wasInSetWindow;
1001
1002 #ifndef NDEBUG
1003         switch (drawingModel) {
1004 #ifndef NP_NO_QUICKDRAW
1005             case NPDrawingModelQuickDraw:
1006                 LOG(Plugins, "NPP_SetWindow (QuickDraw): %d, port=0x%08x, window.x:%d window.y:%d window.width:%d window.height:%d",
1007                 npErr, (int)nPort.qdPort.port, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
1008             break;
1009 #endif /* NP_NO_QUICKDRAW */
1010             
1011             case NPDrawingModelCoreGraphics:
1012                 LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d",
1013                 npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height, 
1014                     window.clipRect.right - window.clipRect.left, window.clipRect.bottom - window.clipRect.top);
1015             break;
1016
1017             case NPDrawingModelCoreAnimation:
1018                 LOG(Plugins, "NPP_SetWindow (CoreAnimation): %d, window=%p window.x:%d window.y:%d window.width:%d window.height:%d",
1019                 npErr, window.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
1020             break;
1021
1022             default:
1023                 ASSERT_NOT_REACHED();
1024             break;
1025         }
1026 #endif /* !defined(NDEBUG) */
1027         
1028         lastSetWindow = window;
1029         lastSetPort = nPort;
1030     }
1031 }
1032
1033 + (void)setCurrentPluginView:(WebNetscapePluginView *)view
1034 {
1035     currentPluginView = view;
1036 }
1037
1038 + (WebNetscapePluginView *)currentPluginView
1039 {
1040     return currentPluginView;
1041 }
1042
1043 - (BOOL)createPlugin
1044 {
1045     // Open the plug-in package so it remains loaded while our plugin uses it
1046     [_pluginPackage.get() open];
1047     
1048     // Initialize drawingModel to an invalid value so that we can detect when the plugin does not specify a drawingModel
1049     drawingModel = (NPDrawingModel)-1;
1050     
1051     // Initialize eventModel to an invalid value so that we can detect when the plugin does not specify an event model.
1052     eventModel = (NPEventModel)-1;
1053     
1054     NPError npErr = [self _createPlugin];
1055     if (npErr != NPERR_NO_ERROR) {
1056         LOG_ERROR("NPP_New failed with error: %d", npErr);
1057         [self _destroyPlugin];
1058         [_pluginPackage.get() close];
1059         return NO;
1060     }
1061     
1062     if (drawingModel == (NPDrawingModel)-1) {
1063 #ifndef NP_NO_QUICKDRAW
1064         // Default to QuickDraw if the plugin did not specify a drawing model.
1065         drawingModel = NPDrawingModelQuickDraw;
1066 #else
1067         // QuickDraw is not available, so we can't default to it. Instead, default to CoreGraphics.
1068         drawingModel = NPDrawingModelCoreGraphics;
1069 #endif
1070     }
1071
1072     if (eventModel == (NPEventModel)-1) {
1073         // If the plug-in did not specify a drawing model we default to Carbon when it is available.
1074 #ifndef NP_NO_CARBON
1075         eventModel = NPEventModelCarbon;
1076 #else
1077         eventModel = NPEventModelCocoa;
1078 #endif // NP_NO_CARBON
1079     }
1080
1081 #ifndef NP_NO_CARBON
1082     if (eventModel == NPEventModelCocoa && isDrawingModelQuickDraw(drawingModel)) {
1083         LOG(Plugins, "Plugin can't use use Cocoa event model with QuickDraw drawing model: %@", _pluginPackage.get());
1084         [self _destroyPlugin];
1085         [_pluginPackage.get() close];
1086         
1087         return NO;
1088     }        
1089 #endif // NP_NO_CARBON
1090     
1091 #ifndef BUILDING_ON_TIGER
1092     if (drawingModel == NPDrawingModelCoreAnimation) {
1093         void *value = 0;
1094         if ([_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) {
1095
1096             // The plug-in gives us a retained layer.
1097             _pluginLayer.adoptNS((CALayer *)value);
1098
1099             BOOL accleratedCompositingEnabled = false;
1100 #if USE(ACCELERATED_COMPOSITING)
1101             accleratedCompositingEnabled = [[[self webView] preferences] acceleratedCompositingEnabled];
1102 #endif
1103             if (accleratedCompositingEnabled) {
1104                 // FIXME: This code can be shared between WebHostedNetscapePluginView and WebNetscapePluginView.
1105 #ifndef BUILDING_ON_LEOPARD
1106                 // Since this layer isn't going to be inserted into a view, we need to create another layer and flip its geometry
1107                 // in order to get the coordinate system right.
1108                 RetainPtr<CALayer> realPluginLayer(AdoptNS, _pluginLayer.releaseRef());
1109                 
1110                 _pluginLayer.adoptNS([[CALayer alloc] init]);
1111                 _pluginLayer.get().bounds = realPluginLayer.get().bounds;
1112                 _pluginLayer.get().geometryFlipped = YES;
1113
1114                 realPluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
1115                 [_pluginLayer.get() addSublayer:realPluginLayer.get()];
1116 #endif
1117                 // Eagerly enter compositing mode, since we know we'll need it. This avoids firing setNeedsStyleRecalc()
1118                 // for iframes that contain composited plugins at bad times. https://bugs.webkit.org/show_bug.cgi?id=39033
1119                 core([self webFrame])->view()->enterCompositingMode();
1120                 [self element]->setNeedsStyleRecalc(SyntheticStyleChange);
1121             } else
1122                 [self setWantsLayer:YES];
1123
1124             LOG(Plugins, "%@ is using Core Animation drawing model with layer %@", _pluginPackage.get(), _pluginLayer.get());
1125         }
1126
1127         ASSERT(_pluginLayer);
1128     }
1129 #endif
1130     
1131     // Create the event handler
1132     _eventHandler = WebNetscapePluginEventHandler::create(self);
1133
1134     return YES;
1135 }
1136
1137 #ifndef BUILDING_ON_TIGER
1138 // FIXME: This method is an ideal candidate to move up to the base class
1139 - (CALayer *)pluginLayer
1140 {
1141     return _pluginLayer.get();
1142 }
1143
1144 - (void)setLayer:(CALayer *)newLayer
1145 {
1146     [super setLayer:newLayer];
1147
1148     if (newLayer && _pluginLayer) {
1149         _pluginLayer.get().frame = [newLayer frame];
1150         _pluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
1151         [newLayer addSublayer:_pluginLayer.get()];
1152     }
1153 }
1154 #endif
1155
1156 - (void)loadStream
1157 {
1158     if ([self _shouldCancelSrcStream])
1159         return;
1160     
1161     if (_loadManually) {
1162         [self _redeliverStream];
1163         return;
1164     }
1165     
1166     // If the OBJECT/EMBED tag has no SRC, the URL is passed to us as "".
1167     // Check for this and don't start a load in this case.
1168     if (_sourceURL && ![_sourceURL.get() _web_isEmpty]) {
1169         NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_sourceURL.get()];
1170         [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()];
1171         [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO];
1172     } 
1173 }
1174
1175 - (BOOL)shouldStop
1176 {
1177     // If we're already calling a plug-in function, do not call NPP_Destroy().  The plug-in function we are calling
1178     // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said
1179     // plugin-function returns.
1180     // See <rdar://problem/4480737>.
1181     if (pluginFunctionCallDepth > 0) {
1182         shouldStopSoon = YES;
1183         return NO;
1184     }
1185
1186     return YES;
1187 }
1188
1189 - (void)destroyPlugin
1190 {
1191     // To stop active streams it's necessary to invoke stop() on a copy 
1192     // of streams. This is because calling WebNetscapePluginStream::stop() also has the side effect
1193     // of removing a stream from this hash set.
1194     Vector<RefPtr<WebNetscapePluginStream> > streamsCopy;
1195     copyToVector(streams, streamsCopy);
1196     for (size_t i = 0; i < streamsCopy.size(); i++)
1197         streamsCopy[i]->stop();
1198     
1199     [[_pendingFrameLoads.get() allKeys] makeObjectsPerformSelector:@selector(_setInternalLoadDelegate:) withObject:nil];
1200     [NSObject cancelPreviousPerformRequestsWithTarget:self];
1201
1202     // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted.
1203     lastSetWindow.type = (NPWindowType)0;
1204     
1205 #ifndef BUILDING_ON_TIGER
1206     _pluginLayer = 0;
1207 #endif
1208     
1209     [self _destroyPlugin];
1210     [_pluginPackage.get() close];
1211     
1212     _eventHandler.clear();
1213 }
1214
1215 - (NPEventModel)eventModel
1216 {
1217     return eventModel;
1218 }
1219
1220 - (NPP)plugin
1221 {
1222     return plugin;
1223 }
1224
1225 - (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values
1226 {
1227     ASSERT([keys count] == [values count]);
1228     
1229     // Convert the attributes to 2 C string arrays.
1230     // These arrays are passed to NPP_New, but the strings need to be
1231     // modifiable and live the entire life of the plugin.
1232
1233     // The Java plug-in requires the first argument to be the base URL
1234     if ([_MIMEType.get() isEqualToString:@"application/x-java-applet"]) {
1235         cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *));
1236         cValues = (char **)malloc(([values count] + 1) * sizeof(char *));
1237         cAttributes[0] = strdup("DOCBASE");
1238         cValues[0] = strdup([_baseURL.get() _web_URLCString]);
1239         argsCount++;
1240     } else {
1241         cAttributes = (char **)malloc([keys count] * sizeof(char *));
1242         cValues = (char **)malloc([values count] * sizeof(char *));
1243     }
1244
1245     BOOL isWMP = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.WMP.defaultplugin";
1246     
1247     unsigned i;
1248     unsigned count = [keys count];
1249     for (i = 0; i < count; i++) {
1250         NSString *key = [keys objectAtIndex:i];
1251         NSString *value = [values objectAtIndex:i];
1252         if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) {
1253             specifiedHeight = [value intValue];
1254         } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) {
1255             specifiedWidth = [value intValue];
1256         }
1257         // Avoid Window Media Player crash when these attributes are present.
1258         if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) {
1259             continue;
1260         }
1261         cAttributes[argsCount] = strdup([key UTF8String]);
1262         cValues[argsCount] = strdup([value UTF8String]);
1263         LOG(Plugins, "%@ = %@", key, value);
1264         argsCount++;
1265     }
1266 }
1267
1268 - (uint32_t)checkIfAllowedToLoadURL:(const char*)urlCString frame:(const char*)frameNameCString 
1269                        callbackFunc:(void (*)(NPP npp, uint32_t checkID, NPBool allowed, void* context))callbackFunc 
1270                             context:(void*)context
1271 {
1272     if (!_containerChecksInProgress) 
1273         _containerChecksInProgress = [[NSMutableDictionary alloc] init];
1274     
1275     NSString *frameName = frameNameCString ? [NSString stringWithCString:frameNameCString encoding:NSISOLatin1StringEncoding] : nil;
1276     
1277     ++_currentContainerCheckRequestID;
1278     WebNetscapeContainerCheckContextInfo *contextInfo = [[WebNetscapeContainerCheckContextInfo alloc] initWithCheckRequestID:_currentContainerCheckRequestID 
1279                                                                                                                 callbackFunc:callbackFunc
1280                                                                                                                       context:context];
1281     
1282     WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[self requestWithURLCString:urlCString]
1283                                                                         target:frameName
1284                                                                   resultObject:self
1285                                                                       selector:@selector(_containerCheckResult:contextInfo:)
1286                                                                     controller:self 
1287                                                                    contextInfo:contextInfo];
1288     
1289     [contextInfo release];
1290     [_containerChecksInProgress setObject:check forKey:[NSNumber numberWithInt:_currentContainerCheckRequestID]];
1291     [check start];
1292     
1293     return _currentContainerCheckRequestID;
1294 }
1295
1296 - (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo
1297 {
1298     ASSERT([contextInfo isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]);
1299     void (*pluginCallback)(NPP npp, uint32_t, NPBool, void*) = [contextInfo callback];
1300     
1301     if (!pluginCallback) {
1302         ASSERT_NOT_REACHED();
1303         return;
1304     }
1305     
1306     pluginCallback([self plugin], [contextInfo checkRequestID], (policy == PolicyUse), [contextInfo context]);
1307 }
1308
1309 - (void)cancelCheckIfAllowedToLoadURL:(uint32_t)checkID
1310 {
1311     WebPluginContainerCheck *check = (WebPluginContainerCheck *)[_containerChecksInProgress objectForKey:[NSNumber numberWithInt:checkID]];
1312     
1313     if (!check)
1314         return;
1315     
1316     [check cancel];
1317     [_containerChecksInProgress removeObjectForKey:[NSNumber numberWithInt:checkID]];
1318 }
1319
1320 // WebPluginContainerCheck automatically calls this method after invoking our _containerCheckResult: selector.
1321 // It works this way because calling -[WebPluginContainerCheck cancel] allows it to do it's teardown process.
1322 - (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck
1323 {
1324     ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]);
1325     WebPluginContainerCheck *check = (WebPluginContainerCheck *)webPluginContainerCheck;
1326     ASSERT([[check contextInfo] isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]);
1327     
1328     [self cancelCheckIfAllowedToLoadURL:[[check contextInfo] checkRequestID]];
1329 }
1330
1331 #ifdef BUILDING_ON_TIGER
1332 // The Tiger compiler requires these two methods be present. Otherwise it doesn't think WebNetscapePluginView
1333 // conforms to the WebPluginContainerCheckController protocol.
1334 - (WebView *)webView
1335 {
1336     return [super webView];   
1337 }
1338
1339 - (WebFrame *)webFrame
1340 {
1341     return [super webFrame];   
1342 }
1343 #endif
1344
1345 // MARK: NSVIEW
1346
1347 - (id)initWithFrame:(NSRect)frame
1348       pluginPackage:(WebNetscapePluginPackage *)pluginPackage
1349                 URL:(NSURL *)URL
1350             baseURL:(NSURL *)baseURL
1351            MIMEType:(NSString *)MIME
1352       attributeKeys:(NSArray *)keys
1353     attributeValues:(NSArray *)values
1354        loadManually:(BOOL)loadManually
1355             element:(PassRefPtr<WebCore::HTMLPlugInElement>)element
1356 {
1357     self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element];
1358     if (!self)
1359         return nil;
1360  
1361     _pendingFrameLoads.adoptNS([[NSMutableDictionary alloc] init]);
1362     
1363     // load the plug-in if it is not already loaded
1364     if (![pluginPackage load]) {
1365         [self release];
1366         return nil;
1367     }
1368
1369     return self;
1370 }
1371
1372 - (id)initWithFrame:(NSRect)frame
1373 {
1374     ASSERT_NOT_REACHED();
1375     return nil;
1376 }
1377
1378 - (void)fini
1379 {
1380 #ifndef NP_NO_QUICKDRAW
1381     if (offscreenGWorld)
1382         DisposeGWorld(offscreenGWorld);
1383 #endif
1384
1385     for (unsigned i = 0; i < argsCount; i++) {
1386         free(cAttributes[i]);
1387         free(cValues[i]);
1388     }
1389     free(cAttributes);
1390     free(cValues);
1391     
1392     ASSERT(!_eventHandler);
1393     
1394     if (timers) {
1395         deleteAllValues(*timers);
1396         delete timers;
1397     }  
1398     
1399     [_containerChecksInProgress release];
1400 }
1401
1402 - (void)disconnectStream:(WebNetscapePluginStream*)stream
1403 {
1404     streams.remove(stream);
1405 }
1406
1407 - (void)dealloc
1408 {
1409     ASSERT(!_isStarted);
1410     ASSERT(!plugin);
1411
1412     [self fini];
1413
1414     [super dealloc];
1415 }
1416
1417 - (void)finalize
1418 {
1419     ASSERT_MAIN_THREAD();
1420     ASSERT(!_isStarted);
1421
1422     [self fini];
1423
1424     [super finalize];
1425 }
1426
1427 - (void)drawRect:(NSRect)rect
1428 {
1429     if (_cachedSnapshot) {
1430         NSRect sourceRect = { NSZeroPoint, [_cachedSnapshot.get() size] };
1431         [_cachedSnapshot.get() drawInRect:[self bounds] fromRect:sourceRect operation:NSCompositeSourceOver fraction:1];
1432         return;
1433     }
1434     
1435     if (drawingModel == NPDrawingModelCoreAnimation && (!_snapshotting || ![self supportsSnapshotting]))
1436         return;
1437
1438     if (!_isStarted)
1439         return;
1440     
1441     if ([NSGraphicsContext currentContextDrawingToScreen] || _isFlash)
1442         [self sendDrawRectEvent:rect];
1443     else {
1444         NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap];
1445         if (printedPluginBitmap) {
1446             // Flip the bitmap before drawing because the QuickDraw port is flipped relative
1447             // to this view.
1448             CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
1449             CGContextSaveGState(cgContext);
1450             NSRect bounds = [self bounds];
1451             CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds));
1452             CGContextScaleCTM(cgContext, 1.0f, -1.0f);
1453             [printedPluginBitmap drawInRect:bounds];
1454             CGContextRestoreGState(cgContext);
1455         }
1456     }
1457 }
1458
1459 - (NPObject *)createPluginScriptableObject
1460 {
1461     if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted)
1462         return NULL;
1463         
1464     NPObject *value = NULL;
1465     NPError error;
1466     [self willCallPlugInFunction];
1467     {
1468         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1469         error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginScriptableNPObject, &value);
1470     }
1471     [self didCallPlugInFunction];
1472     if (error != NPERR_NO_ERROR)
1473         return NULL;
1474     
1475     return value;
1476 }
1477
1478 - (void)willCallPlugInFunction
1479 {
1480     ASSERT(plugin);
1481
1482     // Could try to prevent infinite recursion here, but it's probably not worth the effort.
1483     pluginFunctionCallDepth++;
1484 }
1485
1486 - (void)didCallPlugInFunction
1487 {
1488     ASSERT(pluginFunctionCallDepth > 0);
1489     pluginFunctionCallDepth--;
1490     
1491     // If -stop was called while we were calling into a plug-in function, and we're no longer
1492     // inside a plug-in function, stop now.
1493     if (pluginFunctionCallDepth == 0 && shouldStopSoon) {
1494         shouldStopSoon = NO;
1495         [self stop];
1496     }
1497 }
1498
1499 -(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
1500 {
1501     ASSERT(_loadManually);
1502     ASSERT(!_manualStream);
1503
1504     _manualStream = WebNetscapePluginStream::create(core([self webFrame])->loader());
1505 }
1506
1507 - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
1508 {
1509     ASSERT(_loadManually);
1510     ASSERT(_manualStream);
1511     
1512     _dataLengthReceived += [data length];
1513     
1514     if (!_isStarted)
1515         return;
1516
1517     if (!_manualStream->plugin()) {
1518         // Check if the load should be cancelled
1519         if ([self _shouldCancelSrcStream]) {
1520             NSURLResponse *response = [[self dataSource] response];
1521             
1522             NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad
1523                                                             contentURL:[response URL]
1524                                                          pluginPageURL:nil
1525                                                             pluginName:nil // FIXME: Get this from somewhere
1526                                                               MIMEType:[response MIMEType]];
1527             [[self dataSource] _documentLoader]->cancelMainResourceLoad(error);
1528             [error release];
1529             return;
1530         }
1531         
1532         _manualStream->setRequestURL([[[self dataSource] request] URL]);
1533         _manualStream->setPlugin([self plugin]);
1534         ASSERT(_manualStream->plugin());
1535         
1536         _manualStream->startStreamWithResponse([[self dataSource] response]);
1537     }
1538
1539     if (_manualStream->plugin())
1540         _manualStream->didReceiveData(0, static_cast<const char *>([data bytes]), [data length]);
1541 }
1542
1543 - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
1544 {
1545     ASSERT(_loadManually);
1546
1547     _error = error;
1548     
1549     if (!_isStarted) {
1550         return;
1551     }
1552
1553     _manualStream->destroyStreamWithError(error);
1554 }
1555
1556 - (void)pluginViewFinishedLoading:(NSView *)pluginView 
1557 {
1558     ASSERT(_loadManually);
1559     ASSERT(_manualStream);
1560     
1561     if (_isStarted)
1562         _manualStream->didFinishLoading(0);
1563 }
1564
1565 - (NSTextInputContext *)inputContext
1566 {
1567     return nil;
1568 }
1569
1570 @end
1571
1572 @implementation WebNetscapePluginView (WebNPPCallbacks)
1573
1574 - (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest
1575 {
1576     // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called
1577     // if we are stopped since this method is called after a delay and we call 
1578     // cancelPreviousPerformRequestsWithTarget inside of stop.
1579     if (!_isStarted) {
1580         return;
1581     }
1582     
1583     NSURL *URL = [[JSPluginRequest request] URL];
1584     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1585     ASSERT(JSString);
1586     
1587     NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]];
1588     
1589     // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
1590     if (!_isStarted) {
1591         return;
1592     }
1593         
1594     if ([JSPluginRequest frameName] != nil) {
1595         // FIXME: If the result is a string, we probably want to put that string into the frame.
1596         if ([JSPluginRequest sendNotification]) {
1597             [self willCallPlugInFunction];
1598             {
1599                 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1600                 [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]);
1601             }
1602             [self didCallPlugInFunction];
1603         }
1604     } else if ([result length] > 0) {
1605         // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
1606         NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
1607         
1608         RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create([NSURLRequest requestWithURL:URL], plugin, [JSPluginRequest sendNotification], [JSPluginRequest notifyData]);
1609         
1610         RetainPtr<NSURLResponse> response(AdoptNS, [[NSURLResponse alloc] initWithURL:URL 
1611                                                                              MIMEType:@"text/plain" 
1612                                                                 expectedContentLength:[JSData length]
1613                                                                      textEncodingName:nil]);
1614         
1615         stream->startStreamWithResponse(response.get());
1616         stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]);
1617         stream->didFinishLoading(0);
1618     }
1619 }
1620
1621 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason
1622 {
1623     ASSERT(_isStarted);
1624     
1625     WebPluginRequest *pluginRequest = [_pendingFrameLoads.get() objectForKey:webFrame];
1626     ASSERT(pluginRequest != nil);
1627     ASSERT([pluginRequest sendNotification]);
1628         
1629     [self willCallPlugInFunction];
1630     {
1631         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1632         [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]);
1633     }
1634     [self didCallPlugInFunction];
1635     
1636     [_pendingFrameLoads.get() removeObjectForKey:webFrame];
1637     [webFrame _setInternalLoadDelegate:nil];
1638 }
1639
1640 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error
1641 {
1642     NPReason reason = NPRES_DONE;
1643     if (error != nil)
1644         reason = WebNetscapePluginStream::reasonForError(error);
1645     [self webFrame:webFrame didFinishLoadWithReason:reason];
1646 }
1647
1648 - (void)loadPluginRequest:(WebPluginRequest *)pluginRequest
1649 {
1650     NSURLRequest *request = [pluginRequest request];
1651     NSString *frameName = [pluginRequest frameName];
1652     WebFrame *frame = nil;
1653     
1654     NSURL *URL = [request URL];
1655     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1656     
1657     ASSERT(frameName || JSString);
1658     
1659     if (frameName) {
1660         // FIXME - need to get rid of this window creation which
1661         // bypasses normal targeted link handling
1662         frame = kit(core([self webFrame])->loader()->findFrameForNavigation(frameName));
1663         if (frame == nil) {
1664             WebView *currentWebView = [self webView];
1665             NSDictionary *features = [[NSDictionary alloc] init];
1666             WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
1667                                                         createWebViewWithRequest:nil
1668                                                                   windowFeatures:features];
1669             [features release];
1670
1671             if (!newWebView) {
1672                 if ([pluginRequest sendNotification]) {
1673                     [self willCallPlugInFunction];
1674                     {
1675                         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1676                         [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]);
1677                     }
1678                     [self didCallPlugInFunction];
1679                 }
1680                 return;
1681             }
1682             
1683             frame = [newWebView mainFrame];
1684             core(frame)->tree()->setName(frameName);
1685             [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
1686         }
1687     }
1688
1689     if (JSString) {
1690         ASSERT(frame == nil || [self webFrame] == frame);
1691         [self evaluateJavaScriptPluginRequest:pluginRequest];
1692     } else {
1693         [frame loadRequest:request];
1694         if ([pluginRequest sendNotification]) {
1695             // Check if another plug-in view or even this view is waiting for the frame to load.
1696             // If it is, tell it that the load was cancelled because it will be anyway.
1697             WebNetscapePluginView *view = [frame _internalLoadDelegate];
1698             if (view != nil) {
1699                 ASSERT([view isKindOfClass:[WebNetscapePluginView class]]);
1700                 [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK];
1701             }
1702             [_pendingFrameLoads.get() _webkit_setObject:pluginRequest forUncopiedKey:frame];
1703             [frame _setInternalLoadDelegate:self];
1704         }
1705     }
1706 }
1707
1708 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification
1709 {
1710     NSURL *URL = [request URL];
1711
1712     if (!URL) 
1713         return NPERR_INVALID_URL;
1714
1715     // Don't allow requests to be loaded when the document loader is stopping all loaders.
1716     if ([[self dataSource] _documentLoader]->isStopping())
1717         return NPERR_GENERIC_ERROR;
1718     
1719     NSString *target = nil;
1720     if (cTarget) {
1721         // Find the frame given the target string.
1722         target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding];
1723     }
1724     WebFrame *frame = [self webFrame];
1725
1726     // don't let a plugin start any loads if it is no longer part of a document that is being 
1727     // displayed unless the loads are in the same frame as the plugin.
1728     if ([[self dataSource] _documentLoader] != core([self webFrame])->loader()->activeDocumentLoader() &&
1729         (!cTarget || [frame findFrameNamed:target] != frame)) {
1730         return NPERR_GENERIC_ERROR; 
1731     }
1732     
1733     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1734     if (JSString != nil) {
1735         if (![[[self webView] preferences] isJavaScriptEnabled]) {
1736             // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
1737             return NPERR_GENERIC_ERROR;
1738         } else if (cTarget == NULL && _mode == NP_FULL) {
1739             // Don't allow a JavaScript request from a standalone plug-in that is self-targetted
1740             // because this can cause the user to be redirected to a blank page (3424039).
1741             return NPERR_INVALID_PARAM;
1742         }
1743     } else {
1744         if (!core([self webFrame])->document()->securityOrigin()->canDisplay(URL))
1745             return NPERR_GENERIC_ERROR;
1746     }
1747         
1748     if (cTarget || JSString) {
1749         // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
1750         // want to potentially kill the plug-in inside of its URL request.
1751         
1752         if (JSString && target && [frame findFrameNamed:target] != frame) {
1753             // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
1754             return NPERR_INVALID_PARAM;
1755         }
1756         
1757         bool currentEventIsUserGesture = false;
1758         if (_eventHandler)
1759             currentEventIsUserGesture = _eventHandler->currentEventIsUserGesture();
1760         
1761         WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request 
1762                                                                           frameName:target
1763                                                                          notifyData:notifyData 
1764                                                                    sendNotification:sendNotification
1765                                                             didStartFromUserGesture:currentEventIsUserGesture];
1766         [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0];
1767         [pluginRequest release];
1768     } else {
1769         RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create(request, plugin, sendNotification, notifyData);
1770
1771         streams.add(stream.get());
1772         stream->start();
1773     }
1774     
1775     return NPERR_NO_ERROR;
1776 }
1777
1778 -(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData
1779 {
1780     LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget);
1781
1782     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1783     return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES];
1784 }
1785
1786 -(NPError)getURL:(const char *)URLCString target:(const char *)cTarget
1787 {
1788     LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget);
1789
1790     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1791     return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO];
1792 }
1793
1794 - (NPError)_postURL:(const char *)URLCString
1795              target:(const char *)target
1796                 len:(UInt32)len
1797                 buf:(const char *)buf
1798                file:(NPBool)file
1799          notifyData:(void *)notifyData
1800    sendNotification:(BOOL)sendNotification
1801        allowHeaders:(BOOL)allowHeaders
1802 {
1803     if (!URLCString || !len || !buf) {
1804         return NPERR_INVALID_PARAM;
1805     }
1806     
1807     NSData *postData = nil;
1808
1809     if (file) {
1810         // If we're posting a file, buf is either a file URL or a path to the file.
1811         NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1);
1812         if (!bufString) {
1813             return NPERR_INVALID_PARAM;
1814         }
1815         NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString];
1816         NSString *path;
1817         if ([fileURL isFileURL]) {
1818             path = [fileURL path];
1819         } else {
1820             path = bufString;
1821         }
1822         postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
1823         CFRelease(bufString);
1824         if (!postData) {
1825             return NPERR_FILE_NOT_FOUND;
1826         }
1827     } else {
1828         postData = [NSData dataWithBytes:buf length:len];
1829     }
1830
1831     if ([postData length] == 0) {
1832         return NPERR_INVALID_PARAM;
1833     }
1834
1835     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1836     [request setHTTPMethod:@"POST"];
1837     
1838     if (allowHeaders) {
1839         if ([postData _web_startsWithBlankLine]) {
1840             postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)];
1841         } else {
1842             NSInteger location = [postData _web_locationAfterFirstBlankLine];
1843             if (location != NSNotFound) {
1844                 // If the blank line is somewhere in the middle of postData, everything before is the header.
1845                 NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)];
1846                 NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
1847                 unsigned dataLength = [postData length] - location;
1848
1849                 // Sometimes plugins like to set Content-Length themselves when they post,
1850                 // but WebFoundation does not like that. So we will remove the header
1851                 // and instead truncate the data to the requested length.
1852                 NSString *contentLength = [header objectForKey:@"Content-Length"];
1853
1854                 if (contentLength != nil)
1855                     dataLength = min<unsigned>([contentLength intValue], dataLength);
1856                 [header removeObjectForKey:@"Content-Length"];
1857
1858                 if ([header count] > 0) {
1859                     [request setAllHTTPHeaderFields:header];
1860                 }
1861                 // Everything after the blank line is the actual content of the POST.
1862                 postData = [postData subdataWithRange:NSMakeRange(location, dataLength)];
1863
1864             }
1865         }
1866         if ([postData length] == 0) {
1867             return NPERR_INVALID_PARAM;
1868         }
1869     }
1870
1871     // Plug-ins expect to receive uncached data when doing a POST (3347134).
1872     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1873     [request setHTTPBody:postData];
1874     
1875     return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification];
1876 }
1877
1878 - (NPError)postURLNotify:(const char *)URLCString
1879                   target:(const char *)target
1880                      len:(UInt32)len
1881                      buf:(const char *)buf
1882                     file:(NPBool)file
1883               notifyData:(void *)notifyData
1884 {
1885     LOG(Plugins, "NPN_PostURLNotify: %s", URLCString);
1886     return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES];
1887 }
1888
1889 -(NPError)postURL:(const char *)URLCString
1890            target:(const char *)target
1891               len:(UInt32)len
1892               buf:(const char *)buf
1893              file:(NPBool)file
1894 {
1895     LOG(Plugins, "NPN_PostURL: %s", URLCString);        
1896     // As documented, only allow headers to be specified via NPP_PostURL when using a file.
1897     return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file];
1898 }
1899
1900 -(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream
1901 {
1902     LOG(Plugins, "NPN_NewStream");
1903     return NPERR_GENERIC_ERROR;
1904 }
1905
1906 -(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer
1907 {
1908     LOG(Plugins, "NPN_Write");
1909     return NPERR_GENERIC_ERROR;
1910 }
1911
1912 -(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason
1913 {
1914     LOG(Plugins, "NPN_DestroyStream");
1915     // This function does a sanity check to ensure that the NPStream provided actually
1916     // belongs to the plug-in that provided it, which fixes a crash in the DivX 
1917     // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203
1918     if (!stream || WebNetscapePluginStream::ownerForStream(stream) != plugin) {
1919         LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream);
1920         return NPERR_INVALID_INSTANCE_ERROR;
1921     }
1922     
1923     WebNetscapePluginStream* browserStream = static_cast<WebNetscapePluginStream*>(stream->ndata);
1924     browserStream->cancelLoadAndDestroyStreamWithError(browserStream->errorForReason(reason));
1925     
1926     return NPERR_NO_ERROR;
1927 }
1928
1929 - (const char *)userAgent
1930 {
1931     NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()];
1932     
1933     if (_isSilverlight) {
1934         // Silverlight has a workaround for a leak in Safari 2. This workaround is 
1935         // applied when the user agent does not contain "Version/3" so we append it
1936         // at the end of the user agent.
1937         userAgent = [userAgent stringByAppendingString:@" Version/3.2.1"];
1938     }        
1939         
1940     return [userAgent UTF8String];
1941 }
1942
1943 -(void)status:(const char *)message
1944 {    
1945     CFStringRef status = CFStringCreateWithCString(NULL, message ? message : "", kCFStringEncodingUTF8);
1946     if (!status) {
1947         LOG_ERROR("NPN_Status: the message was not valid UTF-8");
1948         return;
1949     }
1950     
1951     LOG(Plugins, "NPN_Status: %@", status);
1952     WebView *wv = [self webView];
1953     [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status];
1954     CFRelease(status);
1955 }
1956
1957 -(void)invalidateRect:(NPRect *)invalidRect
1958 {
1959     LOG(Plugins, "NPN_InvalidateRect");
1960     [self invalidatePluginContentRect:NSMakeRect(invalidRect->left, invalidRect->top,
1961         (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)];
1962 }
1963
1964 - (void)invalidateRegion:(NPRegion)invalidRegion
1965 {
1966     LOG(Plugins, "NPN_InvalidateRegion");
1967     NSRect invalidRect = NSZeroRect;
1968     switch (drawingModel) {
1969 #ifndef NP_NO_QUICKDRAW
1970         case NPDrawingModelQuickDraw:
1971         {
1972             ::Rect qdRect;
1973             GetRegionBounds((NPQDRegion)invalidRegion, &qdRect);
1974             invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top);
1975         }
1976         break;
1977 #endif /* NP_NO_QUICKDRAW */
1978         
1979         case NPDrawingModelCoreGraphics:
1980         {
1981             CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion);
1982             invalidRect = *(NSRect*)&cgRect;
1983             break;
1984         }
1985         default:
1986             ASSERT_NOT_REACHED();
1987         break;
1988     }
1989     
1990     [self invalidatePluginContentRect:invalidRect];
1991 }
1992
1993 -(void)forceRedraw
1994 {
1995     LOG(Plugins, "forceRedraw");
1996     [self invalidatePluginContentRect:[self bounds]];
1997     [[self window] displayIfNeeded];
1998 }
1999
2000 - (NPError)getVariable:(NPNVariable)variable value:(void *)value
2001 {
2002     switch (variable) {
2003         case NPNVWindowNPObject:
2004         {
2005             Frame* frame = core([self webFrame]);
2006             NPObject* windowScriptObject = frame ? frame->script()->windowScriptNPObject() : 0;
2007
2008             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
2009             if (windowScriptObject)
2010                 _NPN_RetainObject(windowScriptObject);
2011             
2012             void **v = (void **)value;
2013             *v = windowScriptObject;
2014
2015             return NPERR_NO_ERROR;
2016         }
2017
2018         case NPNVPluginElementNPObject:
2019         {
2020             if (!_element)
2021                 return NPERR_GENERIC_ERROR;
2022             
2023             NPObject *plugInScriptObject = _element->getNPObject();
2024
2025             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
2026             if (plugInScriptObject)
2027                 _NPN_RetainObject(plugInScriptObject);
2028
2029             void **v = (void **)value;
2030             *v = plugInScriptObject;
2031
2032             return NPERR_NO_ERROR;
2033         }
2034         
2035         case NPNVpluginDrawingModel:
2036         {
2037             *(NPDrawingModel *)value = drawingModel;
2038             return NPERR_NO_ERROR;
2039         }
2040
2041 #ifndef NP_NO_QUICKDRAW
2042         case NPNVsupportsQuickDrawBool:
2043         {
2044             *(NPBool *)value = TRUE;
2045             return NPERR_NO_ERROR;
2046         }
2047 #endif /* NP_NO_QUICKDRAW */
2048         
2049         case NPNVsupportsCoreGraphicsBool:
2050         {
2051             *(NPBool *)value = TRUE;
2052             return NPERR_NO_ERROR;
2053         }
2054
2055         case NPNVsupportsOpenGLBool:
2056         {
2057             *(NPBool *)value = FALSE;
2058             return NPERR_NO_ERROR;
2059         }
2060         
2061         case NPNVsupportsCoreAnimationBool:
2062         {
2063 #ifdef BUILDING_ON_TIGER
2064             *(NPBool *)value = FALSE;
2065 #else
2066             *(NPBool *)value = TRUE;
2067 #endif
2068             return NPERR_NO_ERROR;
2069         }
2070             
2071 #ifndef NP_NO_CARBON
2072         case NPNVsupportsCarbonBool:
2073         {
2074             *(NPBool *)value = TRUE;
2075             return NPERR_NO_ERROR;
2076         }
2077 #endif /* NP_NO_CARBON */
2078
2079         case NPNVsupportsCocoaBool:
2080         {
2081             *(NPBool *)value = TRUE;
2082             return NPERR_NO_ERROR;
2083         }
2084
2085         case NPNVprivateModeBool:
2086         {
2087             *(NPBool *)value = _isPrivateBrowsingEnabled;
2088             return NPERR_NO_ERROR;
2089         }
2090
2091         case WKNVBrowserContainerCheckFuncs:
2092         {
2093             *(WKNBrowserContainerCheckFuncs **)value = browserContainerCheckFuncs();
2094             return NPERR_NO_ERROR;
2095         }
2096 #if USE(ACCELERATED_COMPOSITING)
2097         case WKNVSupportsCompositingCoreAnimationPluginsBool:
2098         {
2099             *(NPBool *)value = [[[self webView] preferences] acceleratedCompositingEnabled];
2100             return NPERR_NO_ERROR;
2101         }
2102 #endif
2103         default:
2104             break;
2105     }
2106
2107     return NPERR_GENERIC_ERROR;
2108 }
2109
2110 - (NPError)setVariable:(NPPVariable)variable value:(void *)value
2111 {
2112     switch (variable) {
2113         case NPPVpluginDrawingModel:
2114         {
2115             // Can only set drawing model inside NPP_New()
2116             if (self != [[self class] currentPluginView])
2117                 return NPERR_GENERIC_ERROR;
2118             
2119             // Check for valid, supported drawing model
2120             NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value;
2121             switch (newDrawingModel) {
2122                 // Supported drawing models:
2123 #ifndef NP_NO_QUICKDRAW
2124                 case NPDrawingModelQuickDraw:
2125 #endif
2126                 case NPDrawingModelCoreGraphics:
2127 #ifndef BUILDING_ON_TIGER
2128                 case NPDrawingModelCoreAnimation:
2129 #endif
2130                     drawingModel = newDrawingModel;
2131                     return NPERR_NO_ERROR;
2132                     
2133
2134                 // Unsupported (or unknown) drawing models:
2135                 default:
2136                     LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", _eventHandler.get(), drawingModel);
2137                     return NPERR_GENERIC_ERROR;
2138             }
2139         }
2140         
2141         case NPPVpluginEventModel:
2142         {
2143             // Can only set event model inside NPP_New()
2144             if (self != [[self class] currentPluginView])
2145                 return NPERR_GENERIC_ERROR;
2146             
2147             // Check for valid, supported event model
2148             NPEventModel newEventModel = (NPEventModel)(uintptr_t)value;
2149             switch (newEventModel) {
2150                 // Supported event models:
2151 #ifndef NP_NO_CARBON
2152                 case NPEventModelCarbon:
2153 #endif
2154                 case NPEventModelCocoa:
2155                     eventModel = newEventModel;
2156                     return NPERR_NO_ERROR;
2157                     
2158                     // Unsupported (or unknown) event models:
2159                 default:
2160                     LOG(Plugins, "Plugin %@ uses unsupported event model: %d", _eventHandler.get(), eventModel);
2161                     return NPERR_GENERIC_ERROR;
2162             }
2163         }
2164             
2165         default:
2166             return NPERR_GENERIC_ERROR;
2167     }
2168 }
2169
2170 - (uint32_t)scheduleTimerWithInterval:(uint32_t)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32_t timerID))timerFunc
2171 {
2172     if (!timerFunc)
2173         return 0;
2174     
2175     if (!timers)
2176         timers = new HashMap<uint32_t, PluginTimer*>;
2177     
2178     uint32_t timerID;
2179     
2180     do {
2181         timerID = ++currentTimerID;
2182     } while (timers->contains(timerID) || timerID == 0);
2183     
2184     PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc);
2185     timers->set(timerID, timer);
2186
2187     if (_shouldFireTimers)
2188         timer->start(_isCompletelyObscured);
2189     
2190     return timerID;
2191 }
2192
2193 - (void)unscheduleTimer:(uint32_t)timerID
2194 {
2195     if (!timers)
2196         return;
2197     
2198     if (PluginTimer* timer = timers->take(timerID))
2199         delete timer;
2200 }
2201
2202 - (NPError)popUpContextMenu:(NPMenu *)menu
2203 {
2204     NSEvent *currentEvent = [NSApp currentEvent];
2205     
2206     // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent.
2207     if (!currentEvent)
2208         return NPERR_GENERIC_ERROR;
2209     
2210     [NSMenu popUpContextMenu:(NSMenu *)menu withEvent:currentEvent forView:self];
2211     return NPERR_NO_ERROR;
2212 }
2213
2214 - (NPError)getVariable:(NPNURLVariable)variable forURL:(const char*)url value:(char**)value length:(uint32_t*)length
2215 {
2216     switch (variable) {
2217         case NPNURLVCookie: {
2218             if (!value)
2219                 break;
2220             
2221             NSURL *URL = [self URLWithCString:url];
2222             if (!URL)
2223                 break;
2224             
2225             if (Frame* frame = core([self webFrame])) {
2226                 String cookieString = cookies(frame->document(), URL); 
2227                 CString cookieStringUTF8 = cookieString.utf8();
2228                 if (cookieStringUTF8.isNull())
2229                     return NPERR_GENERIC_ERROR;
2230
2231                 *value = static_cast<char*>(NPN_MemAlloc(cookieStringUTF8.length()));
2232                 memcpy(*value, cookieStringUTF8.data(), cookieStringUTF8.length());
2233                 
2234                 if (length)
2235                     *length = cookieStringUTF8.length();
2236                 return NPERR_NO_ERROR;
2237             }
2238             break;
2239         }
2240         case NPNURLVProxy: {
2241 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2242             if (!value)
2243                 break;
2244             
2245             NSURL *URL = [self URLWithCString:url];
2246             if (!URL)
2247                 break;
2248
2249             Vector<ProxyServer> proxyServers = proxyServersForURL(URL, 0);
2250             CString proxiesUTF8 = toString(proxyServers).utf8();
2251             
2252             *value = static_cast<char*>(NPN_MemAlloc(proxiesUTF8.length()));
2253             memcpy(*value, proxiesUTF8.data(), proxiesUTF8.length());
2254             
2255            if (length)
2256                *length = proxiesUTF8.length();
2257             
2258             return NPERR_NO_ERROR;
2259 #else
2260             break;
2261 #endif
2262         }
2263     }
2264     return NPERR_GENERIC_ERROR;
2265 }
2266
2267 - (NPError)setVariable:(NPNURLVariable)variable forURL:(const char*)url value:(const char*)value length:(uint32_t)length
2268 {
2269     switch (variable) {
2270         case NPNURLVCookie: {
2271             NSURL *URL = [self URLWithCString:url];
2272             if (!URL)
2273                 break;
2274             
2275             String cookieString = String::fromUTF8(value, length);
2276             if (!cookieString)
2277                 break;
2278             
2279             if (Frame* frame = core([self webFrame])) {
2280                 setCookies(frame->document(), URL, cookieString);
2281                 return NPERR_NO_ERROR;
2282             }
2283             
2284             break;
2285         }
2286         case NPNURLVProxy:
2287             // Can't set the proxy for a URL.
2288             break;
2289     }
2290     return NPERR_GENERIC_ERROR;
2291 }
2292
2293 - (NPError)getAuthenticationInfoWithProtocol:(const char*)protocolStr host:(const char*)hostStr port:(int32_t)port scheme:(const char*)schemeStr realm:(const char*)realmStr
2294                                     username:(char**)usernameStr usernameLength:(uint32_t*)usernameLength 
2295                                     password:(char**)passwordStr passwordLength:(uint32_t*)passwordLength
2296 {
2297     if (!protocolStr || !hostStr || !schemeStr || !realmStr || !usernameStr || !usernameLength || !passwordStr || !passwordLength)
2298         return NPERR_GENERIC_ERROR;
2299   
2300     CString username;
2301     CString password;
2302     if (!getAuthenticationInfo(protocolStr, hostStr, port, schemeStr, realmStr, username, password))
2303         return NPERR_GENERIC_ERROR;
2304     
2305     *usernameLength = username.length();
2306     *usernameStr = static_cast<char*>(NPN_MemAlloc(username.length()));
2307     memcpy(*usernameStr, username.data(), username.length());
2308     
2309     *passwordLength = password.length();
2310     *passwordStr = static_cast<char*>(NPN_MemAlloc(password.length()));
2311     memcpy(*passwordStr, password.data(), password.length());
2312     
2313     return NPERR_NO_ERROR;
2314 }
2315
2316 - (char*)resolveURL:(const char*)url forTarget:(const char*)target
2317 {
2318     CString location = [self resolvedURLStringForURL:url target:target];
2319
2320     if (location.isNull())
2321         return 0;
2322     
2323     // We use strdup here because the caller needs to free it with NPN_MemFree (which calls free).
2324     return strdup(location.data());
2325 }
2326
2327 @end
2328
2329 @implementation WebNetscapePluginView (Internal)
2330
2331 - (BOOL)_shouldCancelSrcStream
2332 {
2333     ASSERT(_isStarted);
2334     
2335     // Check if we should cancel the load
2336     NPBool cancelSrcStream = 0;
2337     if ([_pluginPackage.get() pluginFuncs]->getvalue &&
2338         [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCancelSrcStream, &cancelSrcStream) == NPERR_NO_ERROR && cancelSrcStream)
2339         return YES;
2340     
2341     return NO;
2342 }
2343
2344 // Work around Silverlight full screen performance issue by maintaining an accelerated GL pixel format.
2345 // We can safely remove it at some point in the future when both:
2346 // 1) Microsoft releases a genuine fix for 7288546.
2347 // 2) Enough Silverlight users update to the new Silverlight.
2348 // For now, we'll distinguish older broken versions of Silverlight by asking the plug-in if it resolved its full screen badness.
2349 - (void)_workaroundSilverlightFullscreenBug:(BOOL)initializedPlugin
2350 {
2351 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2352     ASSERT(_isSilverlight);
2353     NPBool isFullscreenPerformanceIssueFixed = 0;
2354     NPPluginFuncs *pluginFuncs = [_pluginPackage.get() pluginFuncs];
2355     if (pluginFuncs->getvalue && pluginFuncs->getvalue(plugin, static_cast<NPPVariable>(WKNVSilverlightFullscreenPerformanceIssueFixed), &isFullscreenPerformanceIssueFixed) == NPERR_NO_ERROR && isFullscreenPerformanceIssueFixed)
2356         return;
2357     
2358     static CGLPixelFormatObj pixelFormatObject = 0;
2359     static unsigned refCount = 0;
2360     
2361     if (initializedPlugin) {
2362         refCount++;
2363         if (refCount == 1) {
2364             const CGLPixelFormatAttribute attributes[] = { kCGLPFAAccelerated, static_cast<CGLPixelFormatAttribute>(0) };
2365             GLint npix;
2366             CGLChoosePixelFormat(attributes, &pixelFormatObject, &npix);
2367         }  
2368     } else {
2369         ASSERT(pixelFormatObject);
2370         refCount--;
2371         if (!refCount) 
2372             CGLReleasePixelFormat(pixelFormatObject);
2373     }
2374 #endif
2375 }
2376
2377 - (NPError)_createPlugin
2378 {
2379     plugin = (NPP)calloc(1, sizeof(NPP_t));
2380     plugin->ndata = self;
2381
2382     ASSERT([_pluginPackage.get() pluginFuncs]->newp);
2383
2384     // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance.
2385     ASSERT(pluginFunctionCallDepth == 0);
2386
2387     PluginMainThreadScheduler::scheduler().registerPlugin(plugin);
2388
2389     _isFlash = [_pluginPackage.get() bundleIdentifier] == "com.macromedia.Flash Player.plugin";
2390     _isSilverlight = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.SilverlightPlugin";
2391
2392     [[self class] setCurrentPluginView:self];
2393     NPError npErr = [_pluginPackage.get() pluginFuncs]->newp((char *)[_MIMEType.get() cString], plugin, _mode, argsCount, cAttributes, cValues, NULL);
2394     [[self class] setCurrentPluginView:nil];
2395     if (_isSilverlight)
2396         [self _workaroundSilverlightFullscreenBug:YES];
2397     LOG(Plugins, "NPP_New: %d", npErr);
2398     return npErr;
2399 }
2400
2401 - (void)_destroyPlugin
2402 {
2403     PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin);
2404     
2405     if (_isSilverlight)
2406         [self _workaroundSilverlightFullscreenBug:NO];
2407     
2408     NPError npErr;
2409     npErr = ![_pluginPackage.get() pluginFuncs]->destroy(plugin, NULL);
2410     LOG(Plugins, "NPP_Destroy: %d", npErr);
2411     
2412     if (Frame* frame = core([self webFrame]))
2413         frame->script()->cleanupScriptObjectsForPlugin(self);
2414         
2415     free(plugin);
2416     plugin = NULL;
2417 }
2418
2419 - (NSBitmapImageRep *)_printedPluginBitmap
2420 {
2421 #ifdef NP_NO_QUICKDRAW
2422     return nil;
2423 #else
2424     // Cannot print plugins that do not implement NPP_Print
2425     if (![_pluginPackage.get() pluginFuncs]->print)
2426         return nil;
2427
2428     // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into.
2429     // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format.
2430     NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
2431                                                          pixelsWide:window.width
2432                                                          pixelsHigh:window.height
2433                                                          bitsPerSample:8
2434                                                          samplesPerPixel:4
2435                                                          hasAlpha:YES
2436                                                          isPlanar:NO
2437                                                          colorSpaceName:NSDeviceRGBColorSpace
2438                                                          bitmapFormat:NSAlphaFirstBitmapFormat
2439                                                          bytesPerRow:0
2440                                                          bitsPerPixel:0] autorelease];
2441     ASSERT(bitmap);
2442     
2443     // Create a GWorld with the same underlying buffer into which the plugin can draw
2444     ::Rect printGWorldBounds;
2445     SetRect(&printGWorldBounds, 0, 0, window.width, window.height);
2446     GWorldPtr printGWorld;
2447     if (NewGWorldFromPtr(&printGWorld,
2448                          k32ARGBPixelFormat,
2449                          &printGWorldBounds,
2450                          NULL,
2451                          NULL,
2452                          0,
2453                          (Ptr)[bitmap bitmapData],
2454                          [bitmap bytesPerRow]) != noErr) {
2455         LOG_ERROR("Could not create GWorld for printing");
2456         return nil;
2457     }
2458     
2459     /// Create NPWindow for the GWorld
2460     NPWindow printNPWindow;
2461     printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr
2462     printNPWindow.x = 0;
2463     printNPWindow.y = 0;
2464     printNPWindow.width = window.width;
2465     printNPWindow.height = window.height;
2466     printNPWindow.clipRect.top = 0;
2467     printNPWindow.clipRect.left = 0;
2468     printNPWindow.clipRect.right = window.width;
2469     printNPWindow.clipRect.bottom = window.height;
2470     printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window
2471     
2472     // Create embed-mode NPPrint
2473     NPPrint npPrint;
2474     npPrint.mode = NP_EMBED;
2475     npPrint.print.embedPrint.window = printNPWindow;
2476     npPrint.print.embedPrint.platformPrint = printGWorld;
2477     
2478     // Tell the plugin to print into the GWorld
2479     [self willCallPlugInFunction];
2480     {
2481         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
2482         [_pluginPackage.get() pluginFuncs]->print(plugin, &npPrint);
2483     }
2484     [self didCallPlugInFunction];
2485
2486     // Don't need the GWorld anymore
2487     DisposeGWorld(printGWorld);
2488         
2489     return bitmap;
2490 #endif
2491 }
2492
2493 - (void)_redeliverStream
2494 {
2495     if ([self dataSource] && _isStarted) {
2496         // Deliver what has not been passed to the plug-in up to this point.
2497         if (_dataLengthReceived > 0) {
2498             NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)];
2499             _dataLengthReceived = 0;
2500             [self pluginView:self receivedData:data];
2501             if (![[self dataSource] isLoading]) {
2502                 if (_error)
2503                     [self pluginView:self receivedError:_error.get()];
2504                 else
2505                     [self pluginViewFinishedLoading:self];
2506             }
2507         }
2508     }
2509 }
2510
2511 @end
2512
2513 #endif