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