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