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