Get rid of -[NSMutableDictionary _webkit_setObject:forUncopiedKey:]
[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     for (WebFrame *frame in [_pendingFrameLoads keyEnumerator])
1193         [frame _setInternalLoadDelegate:nil];
1194     [NSObject cancelPreviousPerformRequestsWithTarget:self];
1195
1196     // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted.
1197     lastSetWindow.type = (NPWindowType)0;
1198     
1199     _pluginLayer = 0;
1200     
1201     [self _destroyPlugin];
1202     [_pluginPackage.get() close];
1203     
1204     _eventHandler.clear();
1205 }
1206
1207 - (NPEventModel)eventModel
1208 {
1209     return eventModel;
1210 }
1211
1212 - (NPP)plugin
1213 {
1214     return plugin;
1215 }
1216
1217 - (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values
1218 {
1219     ASSERT([keys count] == [values count]);
1220     
1221     // Convert the attributes to 2 C string arrays.
1222     // These arrays are passed to NPP_New, but the strings need to be
1223     // modifiable and live the entire life of the plugin.
1224
1225     // The Java plug-in requires the first argument to be the base URL
1226     if ([_MIMEType.get() isEqualToString:@"application/x-java-applet"]) {
1227         cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *));
1228         cValues = (char **)malloc(([values count] + 1) * sizeof(char *));
1229         cAttributes[0] = strdup("DOCBASE");
1230         cValues[0] = strdup([_baseURL.get() _web_URLCString]);
1231         argsCount++;
1232     } else {
1233         cAttributes = (char **)malloc([keys count] * sizeof(char *));
1234         cValues = (char **)malloc([values count] * sizeof(char *));
1235     }
1236
1237     BOOL isWMP = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.WMP.defaultplugin";
1238     
1239     unsigned i;
1240     unsigned count = [keys count];
1241     for (i = 0; i < count; i++) {
1242         NSString *key = [keys objectAtIndex:i];
1243         NSString *value = [values objectAtIndex:i];
1244         if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) {
1245             specifiedHeight = [value intValue];
1246         } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) {
1247             specifiedWidth = [value intValue];
1248         }
1249         // Avoid Window Media Player crash when these attributes are present.
1250         if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) {
1251             continue;
1252         }
1253         cAttributes[argsCount] = strdup([key UTF8String]);
1254         cValues[argsCount] = strdup([value UTF8String]);
1255         LOG(Plugins, "%@ = %@", key, value);
1256         argsCount++;
1257     }
1258 }
1259
1260 - (uint32_t)checkIfAllowedToLoadURL:(const char*)urlCString frame:(const char*)frameNameCString 
1261                        callbackFunc:(void (*)(NPP npp, uint32_t checkID, NPBool allowed, void* context))callbackFunc 
1262                             context:(void*)context
1263 {
1264     if (!_containerChecksInProgress) 
1265         _containerChecksInProgress = [[NSMutableDictionary alloc] init];
1266     
1267     NSString *frameName = frameNameCString ? [NSString stringWithCString:frameNameCString encoding:NSISOLatin1StringEncoding] : nil;
1268     
1269     ++_currentContainerCheckRequestID;
1270     WebNetscapeContainerCheckContextInfo *contextInfo = [[WebNetscapeContainerCheckContextInfo alloc] initWithCheckRequestID:_currentContainerCheckRequestID 
1271                                                                                                                 callbackFunc:callbackFunc
1272                                                                                                                       context:context];
1273     
1274     WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[self requestWithURLCString:urlCString]
1275                                                                         target:frameName
1276                                                                   resultObject:self
1277                                                                       selector:@selector(_containerCheckResult:contextInfo:)
1278                                                                     controller:self 
1279                                                                    contextInfo:contextInfo];
1280     
1281     [contextInfo release];
1282     [_containerChecksInProgress setObject:check forKey:[NSNumber numberWithInt:_currentContainerCheckRequestID]];
1283     [check start];
1284     
1285     return _currentContainerCheckRequestID;
1286 }
1287
1288 - (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo
1289 {
1290     ASSERT([contextInfo isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]);
1291     void (*pluginCallback)(NPP npp, uint32_t, NPBool, void*) = [contextInfo callback];
1292     
1293     if (!pluginCallback) {
1294         ASSERT_NOT_REACHED();
1295         return;
1296     }
1297     
1298     pluginCallback([self plugin], [contextInfo checkRequestID], (policy == PolicyUse), [contextInfo context]);
1299 }
1300
1301 - (void)cancelCheckIfAllowedToLoadURL:(uint32_t)checkID
1302 {
1303     WebPluginContainerCheck *check = (WebPluginContainerCheck *)[_containerChecksInProgress objectForKey:[NSNumber numberWithInt:checkID]];
1304     
1305     if (!check)
1306         return;
1307     
1308     [check cancel];
1309     [_containerChecksInProgress removeObjectForKey:[NSNumber numberWithInt:checkID]];
1310 }
1311
1312 // WebPluginContainerCheck automatically calls this method after invoking our _containerCheckResult: selector.
1313 // It works this way because calling -[WebPluginContainerCheck cancel] allows it to do it's teardown process.
1314 - (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck
1315 {
1316     ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]);
1317     WebPluginContainerCheck *check = (WebPluginContainerCheck *)webPluginContainerCheck;
1318     ASSERT([[check contextInfo] isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]);
1319     
1320     [self cancelCheckIfAllowedToLoadURL:[[check contextInfo] checkRequestID]];
1321 }
1322
1323
1324 // MARK: NSVIEW
1325
1326 - (id)initWithFrame:(NSRect)frame
1327       pluginPackage:(WebNetscapePluginPackage *)pluginPackage
1328                 URL:(NSURL *)URL
1329             baseURL:(NSURL *)baseURL
1330            MIMEType:(NSString *)MIME
1331       attributeKeys:(NSArray *)keys
1332     attributeValues:(NSArray *)values
1333        loadManually:(BOOL)loadManually
1334             element:(PassRefPtr<WebCore::HTMLPlugInElement>)element
1335 {
1336     self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element];
1337     if (!self)
1338         return nil;
1339
1340     _pendingFrameLoads = adoptNS([[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:0]);
1341
1342     // load the plug-in if it is not already loaded
1343     if (![pluginPackage load]) {
1344         [self release];
1345         return nil;
1346     }
1347
1348     return self;
1349 }
1350
1351 - (id)initWithFrame:(NSRect)frame
1352 {
1353     ASSERT_NOT_REACHED();
1354     return nil;
1355 }
1356
1357 - (void)fini
1358 {
1359 #ifndef NP_NO_QUICKDRAW
1360     if (offscreenGWorld)
1361         DisposeGWorld(offscreenGWorld);
1362 #endif
1363
1364     for (unsigned i = 0; i < argsCount; i++) {
1365         free(cAttributes[i]);
1366         free(cValues[i]);
1367     }
1368     free(cAttributes);
1369     free(cValues);
1370     
1371     ASSERT(!_eventHandler);
1372     
1373     if (timers) {
1374         deleteAllValues(*timers);
1375         delete timers;
1376     }  
1377     
1378     [_containerChecksInProgress release];
1379 }
1380
1381 - (void)disconnectStream:(WebNetscapePluginStream*)stream
1382 {
1383     streams.remove(stream);
1384 }
1385
1386 - (void)dealloc
1387 {
1388     ASSERT(!_isStarted);
1389     ASSERT(!plugin);
1390
1391     [self fini];
1392
1393     [super dealloc];
1394 }
1395
1396 - (void)finalize
1397 {
1398     ASSERT_MAIN_THREAD();
1399     ASSERT(!_isStarted);
1400
1401     [self fini];
1402
1403     [super finalize];
1404 }
1405
1406 - (void)drawRect:(NSRect)rect
1407 {
1408     if (_cachedSnapshot) {
1409         NSRect sourceRect = { NSZeroPoint, [_cachedSnapshot.get() size] };
1410         [_cachedSnapshot.get() drawInRect:[self bounds] fromRect:sourceRect operation:NSCompositeSourceOver fraction:1];
1411         return;
1412     }
1413     
1414     if (drawingModel == NPDrawingModelCoreAnimation && (!_snapshotting || ![self supportsSnapshotting]))
1415         return;
1416
1417     if (!_isStarted)
1418         return;
1419     
1420     if ([NSGraphicsContext currentContextDrawingToScreen] || _isFlash)
1421         [self sendDrawRectEvent:rect];
1422     else {
1423         NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap];
1424         if (printedPluginBitmap) {
1425             // Flip the bitmap before drawing because the QuickDraw port is flipped relative
1426             // to this view.
1427             CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
1428             CGContextSaveGState(cgContext);
1429             NSRect bounds = [self bounds];
1430             CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds));
1431             CGContextScaleCTM(cgContext, 1.0f, -1.0f);
1432             [printedPluginBitmap drawInRect:bounds];
1433             CGContextRestoreGState(cgContext);
1434         }
1435     }
1436 }
1437
1438 - (NPObject *)createPluginScriptableObject
1439 {
1440     if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted)
1441         return NULL;
1442         
1443     NPObject *value = NULL;
1444     NPError error;
1445     [self willCallPlugInFunction];
1446     {
1447         JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
1448         error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginScriptableNPObject, &value);
1449     }
1450     [self didCallPlugInFunction];
1451     if (error != NPERR_NO_ERROR)
1452         return NULL;
1453     
1454     return value;
1455 }
1456
1457 - (BOOL)getFormValue:(NSString **)value
1458 {
1459     if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted)
1460         return false;
1461     // Plugins will allocate memory for the buffer by using NPN_MemAlloc().
1462     char* buffer = NULL;
1463     NPError error;
1464     [self willCallPlugInFunction];
1465     {
1466         JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
1467         error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVformValue, &buffer);
1468     }
1469     [self didCallPlugInFunction];
1470     if (error != NPERR_NO_ERROR || !buffer)
1471         return false;
1472     *value = [[NSString alloc] initWithUTF8String:buffer];
1473     [_pluginPackage.get() browserFuncs]->memfree(buffer);
1474     return true;
1475 }
1476
1477 - (void)willCallPlugInFunction
1478 {
1479     ASSERT(plugin);
1480
1481     // Could try to prevent infinite recursion here, but it's probably not worth the effort.
1482     pluginFunctionCallDepth++;
1483 }
1484
1485 - (void)didCallPlugInFunction
1486 {
1487     ASSERT(pluginFunctionCallDepth > 0);
1488     pluginFunctionCallDepth--;
1489     
1490     // If -stop was called while we were calling into a plug-in function, and we're no longer
1491     // inside a plug-in function, stop now.
1492     if (pluginFunctionCallDepth == 0 && shouldStopSoon) {
1493         shouldStopSoon = NO;
1494         [self stop];
1495     }
1496 }
1497
1498 -(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
1499 {
1500     ASSERT(_loadManually);
1501     ASSERT(!_manualStream);
1502
1503     _manualStream = WebNetscapePluginStream::create(core([self webFrame])->loader());
1504 }
1505
1506 - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
1507 {
1508     ASSERT(_loadManually);
1509     ASSERT(_manualStream);
1510     
1511     _dataLengthReceived += [data length];
1512     
1513     if (!_isStarted)
1514         return;
1515
1516     if (!_manualStream->plugin()) {
1517         // Check if the load should be cancelled
1518         if ([self _shouldCancelSrcStream]) {
1519             NSURLResponse *response = [[self dataSource] response];
1520             
1521             NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad
1522                                                             contentURL:[response URL]
1523                                                          pluginPageURL:nil
1524                                                             pluginName:nil // FIXME: Get this from somewhere
1525                                                               MIMEType:[response MIMEType]];
1526             [[self dataSource] _documentLoader]->cancelMainResourceLoad(error);
1527             [error release];
1528             return;
1529         }
1530         
1531         _manualStream->setRequestURL([[[self dataSource] request] URL]);
1532         _manualStream->setPlugin([self plugin]);
1533         ASSERT(_manualStream->plugin());
1534         
1535         _manualStream->startStreamWithResponse([[self dataSource] response]);
1536     }
1537
1538     if (_manualStream->plugin())
1539         _manualStream->didReceiveData(0, static_cast<const char *>([data bytes]), [data length]);
1540 }
1541
1542 - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
1543 {
1544     ASSERT(_loadManually);
1545
1546     _error = error;
1547     
1548     if (!_isStarted) {
1549         return;
1550     }
1551
1552     _manualStream->destroyStreamWithError(error);
1553 }
1554
1555 - (void)pluginViewFinishedLoading:(NSView *)pluginView 
1556 {
1557     ASSERT(_loadManually);
1558     ASSERT(_manualStream);
1559     
1560     if (_isStarted)
1561         _manualStream->didFinishLoading(0);
1562 }
1563
1564 - (NSTextInputContext *)inputContext
1565 {
1566     return nil;
1567 }
1568
1569 @end
1570
1571 @implementation WebNetscapePluginView (WebNPPCallbacks)
1572
1573 - (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest
1574 {
1575     // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called
1576     // if we are stopped since this method is called after a delay and we call 
1577     // cancelPreviousPerformRequestsWithTarget inside of stop.
1578     if (!_isStarted) {
1579         return;
1580     }
1581     
1582     NSURL *URL = [[JSPluginRequest request] URL];
1583     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1584     ASSERT(JSString);
1585     
1586     NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]];
1587     
1588     // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
1589     if (!_isStarted) {
1590         return;
1591     }
1592         
1593     if ([JSPluginRequest frameName] != nil) {
1594         // FIXME: If the result is a string, we probably want to put that string into the frame.
1595         if ([JSPluginRequest sendNotification]) {
1596             [self willCallPlugInFunction];
1597             {
1598                 JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
1599                 [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]);
1600             }
1601             [self didCallPlugInFunction];
1602         }
1603     } else if ([result length] > 0) {
1604         // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
1605         NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
1606         
1607         RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create([NSURLRequest requestWithURL:URL], plugin, [JSPluginRequest sendNotification], [JSPluginRequest notifyData]);
1608         
1609         RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:URL 
1610                                                                              MIMEType:@"text/plain" 
1611                                                                 expectedContentLength:[JSData length]
1612                                                                      textEncodingName:nil]);
1613         
1614         stream->startStreamWithResponse(response.get());
1615         stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]);
1616         stream->didFinishLoading(0);
1617     }
1618 }
1619
1620 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason
1621 {
1622     ASSERT(_isStarted);
1623     
1624     WebPluginRequest *pluginRequest = [_pendingFrameLoads objectForKey:webFrame];
1625     ASSERT(pluginRequest != nil);
1626     ASSERT([pluginRequest sendNotification]);
1627         
1628     [self willCallPlugInFunction];
1629     {
1630         JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
1631         [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]);
1632     }
1633     [self didCallPlugInFunction];
1634     
1635     [_pendingFrameLoads removeObjectForKey:webFrame];
1636     [webFrame _setInternalLoadDelegate:nil];
1637 }
1638
1639 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error
1640 {
1641     NPReason reason = NPRES_DONE;
1642     if (error != nil)
1643         reason = WebNetscapePluginStream::reasonForError(error);
1644     [self webFrame:webFrame didFinishLoadWithReason:reason];
1645 }
1646
1647 - (void)loadPluginRequest:(WebPluginRequest *)pluginRequest
1648 {
1649     NSURLRequest *request = [pluginRequest request];
1650     NSString *frameName = [pluginRequest frameName];
1651     WebFrame *frame = nil;
1652     
1653     NSURL *URL = [request URL];
1654     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1655     
1656     ASSERT(frameName || JSString);
1657     
1658     if (frameName) {
1659         // FIXME - need to get rid of this window creation which
1660         // bypasses normal targeted link handling
1661         frame = kit(core([self webFrame])->loader()->findFrameForNavigation(frameName));
1662         if (frame == nil) {
1663             WebView *currentWebView = [self webView];
1664             NSDictionary *features = [[NSDictionary alloc] init];
1665             WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
1666                                                         createWebViewWithRequest:nil
1667                                                                   windowFeatures:features];
1668             [features release];
1669
1670             if (!newWebView) {
1671                 if ([pluginRequest sendNotification]) {
1672                     [self willCallPlugInFunction];
1673                     {
1674                         JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
1675                         [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]);
1676                     }
1677                     [self didCallPlugInFunction];
1678                 }
1679                 return;
1680             }
1681             
1682             frame = [newWebView mainFrame];
1683             core(frame)->tree()->setName(frameName);
1684             [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
1685         }
1686     }
1687
1688     if (JSString) {
1689         ASSERT(frame == nil || [self webFrame] == frame);
1690         [self evaluateJavaScriptPluginRequest:pluginRequest];
1691     } else {
1692         [frame loadRequest:request];
1693         if ([pluginRequest sendNotification]) {
1694             // Check if another plug-in view or even this view is waiting for the frame to load.
1695             // If it is, tell it that the load was cancelled because it will be anyway.
1696             WebNetscapePluginView *view = [frame _internalLoadDelegate];
1697             if (view != nil) {
1698                 ASSERT([view isKindOfClass:[WebNetscapePluginView class]]);
1699                 [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK];
1700             }
1701             [_pendingFrameLoads setObject:pluginRequest forKey:frame];
1702             [frame _setInternalLoadDelegate:self];
1703         }
1704     }
1705 }
1706
1707 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification
1708 {
1709     NSURL *URL = [request URL];
1710
1711     if (!URL) 
1712         return NPERR_INVALID_URL;
1713
1714     // Don't allow requests to be loaded when the document loader is stopping all loaders.
1715     if ([[self dataSource] _documentLoader]->isStopping())
1716         return NPERR_GENERIC_ERROR;
1717     
1718     NSString *target = nil;
1719     if (cTarget) {
1720         // Find the frame given the target string.
1721         target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding];
1722     }
1723     WebFrame *frame = [self webFrame];
1724
1725     // don't let a plugin start any loads if it is no longer part of a document that is being 
1726     // displayed unless the loads are in the same frame as the plugin.
1727     if ([[self dataSource] _documentLoader] != core([self webFrame])->loader()->activeDocumentLoader() &&
1728         (!cTarget || [frame findFrameNamed:target] != frame)) {
1729         return NPERR_GENERIC_ERROR; 
1730     }
1731     
1732     NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1733     if (JSString != nil) {
1734         if (![[[self webView] preferences] isJavaScriptEnabled]) {
1735             // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
1736             return NPERR_GENERIC_ERROR;
1737         } else if (cTarget == NULL && _mode == NP_FULL) {
1738             // Don't allow a JavaScript request from a standalone plug-in that is self-targetted
1739             // because this can cause the user to be redirected to a blank page (3424039).
1740             return NPERR_INVALID_PARAM;
1741         }
1742     } else {
1743         if (!core([self webFrame])->document()->securityOrigin()->canDisplay(URL))
1744             return NPERR_GENERIC_ERROR;
1745     }
1746         
1747     if (cTarget || JSString) {
1748         // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
1749         // want to potentially kill the plug-in inside of its URL request.
1750         
1751         if (JSString && target && [frame findFrameNamed:target] != frame) {
1752             // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
1753             return NPERR_INVALID_PARAM;
1754         }
1755         
1756         bool currentEventIsUserGesture = false;
1757         if (_eventHandler)
1758             currentEventIsUserGesture = _eventHandler->currentEventIsUserGesture();
1759         
1760         WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request 
1761                                                                           frameName:target
1762                                                                          notifyData:notifyData 
1763                                                                    sendNotification:sendNotification
1764                                                             didStartFromUserGesture:currentEventIsUserGesture];
1765         [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0];
1766         [pluginRequest release];
1767     } else {
1768         RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create(request, plugin, sendNotification, notifyData);
1769
1770         streams.add(stream.get());
1771         stream->start();
1772     }
1773     
1774     return NPERR_NO_ERROR;
1775 }
1776
1777 -(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData
1778 {
1779     LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget);
1780
1781     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1782     return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES];
1783 }
1784
1785 -(NPError)getURL:(const char *)URLCString target:(const char *)cTarget
1786 {
1787     LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget);
1788
1789     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1790     return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO];
1791 }
1792
1793 - (NPError)_postURL:(const char *)URLCString
1794              target:(const char *)target
1795                 len:(UInt32)len
1796                 buf:(const char *)buf
1797                file:(NPBool)file
1798          notifyData:(void *)notifyData
1799    sendNotification:(BOOL)sendNotification
1800        allowHeaders:(BOOL)allowHeaders
1801 {
1802     if (!URLCString || !len || !buf) {
1803         return NPERR_INVALID_PARAM;
1804     }
1805     
1806     NSData *postData = nil;
1807
1808     if (file) {
1809         // If we're posting a file, buf is either a file URL or a path to the file.
1810         NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1);
1811         if (!bufString) {
1812             return NPERR_INVALID_PARAM;
1813         }
1814         NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString];
1815         NSString *path;
1816         if ([fileURL isFileURL]) {
1817             path = [fileURL path];
1818         } else {
1819             path = bufString;
1820         }
1821         postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
1822         CFRelease(bufString);
1823         if (!postData) {
1824             return NPERR_FILE_NOT_FOUND;
1825         }
1826     } else {
1827         postData = [NSData dataWithBytes:buf length:len];
1828     }
1829
1830     if ([postData length] == 0) {
1831         return NPERR_INVALID_PARAM;
1832     }
1833
1834     NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1835     [request setHTTPMethod:@"POST"];
1836     
1837     if (allowHeaders) {
1838         if ([postData _web_startsWithBlankLine]) {
1839             postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)];
1840         } else {
1841             NSInteger location = [postData _web_locationAfterFirstBlankLine];
1842             if (location != NSNotFound) {
1843                 // If the blank line is somewhere in the middle of postData, everything before is the header.
1844                 NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)];
1845                 NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
1846                 unsigned dataLength = [postData length] - location;
1847
1848                 // Sometimes plugins like to set Content-Length themselves when they post,
1849                 // but WebFoundation does not like that. So we will remove the header
1850                 // and instead truncate the data to the requested length.
1851                 NSString *contentLength = [header objectForKey:@"Content-Length"];
1852
1853                 if (contentLength != nil)
1854                     dataLength = min<unsigned>([contentLength intValue], dataLength);
1855                 [header removeObjectForKey:@"Content-Length"];
1856
1857                 if ([header count] > 0) {
1858                     [request setAllHTTPHeaderFields:header];
1859                 }
1860                 // Everything after the blank line is the actual content of the POST.
1861                 postData = [postData subdataWithRange:NSMakeRange(location, dataLength)];
1862
1863             }
1864         }
1865         if ([postData length] == 0) {
1866             return NPERR_INVALID_PARAM;
1867         }
1868     }
1869
1870     // Plug-ins expect to receive uncached data when doing a POST (3347134).
1871     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1872     [request setHTTPBody:postData];
1873     
1874     return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification];
1875 }
1876
1877 - (NPError)postURLNotify:(const char *)URLCString
1878                   target:(const char *)target
1879                      len:(UInt32)len
1880                      buf:(const char *)buf
1881                     file:(NPBool)file
1882               notifyData:(void *)notifyData
1883 {
1884     LOG(Plugins, "NPN_PostURLNotify: %s", URLCString);
1885     return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES];
1886 }
1887
1888 -(NPError)postURL:(const char *)URLCString
1889            target:(const char *)target
1890               len:(UInt32)len
1891               buf:(const char *)buf
1892              file:(NPBool)file
1893 {
1894     LOG(Plugins, "NPN_PostURL: %s", URLCString);        
1895     // As documented, only allow headers to be specified via NPP_PostURL when using a file.
1896     return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file];
1897 }
1898
1899 -(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream
1900 {
1901     LOG(Plugins, "NPN_NewStream");
1902     return NPERR_GENERIC_ERROR;
1903 }
1904
1905 -(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer
1906 {
1907     LOG(Plugins, "NPN_Write");
1908     return NPERR_GENERIC_ERROR;
1909 }
1910
1911 -(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason
1912 {
1913     LOG(Plugins, "NPN_DestroyStream");
1914     // This function does a sanity check to ensure that the NPStream provided actually
1915     // belongs to the plug-in that provided it, which fixes a crash in the DivX 
1916     // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203
1917     if (!stream || WebNetscapePluginStream::ownerForStream(stream) != plugin) {
1918         LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream);
1919         return NPERR_INVALID_INSTANCE_ERROR;
1920     }
1921     
1922     WebNetscapePluginStream* browserStream = static_cast<WebNetscapePluginStream*>(stream->ndata);
1923     browserStream->cancelLoadAndDestroyStreamWithError(browserStream->errorForReason(reason));
1924     
1925     return NPERR_NO_ERROR;
1926 }
1927
1928 - (const char *)userAgent
1929 {
1930     NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()];
1931     
1932     if (_isSilverlight) {
1933         // Silverlight has a workaround for a leak in Safari 2. This workaround is 
1934         // applied when the user agent does not contain "Version/3" so we append it
1935         // at the end of the user agent.
1936         userAgent = [userAgent stringByAppendingString:@" Version/3.2.1"];
1937     }        
1938         
1939     return [userAgent UTF8String];
1940 }
1941
1942 -(void)status:(const char *)message
1943 {    
1944     CFStringRef status = CFStringCreateWithCString(NULL, message ? message : "", kCFStringEncodingUTF8);
1945     if (!status) {
1946         LOG_ERROR("NPN_Status: the message was not valid UTF-8");
1947         return;
1948     }
1949     
1950     LOG(Plugins, "NPN_Status: %@", status);
1951     WebView *wv = [self webView];
1952     [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status];
1953     CFRelease(status);
1954 }
1955
1956 -(void)invalidateRect:(NPRect *)invalidRect
1957 {
1958     LOG(Plugins, "NPN_InvalidateRect");
1959     [self invalidatePluginContentRect:NSMakeRect(invalidRect->left, invalidRect->top,
1960         (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)];
1961 }
1962
1963 - (void)invalidateRegion:(NPRegion)invalidRegion
1964 {
1965     LOG(Plugins, "NPN_InvalidateRegion");
1966     NSRect invalidRect = NSZeroRect;
1967     switch (drawingModel) {
1968 #ifndef NP_NO_QUICKDRAW
1969         case NPDrawingModelQuickDraw:
1970         {
1971             ::Rect qdRect;
1972             GetRegionBounds((NPQDRegion)invalidRegion, &qdRect);
1973             invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top);
1974         }
1975         break;
1976 #endif /* NP_NO_QUICKDRAW */
1977         
1978         case NPDrawingModelCoreGraphics:
1979         {
1980             CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion);
1981             invalidRect = *(NSRect*)&cgRect;
1982             break;
1983         }
1984         default:
1985             ASSERT_NOT_REACHED();
1986         break;
1987     }
1988     
1989     [self invalidatePluginContentRect:invalidRect];
1990 }
1991
1992 -(void)forceRedraw
1993 {
1994     LOG(Plugins, "forceRedraw");
1995     [self invalidatePluginContentRect:[self bounds]];
1996     [[self window] displayIfNeeded];
1997 }
1998
1999 - (NPError)getVariable:(NPNVariable)variable value:(void *)value
2000 {
2001     switch (static_cast<unsigned>(variable)) {
2002         case NPNVWindowNPObject:
2003         {
2004             Frame* frame = core([self webFrame]);
2005             NPObject* windowScriptObject = frame ? frame->script()->windowScriptNPObject() : 0;
2006
2007             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
2008             if (windowScriptObject)
2009                 _NPN_RetainObject(windowScriptObject);
2010             
2011             void **v = (void **)value;
2012             *v = windowScriptObject;
2013
2014             return NPERR_NO_ERROR;
2015         }
2016
2017         case NPNVPluginElementNPObject:
2018         {
2019             if (!_element)
2020                 return NPERR_GENERIC_ERROR;
2021             
2022             NPObject *plugInScriptObject = _element->getNPObject();
2023
2024             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
2025             if (plugInScriptObject)
2026                 _NPN_RetainObject(plugInScriptObject);
2027
2028             void **v = (void **)value;
2029             *v = plugInScriptObject;
2030
2031             return NPERR_NO_ERROR;
2032         }
2033         
2034         case NPNVpluginDrawingModel:
2035         {
2036             *(NPDrawingModel *)value = drawingModel;
2037             return NPERR_NO_ERROR;
2038         }
2039
2040 #ifndef NP_NO_QUICKDRAW
2041         case NPNVsupportsQuickDrawBool:
2042         {
2043             *(NPBool *)value = TRUE;
2044             return NPERR_NO_ERROR;
2045         }
2046 #endif /* NP_NO_QUICKDRAW */
2047         
2048         case NPNVsupportsCoreGraphicsBool:
2049         {
2050             *(NPBool *)value = TRUE;
2051             return NPERR_NO_ERROR;
2052         }
2053
2054         case NPNVsupportsOpenGLBool:
2055         {
2056             *(NPBool *)value = FALSE;
2057             return NPERR_NO_ERROR;
2058         }
2059         
2060         case NPNVsupportsCoreAnimationBool:
2061         {
2062             *(NPBool *)value = TRUE;
2063             return NPERR_NO_ERROR;
2064         }
2065             
2066 #ifndef NP_NO_CARBON
2067         case NPNVsupportsCarbonBool:
2068         {
2069             *(NPBool *)value = TRUE;
2070             return NPERR_NO_ERROR;
2071         }
2072 #endif /* NP_NO_CARBON */
2073
2074         case NPNVsupportsCocoaBool:
2075         {
2076             *(NPBool *)value = TRUE;
2077             return NPERR_NO_ERROR;
2078         }
2079
2080         case NPNVprivateModeBool:
2081         {
2082             *(NPBool *)value = _isPrivateBrowsingEnabled;
2083             return NPERR_NO_ERROR;
2084         }
2085
2086         case WKNVBrowserContainerCheckFuncs:
2087         {
2088             *(WKNBrowserContainerCheckFuncs **)value = browserContainerCheckFuncs();
2089             return NPERR_NO_ERROR;
2090         }
2091 #if USE(ACCELERATED_COMPOSITING)
2092         case WKNVSupportsCompositingCoreAnimationPluginsBool:
2093         {
2094             *(NPBool *)value = [[[self webView] preferences] acceleratedCompositingEnabled];
2095             return NPERR_NO_ERROR;
2096         }
2097 #endif
2098         default:
2099             break;
2100     }
2101
2102     return NPERR_GENERIC_ERROR;
2103 }
2104
2105 - (NPError)setVariable:(NPPVariable)variable value:(void *)value
2106 {
2107     switch (variable) {
2108         case NPPVpluginDrawingModel:
2109         {
2110             // Can only set drawing model inside NPP_New()
2111             if (self != [[self class] currentPluginView])
2112                 return NPERR_GENERIC_ERROR;
2113             
2114             // Check for valid, supported drawing model
2115             NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value;
2116             switch (newDrawingModel) {
2117                 // Supported drawing models:
2118 #ifndef NP_NO_QUICKDRAW
2119                 case NPDrawingModelQuickDraw:
2120 #endif
2121                 case NPDrawingModelCoreGraphics:
2122                 case NPDrawingModelCoreAnimation:
2123                     drawingModel = newDrawingModel;
2124                     return NPERR_NO_ERROR;
2125                     
2126
2127                 // Unsupported (or unknown) drawing models:
2128                 default:
2129                     LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", _eventHandler.get(), drawingModel);
2130                     return NPERR_GENERIC_ERROR;
2131             }
2132         }
2133         
2134         case NPPVpluginEventModel:
2135         {
2136             // Can only set event model inside NPP_New()
2137             if (self != [[self class] currentPluginView])
2138                 return NPERR_GENERIC_ERROR;
2139             
2140             // Check for valid, supported event model
2141             NPEventModel newEventModel = (NPEventModel)(uintptr_t)value;
2142             switch (newEventModel) {
2143                 // Supported event models:
2144 #ifndef NP_NO_CARBON
2145                 case NPEventModelCarbon:
2146 #endif
2147                 case NPEventModelCocoa:
2148                     eventModel = newEventModel;
2149                     return NPERR_NO_ERROR;
2150                     
2151                     // Unsupported (or unknown) event models:
2152                 default:
2153                     LOG(Plugins, "Plugin %@ uses unsupported event model: %d", _eventHandler.get(), eventModel);
2154                     return NPERR_GENERIC_ERROR;
2155             }
2156         }
2157             
2158         default:
2159             return NPERR_GENERIC_ERROR;
2160     }
2161 }
2162
2163 - (uint32_t)scheduleTimerWithInterval:(uint32_t)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32_t timerID))timerFunc
2164 {
2165     if (!timerFunc)
2166         return 0;
2167     
2168     if (!timers)
2169         timers = new HashMap<uint32_t, PluginTimer*>;
2170     
2171     uint32_t timerID;
2172     
2173     do {
2174         timerID = ++currentTimerID;
2175     } while (timers->contains(timerID) || timerID == 0);
2176     
2177     PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc);
2178     timers->set(timerID, timer);
2179
2180     if (_shouldFireTimers)
2181         timer->start(_isCompletelyObscured);
2182     
2183     return timerID;
2184 }
2185
2186 - (void)unscheduleTimer:(uint32_t)timerID
2187 {
2188     if (!timers)
2189         return;
2190     
2191     if (PluginTimer* timer = timers->take(timerID))
2192         delete timer;
2193 }
2194
2195 - (NPError)popUpContextMenu:(NPMenu *)menu
2196 {
2197     NSEvent *currentEvent = [NSApp currentEvent];
2198     
2199     // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent.
2200     if (!currentEvent)
2201         return NPERR_GENERIC_ERROR;
2202     
2203     [NSMenu popUpContextMenu:(NSMenu *)menu withEvent:currentEvent forView:self];
2204     return NPERR_NO_ERROR;
2205 }
2206
2207 - (NPError)getVariable:(NPNURLVariable)variable forURL:(const char*)url value:(char**)value length:(uint32_t*)length
2208 {
2209     switch (variable) {
2210         case NPNURLVCookie: {
2211             if (!value)
2212                 break;
2213             
2214             NSURL *URL = [self URLWithCString:url];
2215             if (!URL)
2216                 break;
2217             
2218             if (Frame* frame = core([self webFrame])) {
2219                 String cookieString = cookies(frame->document(), URL); 
2220                 CString cookieStringUTF8 = cookieString.utf8();
2221                 if (cookieStringUTF8.isNull())
2222                     return NPERR_GENERIC_ERROR;
2223
2224                 *value = static_cast<char*>(NPN_MemAlloc(cookieStringUTF8.length()));
2225                 memcpy(*value, cookieStringUTF8.data(), cookieStringUTF8.length());
2226                 
2227                 if (length)
2228                     *length = cookieStringUTF8.length();
2229                 return NPERR_NO_ERROR;
2230             }
2231             break;
2232         }
2233         case NPNURLVProxy: {
2234             if (!value)
2235                 break;
2236             
2237             NSURL *URL = [self URLWithCString:url];
2238             if (!URL)
2239                 break;
2240
2241             Vector<ProxyServer> proxyServers = proxyServersForURL(URL, 0);
2242             CString proxiesUTF8 = toString(proxyServers).utf8();
2243             
2244             *value = static_cast<char*>(NPN_MemAlloc(proxiesUTF8.length()));
2245             memcpy(*value, proxiesUTF8.data(), proxiesUTF8.length());
2246             
2247            if (length)
2248                *length = proxiesUTF8.length();
2249             
2250             return NPERR_NO_ERROR;
2251         }
2252     }
2253     return NPERR_GENERIC_ERROR;
2254 }
2255
2256 - (NPError)setVariable:(NPNURLVariable)variable forURL:(const char*)url value:(const char*)value length:(uint32_t)length
2257 {
2258     switch (variable) {
2259         case NPNURLVCookie: {
2260             NSURL *URL = [self URLWithCString:url];
2261             if (!URL)
2262                 break;
2263             
2264             String cookieString = String::fromUTF8(value, length);
2265             if (!cookieString)
2266                 break;
2267             
2268             if (Frame* frame = core([self webFrame])) {
2269                 setCookies(frame->document(), URL, cookieString);
2270                 return NPERR_NO_ERROR;
2271             }
2272             
2273             break;
2274         }
2275         case NPNURLVProxy:
2276             // Can't set the proxy for a URL.
2277             break;
2278     }
2279     return NPERR_GENERIC_ERROR;
2280 }
2281
2282 - (NPError)getAuthenticationInfoWithProtocol:(const char*)protocolStr host:(const char*)hostStr port:(int32_t)port scheme:(const char*)schemeStr realm:(const char*)realmStr
2283                                     username:(char**)usernameStr usernameLength:(uint32_t*)usernameLength 
2284                                     password:(char**)passwordStr passwordLength:(uint32_t*)passwordLength
2285 {
2286     if (!protocolStr || !hostStr || !schemeStr || !realmStr || !usernameStr || !usernameLength || !passwordStr || !passwordLength)
2287         return NPERR_GENERIC_ERROR;
2288   
2289     CString username;
2290     CString password;
2291     if (!getAuthenticationInfo(protocolStr, hostStr, port, schemeStr, realmStr, username, password))
2292         return NPERR_GENERIC_ERROR;
2293     
2294     *usernameLength = username.length();
2295     *usernameStr = static_cast<char*>(NPN_MemAlloc(username.length()));
2296     memcpy(*usernameStr, username.data(), username.length());
2297     
2298     *passwordLength = password.length();
2299     *passwordStr = static_cast<char*>(NPN_MemAlloc(password.length()));
2300     memcpy(*passwordStr, password.data(), password.length());
2301     
2302     return NPERR_NO_ERROR;
2303 }
2304
2305 - (char*)resolveURL:(const char*)url forTarget:(const char*)target
2306 {
2307     CString location = [self resolvedURLStringForURL:url target:target];
2308
2309     if (location.isNull())
2310         return 0;
2311     
2312     // We use strdup here because the caller needs to free it with NPN_MemFree (which calls free).
2313     return strdup(location.data());
2314 }
2315
2316 @end
2317
2318 @implementation WebNetscapePluginView (Internal)
2319
2320 - (BOOL)_shouldCancelSrcStream
2321 {
2322     ASSERT(_isStarted);
2323     
2324     // Check if we should cancel the load
2325     NPBool cancelSrcStream = 0;
2326     if ([_pluginPackage.get() pluginFuncs]->getvalue &&
2327         [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCancelSrcStream, &cancelSrcStream) == NPERR_NO_ERROR && cancelSrcStream)
2328         return YES;
2329     
2330     return NO;
2331 }
2332
2333 // Work around Silverlight full screen performance issue by maintaining an accelerated GL pixel format.
2334 // We can safely remove it at some point in the future when both:
2335 // 1) Microsoft releases a genuine fix for 7288546.
2336 // 2) Enough Silverlight users update to the new Silverlight.
2337 // For now, we'll distinguish older broken versions of Silverlight by asking the plug-in if it resolved its full screen badness.
2338 - (void)_workaroundSilverlightFullscreenBug:(BOOL)initializedPlugin
2339 {
2340     ASSERT(_isSilverlight);
2341     NPBool isFullscreenPerformanceIssueFixed = 0;
2342     NPPluginFuncs *pluginFuncs = [_pluginPackage.get() pluginFuncs];
2343     if (pluginFuncs->getvalue && pluginFuncs->getvalue(plugin, static_cast<NPPVariable>(WKNVSilverlightFullscreenPerformanceIssueFixed), &isFullscreenPerformanceIssueFixed) == NPERR_NO_ERROR && isFullscreenPerformanceIssueFixed)
2344         return;
2345     
2346     static CGLPixelFormatObj pixelFormatObject = 0;
2347     static unsigned refCount = 0;
2348     
2349     if (initializedPlugin) {
2350         refCount++;
2351         if (refCount == 1) {
2352             const CGLPixelFormatAttribute attributes[] = { kCGLPFAAccelerated, static_cast<CGLPixelFormatAttribute>(0) };
2353             GLint npix;
2354             CGLChoosePixelFormat(attributes, &pixelFormatObject, &npix);
2355         }  
2356     } else {
2357         ASSERT(pixelFormatObject);
2358         refCount--;
2359         if (!refCount) 
2360             CGLReleasePixelFormat(pixelFormatObject);
2361     }
2362 }
2363
2364 - (NPError)_createPlugin
2365 {
2366     plugin = (NPP)calloc(1, sizeof(NPP_t));
2367     plugin->ndata = self;
2368
2369     ASSERT([_pluginPackage.get() pluginFuncs]->newp);
2370
2371     // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance.
2372     ASSERT(pluginFunctionCallDepth == 0);
2373
2374     PluginMainThreadScheduler::scheduler().registerPlugin(plugin);
2375
2376     _isFlash = [_pluginPackage.get() bundleIdentifier] == "com.macromedia.Flash Player.plugin";
2377     _isSilverlight = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.SilverlightPlugin";
2378
2379     [[self class] setCurrentPluginView:self];
2380     NPError npErr = [_pluginPackage.get() pluginFuncs]->newp((char *)[_MIMEType.get() cString], plugin, _mode, argsCount, cAttributes, cValues, NULL);
2381     [[self class] setCurrentPluginView:nil];
2382     if (_isSilverlight)
2383         [self _workaroundSilverlightFullscreenBug:YES];
2384     LOG(Plugins, "NPP_New: %d", npErr);
2385     return npErr;
2386 }
2387
2388 - (void)_destroyPlugin
2389 {
2390     PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin);
2391     
2392     if (_isSilverlight)
2393         [self _workaroundSilverlightFullscreenBug:NO];
2394     
2395     NPError npErr;
2396     npErr = ![_pluginPackage.get() pluginFuncs]->destroy(plugin, NULL);
2397     LOG(Plugins, "NPP_Destroy: %d", npErr);
2398     
2399     if (Frame* frame = core([self webFrame]))
2400         frame->script()->cleanupScriptObjectsForPlugin(self);
2401         
2402     free(plugin);
2403     plugin = NULL;
2404 }
2405
2406 - (NSBitmapImageRep *)_printedPluginBitmap
2407 {
2408 #ifdef NP_NO_QUICKDRAW
2409     return nil;
2410 #else
2411     // Cannot print plugins that do not implement NPP_Print
2412     if (![_pluginPackage.get() pluginFuncs]->print)
2413         return nil;
2414
2415     // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into.
2416     // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format.
2417     NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
2418                                                          pixelsWide:window.width
2419                                                          pixelsHigh:window.height
2420                                                          bitsPerSample:8
2421                                                          samplesPerPixel:4
2422                                                          hasAlpha:YES
2423                                                          isPlanar:NO
2424                                                          colorSpaceName:NSDeviceRGBColorSpace
2425                                                          bitmapFormat:NSAlphaFirstBitmapFormat
2426                                                          bytesPerRow:0
2427                                                          bitsPerPixel:0] autorelease];
2428     ASSERT(bitmap);
2429     
2430     // Create a GWorld with the same underlying buffer into which the plugin can draw
2431     ::Rect printGWorldBounds;
2432     SetRect(&printGWorldBounds, 0, 0, window.width, window.height);
2433     GWorldPtr printGWorld;
2434     if (NewGWorldFromPtr(&printGWorld,
2435                          k32ARGBPixelFormat,
2436                          &printGWorldBounds,
2437                          NULL,
2438                          NULL,
2439                          0,
2440                          (Ptr)[bitmap bitmapData],
2441                          [bitmap bytesPerRow]) != noErr) {
2442         LOG_ERROR("Could not create GWorld for printing");
2443         return nil;
2444     }
2445     
2446     /// Create NPWindow for the GWorld
2447     NPWindow printNPWindow;
2448     printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr
2449     printNPWindow.x = 0;
2450     printNPWindow.y = 0;
2451     printNPWindow.width = window.width;
2452     printNPWindow.height = window.height;
2453     printNPWindow.clipRect.top = 0;
2454     printNPWindow.clipRect.left = 0;
2455     printNPWindow.clipRect.right = window.width;
2456     printNPWindow.clipRect.bottom = window.height;
2457     printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window
2458     
2459     // Create embed-mode NPPrint
2460     NPPrint npPrint;
2461     npPrint.mode = NP_EMBED;
2462     npPrint.print.embedPrint.window = printNPWindow;
2463     npPrint.print.embedPrint.platformPrint = printGWorld;
2464     
2465     // Tell the plugin to print into the GWorld
2466     [self willCallPlugInFunction];
2467     {
2468         JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
2469         [_pluginPackage.get() pluginFuncs]->print(plugin, &npPrint);
2470     }
2471     [self didCallPlugInFunction];
2472
2473     // Don't need the GWorld anymore
2474     DisposeGWorld(printGWorld);
2475         
2476     return bitmap;
2477 #endif
2478 }
2479
2480 - (void)_redeliverStream
2481 {
2482     if ([self dataSource] && _isStarted) {
2483         // Deliver what has not been passed to the plug-in up to this point.
2484         if (_dataLengthReceived > 0) {
2485             NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)];
2486             _dataLengthReceived = 0;
2487             [self pluginView:self receivedData:data];
2488             if (![[self dataSource] isLoading]) {
2489                 if (_error)
2490                     [self pluginView:self receivedError:_error.get()];
2491                 else
2492                     [self pluginViewFinishedLoading:self];
2493             }
2494         }
2495     }
2496 }
2497
2498 @end
2499
2500 #endif