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