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