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