2 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #if ENABLE(NETSCAPE_PLUGIN_API)
31 #import "WebNetscapePluginView.h"
33 #import "QuickDrawCompatibility.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebDefaultUIDelegate.h"
36 #import "WebFrameInternal.h"
37 #import "WebFrameView.h"
38 #import "WebKitErrorsPrivate.h"
39 #import "WebKitLogging.h"
40 #import "WebKitNSStringExtras.h"
41 #import "WebKitSystemInterface.h"
42 #import "WebNSDataExtras.h"
43 #import "WebNSDictionaryExtras.h"
44 #import "WebNSObjectExtras.h"
45 #import "WebNSURLExtras.h"
46 #import "WebNSURLRequestExtras.h"
47 #import "WebNSViewExtras.h"
48 #import "WebNetscapeContainerCheckContextInfo.h"
49 #import "WebNetscapeContainerCheckPrivate.h"
50 #import "WebNetscapePluginEventHandler.h"
51 #import "WebNetscapePluginPackage.h"
52 #import "WebNetscapePluginStream.h"
53 #import "WebPluginContainerCheck.h"
54 #import "WebPluginRequest.h"
55 #import "WebPreferences.h"
56 #import "WebUIDelegatePrivate.h"
57 #import "WebViewInternal.h"
58 #import <Carbon/Carbon.h>
59 #import <WebCore/CookieJar.h>
60 #import <WebCore/DocumentLoader.h>
61 #import <WebCore/Element.h>
62 #import <WebCore/Frame.h>
63 #import <WebCore/FrameLoader.h>
64 #import <WebCore/FrameTree.h>
65 #import <WebCore/FrameView.h>
66 #import <WebCore/HTMLPlugInElement.h>
67 #import <WebCore/Page.h>
68 #import <WebCore/PluginMainThreadScheduler.h>
69 #import <WebCore/ProxyServer.h>
70 #import <WebCore/ScriptController.h>
71 #import <WebCore/SecurityOrigin.h>
72 #import <WebCore/SoftLinking.h>
73 #import <WebCore/UserGestureIndicator.h>
74 #import <WebCore/WebCoreObjCExtras.h>
75 #import <WebCore/WebCoreURLResponse.h>
76 #import <WebCore/npruntime_impl.h>
77 #import <WebKit/DOMPrivate.h>
78 #import <WebKit/WebUIDelegate.h>
79 #import <objc/objc-runtime.h>
80 #import <runtime/InitializeThreading.h>
81 #import <runtime/JSLock.h>
82 #import <wtf/Assertions.h>
83 #import <wtf/MainThread.h>
84 #import <wtf/text/CString.h>
86 #define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification"
87 #define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification"
88 #define WKNVSupportsCompositingCoreAnimationPluginsBool 74656 /* TRUE if the browser supports hardware compositing of Core Animation plug-ins */
89 static const int WKNVSilverlightFullscreenPerformanceIssueFixed = 7288546; /* TRUE if Siverlight addressed its underlying bug in <rdar://problem/7288546> */
91 using namespace WebCore;
92 using namespace WebKit;
95 static inline bool isDrawingModelQuickDraw(NPDrawingModel drawingModel)
97 #ifndef NP_NO_QUICKDRAW
98 return drawingModel == NPDrawingModelQuickDraw;
104 @interface WebNetscapePluginView (Internal)
105 - (NPError)_createPlugin;
106 - (void)_destroyPlugin;
107 - (NSBitmapImageRep *)_printedPluginBitmap;
108 - (void)_redeliverStream;
109 - (BOOL)_shouldCancelSrcStream;
112 static WebNetscapePluginView *currentPluginView = nil;
114 typedef struct OpaquePortState* PortState;
116 static const double ThrottledTimerInterval = 0.25;
118 class PluginTimer : public TimerBase {
120 typedef void (*TimerFunc)(NPP npp, uint32_t timerID);
122 PluginTimer(NPP npp, uint32_t timerID, uint32_t interval, NPBool repeat, TimerFunc timerFunc)
125 , m_interval(interval)
127 , m_timerFunc(timerFunc)
131 void start(bool throttle)
135 double timeInterval = m_interval / 1000.0;
138 timeInterval = max(timeInterval, ThrottledTimerInterval);
141 startRepeating(timeInterval);
143 startOneShot(timeInterval);
149 m_timerFunc(m_npp, m_timerID);
158 TimerFunc m_timerFunc;
161 #ifndef NP_NO_QUICKDRAW
163 // QuickDraw is not available in 64-bit
169 RgnHandle oldClipRegion;
170 RgnHandle oldVisibleRegion;
171 RgnHandle clipRegion;
175 #endif /* NP_NO_QUICKDRAW */
178 CGContextRef context;
181 @class NSTextInputContext;
182 @interface NSResponder (AppKitDetails)
183 - (NSTextInputContext *)inputContext;
186 @interface WebNetscapePluginView (ForwardDeclarations)
187 - (void)setWindowIfNecessary;
188 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification;
191 @implementation WebNetscapePluginView
195 JSC::initializeThreading();
196 WTF::initializeMainThreadToProcessMainThread();
197 WebCoreObjCFinalizeOnMainThread(self);
198 WKSendUserChangeNotifications();
203 // The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers
204 // the entire window frame (or structure region to use the Carbon term) rather then just the window content.
205 // We can remove this when <rdar://problem/4201099> is fixed.
206 - (void)fixWindowPort
208 #ifndef NP_NO_QUICKDRAW
209 ASSERT(isDrawingModelQuickDraw(drawingModel));
211 NSWindow *currentWindow = [self currentWindow];
212 if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")])
215 float windowHeight = [currentWindow frame].size.height;
216 NSView *contentView = [currentWindow contentView];
217 NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates
221 SetPort(GetWindowPort((WindowRef)[currentWindow windowRef]));
223 MovePortTo(static_cast<short>(contentRect.origin.x), /* Flip Y */ static_cast<short>(windowHeight - NSMaxY(contentRect)));
224 PortSize(static_cast<short>(contentRect.size.width), static_cast<short>(contentRect.size.height));
230 #ifndef NP_NO_QUICKDRAW
231 static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context)
233 UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) & kCGBitmapByteOrderMask;
234 if (byteOrder == kCGBitmapByteOrderDefault)
235 switch (CGBitmapContextGetBitsPerPixel(context)) {
237 byteOrder = kCGBitmapByteOrder16Host;
240 byteOrder = kCGBitmapByteOrder32Host;
244 case kCGBitmapByteOrder16Little:
245 return k16LE555PixelFormat;
246 case kCGBitmapByteOrder32Little:
247 return k32BGRAPixelFormat;
248 case kCGBitmapByteOrder16Big:
249 return k16BE555PixelFormat;
250 case kCGBitmapByteOrder32Big:
251 return k32ARGBPixelFormat;
253 ASSERT_NOT_REACHED();
257 static inline void getNPRect(const CGRect& cgr, NPRect& npr)
259 npr.top = static_cast<uint16_t>(cgr.origin.y);
260 npr.left = static_cast<uint16_t>(cgr.origin.x);
261 npr.bottom = static_cast<uint16_t>(CGRectGetMaxY(cgr));
262 npr.right = static_cast<uint16_t>(CGRectGetMaxX(cgr));
267 static inline void getNPRect(const NSRect& nr, NPRect& npr)
269 npr.top = static_cast<uint16_t>(nr.origin.y);
270 npr.left = static_cast<uint16_t>(nr.origin.x);
271 npr.bottom = static_cast<uint16_t>(NSMaxY(nr));
272 npr.right = static_cast<uint16_t>(NSMaxX(nr));
275 - (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate
277 ASSERT([self currentWindow] != nil);
279 // The base coordinates of a window and it's contentView happen to be the equal at a userSpaceScaleFactor
280 // of 1. For non-1.0 scale factors this assumption is false.
281 NSView *windowContentView = [[self window] contentView];
282 NSRect boundsInWindow = [self convertRect:[self bounds] toView:windowContentView];
283 NSRect visibleRectInWindow = [self actualVisibleRectInWindow];
285 // Flip Y to convert -[NSWindow contentView] coordinates to top-left-based window coordinates.
286 float borderViewHeight = [[self currentWindow] frame].size.height;
287 boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow);
288 visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow);
290 #ifndef NP_NO_QUICKDRAW
291 WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
294 // Look at the Carbon port to convert top-left-based window coordinates into top-left-based content coordinates.
295 if (isDrawingModelQuickDraw(drawingModel)) {
296 // If drawing with QuickDraw, fix the window port so that it has the same bounds as the NSWindow's
297 // content view. This makes it easier to convert between AppKit view and QuickDraw port coordinates.
298 [self fixWindowPort];
301 CGrafPtr port = GetWindowPort(windowRef);
302 GetPortBounds(port, &portBounds);
304 PixMap *pix = *GetPortPixMap(port);
305 boundsInWindow.origin.x += pix->bounds.left - portBounds.left;
306 boundsInWindow.origin.y += pix->bounds.top - portBounds.top;
307 visibleRectInWindow.origin.x += pix->bounds.left - portBounds.left;
308 visibleRectInWindow.origin.y += pix->bounds.top - portBounds.top;
312 window.type = NPWindowTypeWindow;
313 window.x = (int32_t)boundsInWindow.origin.x;
314 window.y = (int32_t)boundsInWindow.origin.y;
315 window.width = static_cast<uint32_t>(NSWidth(boundsInWindow));
316 window.height = static_cast<uint32_t>(NSHeight(boundsInWindow));
318 // "Clip-out" the plug-in when:
319 // 1) it's not really in a window or off-screen or has no height or width.
320 // 2) window.x is a "big negative number" which is how WebCore expresses off-screen widgets.
321 // 3) the window is miniaturized or the app is hidden
322 // 4) we're inside of viewWillMoveToWindow: with a nil window. In this case, superviews may already have nil
323 // superviews and nil windows and results from convertRect:toView: are incorrect.
324 if (window.width <= 0 || window.height <= 0 || window.x < -100000 || [self shouldClipOutPlugin]) {
326 // The following code tries to give plug-ins the same size they will eventually have.
327 // The specifiedWidth and specifiedHeight variables are used to predict the size that
328 // WebCore will eventually resize us to.
330 // The QuickTime plug-in has problems if you give it a width or height of 0.
331 // Since other plug-ins also might have the same sort of trouble, we make sure
332 // to always give plug-ins a size other than 0,0.
334 if (window.width <= 0)
335 window.width = specifiedWidth > 0 ? specifiedWidth : 100;
336 if (window.height <= 0)
337 window.height = specifiedHeight > 0 ? specifiedHeight : 100;
339 window.clipRect.bottom = window.clipRect.top;
340 window.clipRect.left = window.clipRect.right;
342 // Core Animation plug-ins need to be updated (with a 0,0,0,0 clipRect) when
343 // moved to a background tab. We don't do this for Core Graphics plug-ins as
344 // older versions of Flash have historical WebKit-specific code that isn't
345 // compatible with this behavior.
346 if (drawingModel == NPDrawingModelCoreAnimation)
347 getNPRect(NSZeroRect, window.clipRect);
349 getNPRect(visibleRectInWindow, window.clipRect);
352 // Save the port state, set up the port for entry into the plugin
354 switch (drawingModel) {
355 #ifndef NP_NO_QUICKDRAW
356 case NPDrawingModelQuickDraw: {
359 CGrafPtr port = GetWindowPort(windowRef);
360 GetPortBounds(port, &portBounds);
361 nPort.qdPort.port = port;
362 nPort.qdPort.portx = (int32_t)-boundsInWindow.origin.x;
363 nPort.qdPort.porty = (int32_t)-boundsInWindow.origin.y;
364 window.window = &nPort;
366 PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD));
367 portState = (PortState)qdPortState;
369 GetGWorld(&qdPortState->oldPort, &qdPortState->oldDevice);
371 qdPortState->oldOrigin.h = portBounds.left;
372 qdPortState->oldOrigin.v = portBounds.top;
374 qdPortState->oldClipRegion = NewRgn();
375 GetPortClipRegion(port, qdPortState->oldClipRegion);
377 qdPortState->oldVisibleRegion = NewRgn();
378 GetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
380 RgnHandle clipRegion = NewRgn();
381 qdPortState->clipRegion = clipRegion;
383 CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
384 if (currentContext && WKCGContextIsBitmapContext(currentContext)) {
385 // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData
386 // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext
387 // returns true, it still might not be a context we need to create a GWorld for; for example
388 // transparency layers will return true, but return 0 for CGBitmapContextGetData.
389 void* offscreenData = CGBitmapContextGetData(currentContext);
391 // If the current context is an offscreen bitmap, then create a GWorld for it.
392 ::Rect offscreenBounds;
393 offscreenBounds.top = 0;
394 offscreenBounds.left = 0;
395 offscreenBounds.right = CGBitmapContextGetWidth(currentContext);
396 offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext);
397 GWorldPtr newOffscreenGWorld;
398 QDErr err = NewGWorldFromPtr(&newOffscreenGWorld,
399 getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0,
400 static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext));
401 ASSERT(newOffscreenGWorld);
405 DisposeGWorld(offscreenGWorld);
406 offscreenGWorld = newOffscreenGWorld;
408 SetGWorld(offscreenGWorld, NULL);
410 port = offscreenGWorld;
412 nPort.qdPort.port = port;
413 boundsInWindow = [self bounds];
415 // Generate a QD origin based on the current affine transform for currentContext.
416 CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext);
417 CGPoint origin = {0,0};
418 CGPoint axisFlip = {1,1};
419 origin = CGPointApplyAffineTransform(origin, offscreenMatrix);
420 axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix);
422 // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that.
423 origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x);
424 origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y);
426 nPort.qdPort.portx = static_cast<int32_t>(-boundsInWindow.origin.x + origin.x);
427 nPort.qdPort.porty = static_cast<int32_t>(-boundsInWindow.origin.y - origin.y);
430 window.window = &nPort;
432 // Use the clip bounds from the context instead of the bounds we created
433 // from the window above.
434 getNPRect(CGRectOffset(CGContextGetClipBoundingBox(currentContext), -origin.x, origin.y), window.clipRect);
439 MacSetRectRgn(clipRegion,
440 window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty,
441 window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty);
443 // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
444 if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
445 // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are
446 // not going to be redrawn this update. This forces plug-ins to play nice with z-index ordering.
448 RgnHandle viewClipRegion = NewRgn();
450 // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
451 // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
452 // knows about the true set of dirty rects.
453 NSView *opaqueAncestor = [self opaqueAncestor];
454 const NSRect *dirtyRects;
455 NSInteger dirtyRectCount, dirtyRectIndex;
456 [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
458 for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) {
459 NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor];
460 if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) {
461 // Create a region for this dirty rect
462 RgnHandle dirtyRectRegion = NewRgn();
463 SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect)));
465 // Union this dirty rect with the rest of the dirty rects
466 UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion);
467 DisposeRgn(dirtyRectRegion);
471 // Intersect the dirty region with the clip region, so that we only draw over dirty parts
472 SectRgn(clipRegion, viewClipRegion, clipRegion);
473 DisposeRgn(viewClipRegion);
477 // Switch to the port and set it up.
480 ForeColor(blackColor);
481 BackColor(whiteColor);
482 SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty);
483 SetPortClipRegion(nPort.qdPort.port, clipRegion);
486 // AppKit may have tried to help us by doing a BeginUpdate.
487 // But the invalid region at that level didn't include AppKit's notion of what was not valid.
488 // We reset the port's visible region to counteract what BeginUpdate did.
489 SetPortVisibleRegion(nPort.qdPort.port, clipRegion);
490 InvalWindowRgn(windowRef, clipRegion);
493 qdPortState->forUpdate = forUpdate;
496 #endif /* NP_NO_QUICKDRAW */
498 case NPDrawingModelCoreGraphics: {
499 if (![self canDraw]) {
504 ASSERT([NSView focusView] == self);
506 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
508 PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG));
509 portState = (PortState)cgPortState;
510 cgPortState->context = context;
513 if (eventModel != NPEventModelCocoa) {
514 // Update the plugin's window/context
515 nPort.cgPort.window = windowRef;
516 nPort.cgPort.context = context;
517 window.window = &nPort.cgPort;
519 #endif /* NP_NO_CARBON */
521 // Save current graphics context's state; will be restored by -restorePortState:
522 CGContextSaveGState(context);
524 // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
525 if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
526 // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
527 // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
528 // knows about the true set of dirty rects.
529 NSView *opaqueAncestor = [self opaqueAncestor];
530 const NSRect *dirtyRects;
532 [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count];
533 Vector<CGRect, 16> convertedDirtyRects;
534 convertedDirtyRects.resize(count);
535 for (int i = 0; i < count; ++i)
536 reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor];
537 CGContextClipToRects(context, convertedDirtyRects.data(), count);
543 case NPDrawingModelCoreAnimation:
544 // Just set the port state to a dummy value.
545 portState = (PortState)1;
549 ASSERT_NOT_REACHED();
557 - (PortState)saveAndSetNewPortState
559 return [self saveAndSetNewPortStateForUpdate:NO];
562 - (void)restorePortState:(PortState)portState
564 ASSERT([self currentWindow]);
567 switch (drawingModel) {
568 #ifndef NP_NO_QUICKDRAW
569 case NPDrawingModelQuickDraw: {
570 PortState_QD *qdPortState = (PortState_QD *)portState;
571 WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
572 CGrafPtr port = GetWindowPort(windowRef);
576 if (qdPortState->forUpdate)
577 ValidWindowRgn(windowRef, qdPortState->clipRegion);
579 SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v);
581 SetPortClipRegion(port, qdPortState->oldClipRegion);
582 if (qdPortState->forUpdate)
583 SetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
585 DisposeRgn(qdPortState->oldClipRegion);
586 DisposeRgn(qdPortState->oldVisibleRegion);
587 DisposeRgn(qdPortState->clipRegion);
589 SetGWorld(qdPortState->oldPort, qdPortState->oldDevice);
592 #endif /* NP_NO_QUICKDRAW */
594 case NPDrawingModelCoreGraphics: {
595 ASSERT([NSView focusView] == self);
597 CGContextRef context = ((PortState_CG *)portState)->context;
598 ASSERT(!nPort.cgPort.context || (context == nPort.cgPort.context));
599 CGContextRestoreGState(context);
603 case NPDrawingModelCoreAnimation:
604 ASSERT(portState == (PortState)1);
607 ASSERT_NOT_REACHED();
612 - (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect
621 ASSERT([_pluginPackage.get() pluginFuncs]->event);
623 // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
624 // We probably don't want more general reentrancy protection; we are really
625 // protecting only against this one case, which actually comes up when
626 // you first install the SVG viewer plug-in.
630 Frame* frame = core([self webFrame]);
633 Page* page = frame->page();
637 // Can only send drawRect (updateEvt) to CoreGraphics plugins when actually drawing
638 ASSERT((drawingModel != NPDrawingModelCoreGraphics) || !eventIsDrawRect || [NSView focusView] == self);
640 PortState portState = NULL;
642 if (isDrawingModelQuickDraw(drawingModel) || (drawingModel != NPDrawingModelCoreAnimation && eventIsDrawRect)) {
643 // In CoreGraphics mode, the port state only needs to be saved/set when redrawing the plug-in view.
644 // The plug-in is not allowed to draw at any other time.
645 portState = [self saveAndSetNewPortStateForUpdate:eventIsDrawRect];
646 // We may have changed the window, so inform the plug-in.
647 [self setWindowIfNecessary];
650 #if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW)
651 // Draw green to help debug.
652 // If we see any green we know something's wrong.
653 // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined.
654 if (isDrawingModelQuickDraw(drawingModel) && eventIsDrawRect) {
655 ForeColor(greenColor);
656 const ::Rect bigRect = { -10000, -10000, 10000, 10000 };
658 ForeColor(blackColor);
662 // Temporarily retain self in case the plug-in view is released while sending an event.
663 [[self retain] autorelease];
666 [self willCallPlugInFunction];
667 // Set the pluginAllowPopup flag.
668 ASSERT(_eventHandler);
670 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
671 UserGestureIndicator gestureIndicator(_eventHandler->currentEventIsUserGesture() ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
672 acceptedEvent = [_pluginPackage.get() pluginFuncs]->event(plugin, event);
674 [self didCallPlugInFunction];
677 if ([self currentWindow])
678 [self restorePortState:portState];
679 if (portState != (PortState)1)
683 return acceptedEvent;
686 - (void)windowFocusChanged:(BOOL)hasFocus
688 _eventHandler->windowFocusChanged(hasFocus);
691 - (void)sendDrawRectEvent:(NSRect)rect
693 ASSERT(_eventHandler);
695 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
696 _eventHandler->drawRect(context, rect);
704 _eventHandler->stopTimers();
709 HashMap<uint32_t, PluginTimer*>::const_iterator end = timers->end();
710 for (HashMap<uint32_t, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
711 PluginTimer* timer = it->second;
720 // If the plugin is completely obscured (scrolled out of view, for example), then we will
721 // send null events at a reduced rate.
722 _eventHandler->startTimers(_isCompletelyObscured);
727 HashMap<uint32_t, PluginTimer*>::const_iterator end = timers->end();
728 for (HashMap<uint32_t, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
729 PluginTimer* timer = it->second;
730 ASSERT(!timer->isActive());
731 timer->start(_isCompletelyObscured);
737 // We need to null check the event handler here because
738 // the plug-in view can resign focus after it's been stopped
739 // and the event handler has been deleted.
741 _eventHandler->focusChanged(_hasFocus);
744 - (void)mouseDown:(NSEvent *)theEvent
749 _eventHandler->mouseDown(theEvent);
752 - (void)mouseUp:(NSEvent *)theEvent
757 _eventHandler->mouseUp(theEvent);
760 - (void)handleMouseEntered:(NSEvent *)theEvent
765 // Set cursor to arrow. Plugins often handle cursor internally, but those that don't will just get this default one.
766 [[NSCursor arrowCursor] set];
768 _eventHandler->mouseEntered(theEvent);
771 - (void)handleMouseExited:(NSEvent *)theEvent
776 _eventHandler->mouseExited(theEvent);
778 // Set cursor back to arrow cursor. Because NSCursor doesn't know about changes that the plugin made, we could get confused about what we think the
779 // current cursor is otherwise. Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin.
780 [[NSCursor arrowCursor] set];
783 - (void)handleMouseMoved:(NSEvent *)theEvent
788 _eventHandler->mouseMoved(theEvent);
791 - (void)mouseDragged:(NSEvent *)theEvent
796 _eventHandler->mouseDragged(theEvent);
799 - (void)scrollWheel:(NSEvent *)theEvent
802 [super scrollWheel:theEvent];
806 if (!_eventHandler->scrollWheel(theEvent))
807 [super scrollWheel:theEvent];
810 - (void)keyUp:(NSEvent *)theEvent
815 _eventHandler->keyUp(theEvent);
818 - (void)keyDown:(NSEvent *)theEvent
823 _eventHandler->keyDown(theEvent);
826 - (void)flagsChanged:(NSEvent *)theEvent
831 _eventHandler->flagsChanged(theEvent);
834 - (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character
839 _eventHandler->syntheticKeyDownWithCommandModifier(keyCode, character);
842 - (void)privateBrowsingModeDidChange
847 NPBool value = _isPrivateBrowsingEnabled;
849 [self willCallPlugInFunction];
851 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
852 if ([_pluginPackage.get() pluginFuncs]->setvalue)
853 [_pluginPackage.get() pluginFuncs]->setvalue(plugin, NPNVprivateModeBool, &value);
855 [self didCallPlugInFunction];
858 // MARK: WEB_NETSCAPE_PLUGIN
860 - (BOOL)isNewWindowEqualToOldWindow
862 if (window.x != lastSetWindow.x)
864 if (window.y != lastSetWindow.y)
866 if (window.width != lastSetWindow.width)
868 if (window.height != lastSetWindow.height)
870 if (window.clipRect.top != lastSetWindow.clipRect.top)
872 if (window.clipRect.left != lastSetWindow.clipRect.left)
874 if (window.clipRect.bottom != lastSetWindow.clipRect.bottom)
876 if (window.clipRect.right != lastSetWindow.clipRect.right)
878 if (window.type != lastSetWindow.type)
881 switch (drawingModel) {
882 #ifndef NP_NO_QUICKDRAW
883 case NPDrawingModelQuickDraw:
884 if (nPort.qdPort.portx != lastSetPort.qdPort.portx)
886 if (nPort.qdPort.porty != lastSetPort.qdPort.porty)
888 if (nPort.qdPort.port != lastSetPort.qdPort.port)
891 #endif /* NP_NO_QUICKDRAW */
893 case NPDrawingModelCoreGraphics:
894 if (nPort.cgPort.window != lastSetPort.cgPort.window)
896 if (nPort.cgPort.context != lastSetPort.cgPort.context)
900 case NPDrawingModelCoreAnimation:
901 if (window.window != lastSetWindow.window)
905 ASSERT_NOT_REACHED();
912 -(void)tellQuickTimeToChill
914 #ifndef NP_NO_QUICKDRAW
915 ASSERT(isDrawingModelQuickDraw(drawingModel));
917 // Make a call to the secret QuickDraw API that makes QuickTime calm down.
918 WindowRef windowRef = (WindowRef)[[self window] windowRef];
922 CGrafPtr port = GetWindowPort(windowRef);
924 GetPortBounds(port, &bounds);
925 WKCallDrawingNotification(port, &bounds);
926 #endif /* NP_NO_QUICKDRAW */
929 - (void)updateAndSetWindow
931 // A plug-in can only update if it's (1) already been started (2) isn't stopped
932 // and (3) is able to draw on-screen. To meet condition (3) the plug-in must not
933 // be hidden and be attached to a window. There are two exceptions to this rule:
935 // Exception 1: QuickDraw plug-ins must be manually told when to stop writing
936 // bits to the window backing store, thus to do so requires a new call to
937 // NPP_SetWindow() with an empty NPWindow struct.
939 // Exception 2: CoreGraphics plug-ins expect to have their drawable area updated
940 // when they are moved to a background tab, via a NPP_SetWindow call. This is
941 // accomplished by allowing -saveAndSetNewPortStateForUpdate to "clip-out" the window's
942 // clipRect. Flash is curently an exception to this. See 6453738.
948 #ifdef NP_NO_QUICKDRAW
952 if (drawingModel == NPDrawingModelQuickDraw)
953 [self tellQuickTimeToChill];
954 else if (drawingModel == NPDrawingModelCoreGraphics && ![self canDraw] && _isFlash) {
955 // The Flash plug-in does not expect an NPP_SetWindow call from WebKit in this case.
956 // See Exception 2 above.
959 #endif // NP_NO_QUICKDRAW
961 BOOL didLockFocus = [NSView focusView] != self && [self lockFocusIfCanDraw];
963 PortState portState = [self saveAndSetNewPortState];
965 [self setWindowIfNecessary];
966 [self restorePortState:portState];
967 if (portState != (PortState)1)
969 } else if (drawingModel == NPDrawingModelCoreGraphics)
970 [self setWindowIfNecessary];
976 - (void)setWindowIfNecessary
981 if (![self isNewWindowEqualToOldWindow]) {
982 // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
983 // We probably don't want more general reentrancy protection; we are really
984 // protecting only against this one case, which actually comes up when
985 // you first install the SVG viewer plug-in.
988 BOOL wasInSetWindow = inSetWindow;
990 [self willCallPlugInFunction];
992 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
993 npErr = [_pluginPackage.get() pluginFuncs]->setwindow(plugin, &window);
995 [self didCallPlugInFunction];
996 inSetWindow = wasInSetWindow;
999 switch (drawingModel) {
1000 #ifndef NP_NO_QUICKDRAW
1001 case NPDrawingModelQuickDraw:
1002 LOG(Plugins, "NPP_SetWindow (QuickDraw): %d, port=0x%08x, window.x:%d window.y:%d window.width:%d window.height:%d",
1003 npErr, (int)nPort.qdPort.port, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
1005 #endif /* NP_NO_QUICKDRAW */
1007 case NPDrawingModelCoreGraphics:
1008 LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d",
1009 npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height,
1010 window.clipRect.right - window.clipRect.left, window.clipRect.bottom - window.clipRect.top);
1013 case NPDrawingModelCoreAnimation:
1014 LOG(Plugins, "NPP_SetWindow (CoreAnimation): %d, window=%p window.x:%d window.y:%d window.width:%d window.height:%d",
1015 npErr, window.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
1019 ASSERT_NOT_REACHED();
1022 #endif /* !defined(NDEBUG) */
1024 lastSetWindow = window;
1025 lastSetPort = nPort;
1029 + (void)setCurrentPluginView:(WebNetscapePluginView *)view
1031 currentPluginView = view;
1034 + (WebNetscapePluginView *)currentPluginView
1036 return currentPluginView;
1039 - (BOOL)createPlugin
1041 // Open the plug-in package so it remains loaded while our plugin uses it
1042 [_pluginPackage.get() open];
1044 // Initialize drawingModel to an invalid value so that we can detect when the plugin does not specify a drawingModel
1045 drawingModel = (NPDrawingModel)-1;
1047 // Initialize eventModel to an invalid value so that we can detect when the plugin does not specify an event model.
1048 eventModel = (NPEventModel)-1;
1050 NPError npErr = [self _createPlugin];
1051 if (npErr != NPERR_NO_ERROR) {
1052 LOG_ERROR("NPP_New failed with error: %d", npErr);
1053 [self _destroyPlugin];
1054 [_pluginPackage.get() close];
1058 if (drawingModel == (NPDrawingModel)-1) {
1059 #ifndef NP_NO_QUICKDRAW
1060 // Default to QuickDraw if the plugin did not specify a drawing model.
1061 drawingModel = NPDrawingModelQuickDraw;
1063 // QuickDraw is not available, so we can't default to it. Instead, default to CoreGraphics.
1064 drawingModel = NPDrawingModelCoreGraphics;
1068 if (eventModel == (NPEventModel)-1) {
1069 // If the plug-in did not specify a drawing model we default to Carbon when it is available.
1070 #ifndef NP_NO_CARBON
1071 eventModel = NPEventModelCarbon;
1073 eventModel = NPEventModelCocoa;
1074 #endif // NP_NO_CARBON
1077 #ifndef NP_NO_CARBON
1078 if (eventModel == NPEventModelCocoa && isDrawingModelQuickDraw(drawingModel)) {
1079 LOG(Plugins, "Plugin can't use use Cocoa event model with QuickDraw drawing model: %@", _pluginPackage.get());
1080 [self _destroyPlugin];
1081 [_pluginPackage.get() close];
1085 #endif // NP_NO_CARBON
1087 if (drawingModel == NPDrawingModelCoreAnimation) {
1089 if ([_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) {
1091 // The plug-in gives us a retained layer.
1092 _pluginLayer.adoptNS((CALayer *)value);
1094 BOOL accleratedCompositingEnabled = false;
1095 #if USE(ACCELERATED_COMPOSITING)
1096 accleratedCompositingEnabled = [[[self webView] preferences] acceleratedCompositingEnabled];
1098 if (accleratedCompositingEnabled) {
1099 // FIXME: This code can be shared between WebHostedNetscapePluginView and WebNetscapePluginView.
1100 #ifndef BUILDING_ON_LEOPARD
1101 // Since this layer isn't going to be inserted into a view, we need to create another layer and flip its geometry
1102 // in order to get the coordinate system right.
1103 RetainPtr<CALayer> realPluginLayer(AdoptNS, _pluginLayer.releaseRef());
1105 _pluginLayer.adoptNS([[CALayer alloc] init]);
1106 _pluginLayer.get().bounds = realPluginLayer.get().bounds;
1107 _pluginLayer.get().geometryFlipped = YES;
1109 realPluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
1110 [_pluginLayer.get() addSublayer:realPluginLayer.get()];
1112 // Eagerly enter compositing mode, since we know we'll need it. This avoids firing setNeedsStyleRecalc()
1113 // for iframes that contain composited plugins at bad times. https://bugs.webkit.org/show_bug.cgi?id=39033
1114 core([self webFrame])->view()->enterCompositingMode();
1115 [self element]->setNeedsStyleRecalc(SyntheticStyleChange);
1117 [self setWantsLayer:YES];
1119 LOG(Plugins, "%@ is using Core Animation drawing model with layer %@", _pluginPackage.get(), _pluginLayer.get());
1122 ASSERT(_pluginLayer);
1125 // Create the event handler
1126 _eventHandler = WebNetscapePluginEventHandler::create(self);
1131 // FIXME: This method is an ideal candidate to move up to the base class
1132 - (CALayer *)pluginLayer
1134 return _pluginLayer.get();
1137 - (void)setLayer:(CALayer *)newLayer
1139 [super setLayer:newLayer];
1141 if (newLayer && _pluginLayer) {
1142 _pluginLayer.get().frame = [newLayer frame];
1143 _pluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
1144 [newLayer addSublayer:_pluginLayer.get()];
1150 if ([self _shouldCancelSrcStream])
1153 if (_loadManually) {
1154 [self _redeliverStream];
1158 // If the OBJECT/EMBED tag has no SRC, the URL is passed to us as "".
1159 // Check for this and don't start a load in this case.
1160 if (_sourceURL && ![_sourceURL.get() _web_isEmpty]) {
1161 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_sourceURL.get()];
1162 [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()];
1163 [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO];
1169 // If we're already calling a plug-in function, do not call NPP_Destroy(). The plug-in function we are calling
1170 // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said
1171 // plugin-function returns.
1172 // See <rdar://problem/4480737>.
1173 if (pluginFunctionCallDepth > 0) {
1174 shouldStopSoon = YES;
1181 - (void)destroyPlugin
1183 // To stop active streams it's necessary to invoke stop() on a copy
1184 // of streams. This is because calling WebNetscapePluginStream::stop() also has the side effect
1185 // of removing a stream from this hash set.
1186 Vector<RefPtr<WebNetscapePluginStream> > streamsCopy;
1187 copyToVector(streams, streamsCopy);
1188 for (size_t i = 0; i < streamsCopy.size(); i++)
1189 streamsCopy[i]->stop();
1191 [[_pendingFrameLoads.get() allKeys] makeObjectsPerformSelector:@selector(_setInternalLoadDelegate:) withObject:nil];
1192 [NSObject cancelPreviousPerformRequestsWithTarget:self];
1194 // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted.
1195 lastSetWindow.type = (NPWindowType)0;
1199 [self _destroyPlugin];
1200 [_pluginPackage.get() close];
1202 _eventHandler.clear();
1205 - (NPEventModel)eventModel
1215 - (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values
1217 ASSERT([keys count] == [values count]);
1219 // Convert the attributes to 2 C string arrays.
1220 // These arrays are passed to NPP_New, but the strings need to be
1221 // modifiable and live the entire life of the plugin.
1223 // The Java plug-in requires the first argument to be the base URL
1224 if ([_MIMEType.get() isEqualToString:@"application/x-java-applet"]) {
1225 cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *));
1226 cValues = (char **)malloc(([values count] + 1) * sizeof(char *));
1227 cAttributes[0] = strdup("DOCBASE");
1228 cValues[0] = strdup([_baseURL.get() _web_URLCString]);
1231 cAttributes = (char **)malloc([keys count] * sizeof(char *));
1232 cValues = (char **)malloc([values count] * sizeof(char *));
1235 BOOL isWMP = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.WMP.defaultplugin";
1238 unsigned count = [keys count];
1239 for (i = 0; i < count; i++) {
1240 NSString *key = [keys objectAtIndex:i];
1241 NSString *value = [values objectAtIndex:i];
1242 if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) {
1243 specifiedHeight = [value intValue];
1244 } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) {
1245 specifiedWidth = [value intValue];
1247 // Avoid Window Media Player crash when these attributes are present.
1248 if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) {
1251 cAttributes[argsCount] = strdup([key UTF8String]);
1252 cValues[argsCount] = strdup([value UTF8String]);
1253 LOG(Plugins, "%@ = %@", key, value);
1258 - (uint32_t)checkIfAllowedToLoadURL:(const char*)urlCString frame:(const char*)frameNameCString
1259 callbackFunc:(void (*)(NPP npp, uint32_t checkID, NPBool allowed, void* context))callbackFunc
1260 context:(void*)context
1262 if (!_containerChecksInProgress)
1263 _containerChecksInProgress = [[NSMutableDictionary alloc] init];
1265 NSString *frameName = frameNameCString ? [NSString stringWithCString:frameNameCString encoding:NSISOLatin1StringEncoding] : nil;
1267 ++_currentContainerCheckRequestID;
1268 WebNetscapeContainerCheckContextInfo *contextInfo = [[WebNetscapeContainerCheckContextInfo alloc] initWithCheckRequestID:_currentContainerCheckRequestID
1269 callbackFunc:callbackFunc
1272 WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[self requestWithURLCString:urlCString]
1275 selector:@selector(_containerCheckResult:contextInfo:)
1277 contextInfo:contextInfo];
1279 [contextInfo release];
1280 [_containerChecksInProgress setObject:check forKey:[NSNumber numberWithInt:_currentContainerCheckRequestID]];
1283 return _currentContainerCheckRequestID;
1286 - (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo
1288 ASSERT([contextInfo isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]);
1289 void (*pluginCallback)(NPP npp, uint32_t, NPBool, void*) = [contextInfo callback];
1291 if (!pluginCallback) {
1292 ASSERT_NOT_REACHED();
1296 pluginCallback([self plugin], [contextInfo checkRequestID], (policy == PolicyUse), [contextInfo context]);
1299 - (void)cancelCheckIfAllowedToLoadURL:(uint32_t)checkID
1301 WebPluginContainerCheck *check = (WebPluginContainerCheck *)[_containerChecksInProgress objectForKey:[NSNumber numberWithInt:checkID]];
1307 [_containerChecksInProgress removeObjectForKey:[NSNumber numberWithInt:checkID]];
1310 // WebPluginContainerCheck automatically calls this method after invoking our _containerCheckResult: selector.
1311 // It works this way because calling -[WebPluginContainerCheck cancel] allows it to do it's teardown process.
1312 - (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck
1314 ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]);
1315 WebPluginContainerCheck *check = (WebPluginContainerCheck *)webPluginContainerCheck;
1316 ASSERT([[check contextInfo] isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]);
1318 [self cancelCheckIfAllowedToLoadURL:[[check contextInfo] checkRequestID]];
1324 - (id)initWithFrame:(NSRect)frame
1325 pluginPackage:(WebNetscapePluginPackage *)pluginPackage
1327 baseURL:(NSURL *)baseURL
1328 MIMEType:(NSString *)MIME
1329 attributeKeys:(NSArray *)keys
1330 attributeValues:(NSArray *)values
1331 loadManually:(BOOL)loadManually
1332 element:(PassRefPtr<WebCore::HTMLPlugInElement>)element
1334 self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element];
1338 _pendingFrameLoads.adoptNS([[NSMutableDictionary alloc] init]);
1340 // load the plug-in if it is not already loaded
1341 if (![pluginPackage load]) {
1349 - (id)initWithFrame:(NSRect)frame
1351 ASSERT_NOT_REACHED();
1357 #ifndef NP_NO_QUICKDRAW
1358 if (offscreenGWorld)
1359 DisposeGWorld(offscreenGWorld);
1362 for (unsigned i = 0; i < argsCount; i++) {
1363 free(cAttributes[i]);
1369 ASSERT(!_eventHandler);
1372 deleteAllValues(*timers);
1376 [_containerChecksInProgress release];
1379 - (void)disconnectStream:(WebNetscapePluginStream*)stream
1381 streams.remove(stream);
1386 ASSERT(!_isStarted);
1396 ASSERT_MAIN_THREAD();
1397 ASSERT(!_isStarted);
1404 - (void)drawRect:(NSRect)rect
1406 if (_cachedSnapshot) {
1407 NSRect sourceRect = { NSZeroPoint, [_cachedSnapshot.get() size] };
1408 [_cachedSnapshot.get() drawInRect:[self bounds] fromRect:sourceRect operation:NSCompositeSourceOver fraction:1];
1412 if (drawingModel == NPDrawingModelCoreAnimation && (!_snapshotting || ![self supportsSnapshotting]))
1418 if ([NSGraphicsContext currentContextDrawingToScreen] || _isFlash)
1419 [self sendDrawRectEvent:rect];
1421 NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap];
1422 if (printedPluginBitmap) {
1423 // Flip the bitmap before drawing because the QuickDraw port is flipped relative
1425 CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
1426 CGContextSaveGState(cgContext);
1427 NSRect bounds = [self bounds];
1428 CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds));
1429 CGContextScaleCTM(cgContext, 1.0f, -1.0f);
1430 [printedPluginBitmap drawInRect:bounds];
1431 CGContextRestoreGState(cgContext);
1436 - (NPObject *)createPluginScriptableObject
1438 if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted)
1441 NPObject *value = NULL;
1443 [self willCallPlugInFunction];
1445 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1446 error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginScriptableNPObject, &value);
1448 [self didCallPlugInFunction];
1449 if (error != NPERR_NO_ERROR)
1455 - (BOOL)getFormValue:(NSString **)value
1457 if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted)
1459 // Plugins will allocate memory for the buffer by using NPN_MemAlloc().
1460 char* buffer = NULL;
1462 [self willCallPlugInFunction];
1464 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1465 error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVformValue, &buffer);
1467 [self didCallPlugInFunction];
1468 if (error != NPERR_NO_ERROR || !buffer)
1470 *value = [[NSString alloc] initWithUTF8String:buffer];
1471 [_pluginPackage.get() browserFuncs]->memfree(buffer);
1475 - (void)willCallPlugInFunction
1479 // Could try to prevent infinite recursion here, but it's probably not worth the effort.
1480 pluginFunctionCallDepth++;
1483 - (void)didCallPlugInFunction
1485 ASSERT(pluginFunctionCallDepth > 0);
1486 pluginFunctionCallDepth--;
1488 // If -stop was called while we were calling into a plug-in function, and we're no longer
1489 // inside a plug-in function, stop now.
1490 if (pluginFunctionCallDepth == 0 && shouldStopSoon) {
1491 shouldStopSoon = NO;
1496 -(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
1498 ASSERT(_loadManually);
1499 ASSERT(!_manualStream);
1501 _manualStream = WebNetscapePluginStream::create(core([self webFrame])->loader());
1504 - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
1506 ASSERT(_loadManually);
1507 ASSERT(_manualStream);
1509 _dataLengthReceived += [data length];
1514 if (!_manualStream->plugin()) {
1515 // Check if the load should be cancelled
1516 if ([self _shouldCancelSrcStream]) {
1517 NSURLResponse *response = [[self dataSource] response];
1519 NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad
1520 contentURL:[response URL]
1522 pluginName:nil // FIXME: Get this from somewhere
1523 MIMEType:[response MIMEType]];
1524 [[self dataSource] _documentLoader]->cancelMainResourceLoad(error);
1529 _manualStream->setRequestURL([[[self dataSource] request] URL]);
1530 _manualStream->setPlugin([self plugin]);
1531 ASSERT(_manualStream->plugin());
1533 _manualStream->startStreamWithResponse([[self dataSource] response]);
1536 if (_manualStream->plugin())
1537 _manualStream->didReceiveData(0, static_cast<const char *>([data bytes]), [data length]);
1540 - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
1542 ASSERT(_loadManually);
1550 _manualStream->destroyStreamWithError(error);
1553 - (void)pluginViewFinishedLoading:(NSView *)pluginView
1555 ASSERT(_loadManually);
1556 ASSERT(_manualStream);
1559 _manualStream->didFinishLoading(0);
1562 - (NSTextInputContext *)inputContext
1569 @implementation WebNetscapePluginView (WebNPPCallbacks)
1571 - (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest
1573 // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called
1574 // if we are stopped since this method is called after a delay and we call
1575 // cancelPreviousPerformRequestsWithTarget inside of stop.
1580 NSURL *URL = [[JSPluginRequest request] URL];
1581 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1584 NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]];
1586 // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
1591 if ([JSPluginRequest frameName] != nil) {
1592 // FIXME: If the result is a string, we probably want to put that string into the frame.
1593 if ([JSPluginRequest sendNotification]) {
1594 [self willCallPlugInFunction];
1596 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1597 [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]);
1599 [self didCallPlugInFunction];
1601 } else if ([result length] > 0) {
1602 // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
1603 NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
1605 RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create([NSURLRequest requestWithURL:URL], plugin, [JSPluginRequest sendNotification], [JSPluginRequest notifyData]);
1607 RetainPtr<NSURLResponse> response(AdoptNS, [[NSURLResponse alloc] initWithURL:URL
1608 MIMEType:@"text/plain"
1609 expectedContentLength:[JSData length]
1610 textEncodingName:nil]);
1612 stream->startStreamWithResponse(response.get());
1613 stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]);
1614 stream->didFinishLoading(0);
1618 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason
1622 WebPluginRequest *pluginRequest = [_pendingFrameLoads.get() objectForKey:webFrame];
1623 ASSERT(pluginRequest != nil);
1624 ASSERT([pluginRequest sendNotification]);
1626 [self willCallPlugInFunction];
1628 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1629 [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]);
1631 [self didCallPlugInFunction];
1633 [_pendingFrameLoads.get() removeObjectForKey:webFrame];
1634 [webFrame _setInternalLoadDelegate:nil];
1637 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error
1639 NPReason reason = NPRES_DONE;
1641 reason = WebNetscapePluginStream::reasonForError(error);
1642 [self webFrame:webFrame didFinishLoadWithReason:reason];
1645 - (void)loadPluginRequest:(WebPluginRequest *)pluginRequest
1647 NSURLRequest *request = [pluginRequest request];
1648 NSString *frameName = [pluginRequest frameName];
1649 WebFrame *frame = nil;
1651 NSURL *URL = [request URL];
1652 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1654 ASSERT(frameName || JSString);
1657 // FIXME - need to get rid of this window creation which
1658 // bypasses normal targeted link handling
1659 frame = kit(core([self webFrame])->loader()->findFrameForNavigation(frameName));
1661 WebView *currentWebView = [self webView];
1662 NSDictionary *features = [[NSDictionary alloc] init];
1663 WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
1664 createWebViewWithRequest:nil
1665 windowFeatures:features];
1669 if ([pluginRequest sendNotification]) {
1670 [self willCallPlugInFunction];
1672 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1673 [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]);
1675 [self didCallPlugInFunction];
1680 frame = [newWebView mainFrame];
1681 core(frame)->tree()->setName(frameName);
1682 [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
1687 ASSERT(frame == nil || [self webFrame] == frame);
1688 [self evaluateJavaScriptPluginRequest:pluginRequest];
1690 [frame loadRequest:request];
1691 if ([pluginRequest sendNotification]) {
1692 // Check if another plug-in view or even this view is waiting for the frame to load.
1693 // If it is, tell it that the load was cancelled because it will be anyway.
1694 WebNetscapePluginView *view = [frame _internalLoadDelegate];
1696 ASSERT([view isKindOfClass:[WebNetscapePluginView class]]);
1697 [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK];
1699 [_pendingFrameLoads.get() _webkit_setObject:pluginRequest forUncopiedKey:frame];
1700 [frame _setInternalLoadDelegate:self];
1705 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification
1707 NSURL *URL = [request URL];
1710 return NPERR_INVALID_URL;
1712 // Don't allow requests to be loaded when the document loader is stopping all loaders.
1713 if ([[self dataSource] _documentLoader]->isStopping())
1714 return NPERR_GENERIC_ERROR;
1716 NSString *target = nil;
1718 // Find the frame given the target string.
1719 target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding];
1721 WebFrame *frame = [self webFrame];
1723 // don't let a plugin start any loads if it is no longer part of a document that is being
1724 // displayed unless the loads are in the same frame as the plugin.
1725 if ([[self dataSource] _documentLoader] != core([self webFrame])->loader()->activeDocumentLoader() &&
1726 (!cTarget || [frame findFrameNamed:target] != frame)) {
1727 return NPERR_GENERIC_ERROR;
1730 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
1731 if (JSString != nil) {
1732 if (![[[self webView] preferences] isJavaScriptEnabled]) {
1733 // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
1734 return NPERR_GENERIC_ERROR;
1735 } else if (cTarget == NULL && _mode == NP_FULL) {
1736 // Don't allow a JavaScript request from a standalone plug-in that is self-targetted
1737 // because this can cause the user to be redirected to a blank page (3424039).
1738 return NPERR_INVALID_PARAM;
1741 if (!core([self webFrame])->document()->securityOrigin()->canDisplay(URL))
1742 return NPERR_GENERIC_ERROR;
1745 if (cTarget || JSString) {
1746 // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
1747 // want to potentially kill the plug-in inside of its URL request.
1749 if (JSString && target && [frame findFrameNamed:target] != frame) {
1750 // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
1751 return NPERR_INVALID_PARAM;
1754 bool currentEventIsUserGesture = false;
1756 currentEventIsUserGesture = _eventHandler->currentEventIsUserGesture();
1758 WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request
1760 notifyData:notifyData
1761 sendNotification:sendNotification
1762 didStartFromUserGesture:currentEventIsUserGesture];
1763 [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0];
1764 [pluginRequest release];
1766 RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create(request, plugin, sendNotification, notifyData);
1768 streams.add(stream.get());
1772 return NPERR_NO_ERROR;
1775 -(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData
1777 LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget);
1779 NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1780 return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES];
1783 -(NPError)getURL:(const char *)URLCString target:(const char *)cTarget
1785 LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget);
1787 NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1788 return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO];
1791 - (NPError)_postURL:(const char *)URLCString
1792 target:(const char *)target
1794 buf:(const char *)buf
1796 notifyData:(void *)notifyData
1797 sendNotification:(BOOL)sendNotification
1798 allowHeaders:(BOOL)allowHeaders
1800 if (!URLCString || !len || !buf) {
1801 return NPERR_INVALID_PARAM;
1804 NSData *postData = nil;
1807 // If we're posting a file, buf is either a file URL or a path to the file.
1808 NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1);
1810 return NPERR_INVALID_PARAM;
1812 NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString];
1814 if ([fileURL isFileURL]) {
1815 path = [fileURL path];
1819 postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
1820 CFRelease(bufString);
1822 return NPERR_FILE_NOT_FOUND;
1825 postData = [NSData dataWithBytes:buf length:len];
1828 if ([postData length] == 0) {
1829 return NPERR_INVALID_PARAM;
1832 NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
1833 [request setHTTPMethod:@"POST"];
1836 if ([postData _web_startsWithBlankLine]) {
1837 postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)];
1839 NSInteger location = [postData _web_locationAfterFirstBlankLine];
1840 if (location != NSNotFound) {
1841 // If the blank line is somewhere in the middle of postData, everything before is the header.
1842 NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)];
1843 NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
1844 unsigned dataLength = [postData length] - location;
1846 // Sometimes plugins like to set Content-Length themselves when they post,
1847 // but WebFoundation does not like that. So we will remove the header
1848 // and instead truncate the data to the requested length.
1849 NSString *contentLength = [header objectForKey:@"Content-Length"];
1851 if (contentLength != nil)
1852 dataLength = min<unsigned>([contentLength intValue], dataLength);
1853 [header removeObjectForKey:@"Content-Length"];
1855 if ([header count] > 0) {
1856 [request setAllHTTPHeaderFields:header];
1858 // Everything after the blank line is the actual content of the POST.
1859 postData = [postData subdataWithRange:NSMakeRange(location, dataLength)];
1863 if ([postData length] == 0) {
1864 return NPERR_INVALID_PARAM;
1868 // Plug-ins expect to receive uncached data when doing a POST (3347134).
1869 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1870 [request setHTTPBody:postData];
1872 return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification];
1875 - (NPError)postURLNotify:(const char *)URLCString
1876 target:(const char *)target
1878 buf:(const char *)buf
1880 notifyData:(void *)notifyData
1882 LOG(Plugins, "NPN_PostURLNotify: %s", URLCString);
1883 return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES];
1886 -(NPError)postURL:(const char *)URLCString
1887 target:(const char *)target
1889 buf:(const char *)buf
1892 LOG(Plugins, "NPN_PostURL: %s", URLCString);
1893 // As documented, only allow headers to be specified via NPP_PostURL when using a file.
1894 return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file];
1897 -(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream
1899 LOG(Plugins, "NPN_NewStream");
1900 return NPERR_GENERIC_ERROR;
1903 -(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer
1905 LOG(Plugins, "NPN_Write");
1906 return NPERR_GENERIC_ERROR;
1909 -(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason
1911 LOG(Plugins, "NPN_DestroyStream");
1912 // This function does a sanity check to ensure that the NPStream provided actually
1913 // belongs to the plug-in that provided it, which fixes a crash in the DivX
1914 // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203
1915 if (!stream || WebNetscapePluginStream::ownerForStream(stream) != plugin) {
1916 LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream);
1917 return NPERR_INVALID_INSTANCE_ERROR;
1920 WebNetscapePluginStream* browserStream = static_cast<WebNetscapePluginStream*>(stream->ndata);
1921 browserStream->cancelLoadAndDestroyStreamWithError(browserStream->errorForReason(reason));
1923 return NPERR_NO_ERROR;
1926 - (const char *)userAgent
1928 NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()];
1930 if (_isSilverlight) {
1931 // Silverlight has a workaround for a leak in Safari 2. This workaround is
1932 // applied when the user agent does not contain "Version/3" so we append it
1933 // at the end of the user agent.
1934 userAgent = [userAgent stringByAppendingString:@" Version/3.2.1"];
1937 return [userAgent UTF8String];
1940 -(void)status:(const char *)message
1942 CFStringRef status = CFStringCreateWithCString(NULL, message ? message : "", kCFStringEncodingUTF8);
1944 LOG_ERROR("NPN_Status: the message was not valid UTF-8");
1948 LOG(Plugins, "NPN_Status: %@", status);
1949 WebView *wv = [self webView];
1950 [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status];
1954 -(void)invalidateRect:(NPRect *)invalidRect
1956 LOG(Plugins, "NPN_InvalidateRect");
1957 [self invalidatePluginContentRect:NSMakeRect(invalidRect->left, invalidRect->top,
1958 (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)];
1961 - (void)invalidateRegion:(NPRegion)invalidRegion
1963 LOG(Plugins, "NPN_InvalidateRegion");
1964 NSRect invalidRect = NSZeroRect;
1965 switch (drawingModel) {
1966 #ifndef NP_NO_QUICKDRAW
1967 case NPDrawingModelQuickDraw:
1970 GetRegionBounds((NPQDRegion)invalidRegion, &qdRect);
1971 invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top);
1974 #endif /* NP_NO_QUICKDRAW */
1976 case NPDrawingModelCoreGraphics:
1978 CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion);
1979 invalidRect = *(NSRect*)&cgRect;
1983 ASSERT_NOT_REACHED();
1987 [self invalidatePluginContentRect:invalidRect];
1992 LOG(Plugins, "forceRedraw");
1993 [self invalidatePluginContentRect:[self bounds]];
1994 [[self window] displayIfNeeded];
1997 - (NPError)getVariable:(NPNVariable)variable value:(void *)value
2000 case NPNVWindowNPObject:
2002 Frame* frame = core([self webFrame]);
2003 NPObject* windowScriptObject = frame ? frame->script()->windowScriptNPObject() : 0;
2005 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
2006 if (windowScriptObject)
2007 _NPN_RetainObject(windowScriptObject);
2009 void **v = (void **)value;
2010 *v = windowScriptObject;
2012 return NPERR_NO_ERROR;
2015 case NPNVPluginElementNPObject:
2018 return NPERR_GENERIC_ERROR;
2020 NPObject *plugInScriptObject = _element->getNPObject();
2022 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
2023 if (plugInScriptObject)
2024 _NPN_RetainObject(plugInScriptObject);
2026 void **v = (void **)value;
2027 *v = plugInScriptObject;
2029 return NPERR_NO_ERROR;
2032 case NPNVpluginDrawingModel:
2034 *(NPDrawingModel *)value = drawingModel;
2035 return NPERR_NO_ERROR;
2038 #ifndef NP_NO_QUICKDRAW
2039 case NPNVsupportsQuickDrawBool:
2041 *(NPBool *)value = TRUE;
2042 return NPERR_NO_ERROR;
2044 #endif /* NP_NO_QUICKDRAW */
2046 case NPNVsupportsCoreGraphicsBool:
2048 *(NPBool *)value = TRUE;
2049 return NPERR_NO_ERROR;
2052 case NPNVsupportsOpenGLBool:
2054 *(NPBool *)value = FALSE;
2055 return NPERR_NO_ERROR;
2058 case NPNVsupportsCoreAnimationBool:
2060 *(NPBool *)value = TRUE;
2061 return NPERR_NO_ERROR;
2064 #ifndef NP_NO_CARBON
2065 case NPNVsupportsCarbonBool:
2067 *(NPBool *)value = TRUE;
2068 return NPERR_NO_ERROR;
2070 #endif /* NP_NO_CARBON */
2072 case NPNVsupportsCocoaBool:
2074 *(NPBool *)value = TRUE;
2075 return NPERR_NO_ERROR;
2078 case NPNVprivateModeBool:
2080 *(NPBool *)value = _isPrivateBrowsingEnabled;
2081 return NPERR_NO_ERROR;
2084 case WKNVBrowserContainerCheckFuncs:
2086 *(WKNBrowserContainerCheckFuncs **)value = browserContainerCheckFuncs();
2087 return NPERR_NO_ERROR;
2089 #if USE(ACCELERATED_COMPOSITING)
2090 case WKNVSupportsCompositingCoreAnimationPluginsBool:
2092 *(NPBool *)value = [[[self webView] preferences] acceleratedCompositingEnabled];
2093 return NPERR_NO_ERROR;
2100 return NPERR_GENERIC_ERROR;
2103 - (NPError)setVariable:(NPPVariable)variable value:(void *)value
2106 case NPPVpluginDrawingModel:
2108 // Can only set drawing model inside NPP_New()
2109 if (self != [[self class] currentPluginView])
2110 return NPERR_GENERIC_ERROR;
2112 // Check for valid, supported drawing model
2113 NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value;
2114 switch (newDrawingModel) {
2115 // Supported drawing models:
2116 #ifndef NP_NO_QUICKDRAW
2117 case NPDrawingModelQuickDraw:
2119 case NPDrawingModelCoreGraphics:
2120 case NPDrawingModelCoreAnimation:
2121 drawingModel = newDrawingModel;
2122 return NPERR_NO_ERROR;
2125 // Unsupported (or unknown) drawing models:
2127 LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", _eventHandler.get(), drawingModel);
2128 return NPERR_GENERIC_ERROR;
2132 case NPPVpluginEventModel:
2134 // Can only set event model inside NPP_New()
2135 if (self != [[self class] currentPluginView])
2136 return NPERR_GENERIC_ERROR;
2138 // Check for valid, supported event model
2139 NPEventModel newEventModel = (NPEventModel)(uintptr_t)value;
2140 switch (newEventModel) {
2141 // Supported event models:
2142 #ifndef NP_NO_CARBON
2143 case NPEventModelCarbon:
2145 case NPEventModelCocoa:
2146 eventModel = newEventModel;
2147 return NPERR_NO_ERROR;
2149 // Unsupported (or unknown) event models:
2151 LOG(Plugins, "Plugin %@ uses unsupported event model: %d", _eventHandler.get(), eventModel);
2152 return NPERR_GENERIC_ERROR;
2157 return NPERR_GENERIC_ERROR;
2161 - (uint32_t)scheduleTimerWithInterval:(uint32_t)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32_t timerID))timerFunc
2167 timers = new HashMap<uint32_t, PluginTimer*>;
2172 timerID = ++currentTimerID;
2173 } while (timers->contains(timerID) || timerID == 0);
2175 PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc);
2176 timers->set(timerID, timer);
2178 if (_shouldFireTimers)
2179 timer->start(_isCompletelyObscured);
2184 - (void)unscheduleTimer:(uint32_t)timerID
2189 if (PluginTimer* timer = timers->take(timerID))
2193 - (NPError)popUpContextMenu:(NPMenu *)menu
2195 NSEvent *currentEvent = [NSApp currentEvent];
2197 // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent.
2199 return NPERR_GENERIC_ERROR;
2201 [NSMenu popUpContextMenu:(NSMenu *)menu withEvent:currentEvent forView:self];
2202 return NPERR_NO_ERROR;
2205 - (NPError)getVariable:(NPNURLVariable)variable forURL:(const char*)url value:(char**)value length:(uint32_t*)length
2208 case NPNURLVCookie: {
2212 NSURL *URL = [self URLWithCString:url];
2216 if (Frame* frame = core([self webFrame])) {
2217 String cookieString = cookies(frame->document(), URL);
2218 CString cookieStringUTF8 = cookieString.utf8();
2219 if (cookieStringUTF8.isNull())
2220 return NPERR_GENERIC_ERROR;
2222 *value = static_cast<char*>(NPN_MemAlloc(cookieStringUTF8.length()));
2223 memcpy(*value, cookieStringUTF8.data(), cookieStringUTF8.length());
2226 *length = cookieStringUTF8.length();
2227 return NPERR_NO_ERROR;
2231 case NPNURLVProxy: {
2232 #ifndef BUILDING_ON_LEOPARD
2236 NSURL *URL = [self URLWithCString:url];
2240 Vector<ProxyServer> proxyServers = proxyServersForURL(URL, 0);
2241 CString proxiesUTF8 = toString(proxyServers).utf8();
2243 *value = static_cast<char*>(NPN_MemAlloc(proxiesUTF8.length()));
2244 memcpy(*value, proxiesUTF8.data(), proxiesUTF8.length());
2247 *length = proxiesUTF8.length();
2249 return NPERR_NO_ERROR;
2255 return NPERR_GENERIC_ERROR;
2258 - (NPError)setVariable:(NPNURLVariable)variable forURL:(const char*)url value:(const char*)value length:(uint32_t)length
2261 case NPNURLVCookie: {
2262 NSURL *URL = [self URLWithCString:url];
2266 String cookieString = String::fromUTF8(value, length);
2270 if (Frame* frame = core([self webFrame])) {
2271 setCookies(frame->document(), URL, cookieString);
2272 return NPERR_NO_ERROR;
2278 // Can't set the proxy for a URL.
2281 return NPERR_GENERIC_ERROR;
2284 - (NPError)getAuthenticationInfoWithProtocol:(const char*)protocolStr host:(const char*)hostStr port:(int32_t)port scheme:(const char*)schemeStr realm:(const char*)realmStr
2285 username:(char**)usernameStr usernameLength:(uint32_t*)usernameLength
2286 password:(char**)passwordStr passwordLength:(uint32_t*)passwordLength
2288 if (!protocolStr || !hostStr || !schemeStr || !realmStr || !usernameStr || !usernameLength || !passwordStr || !passwordLength)
2289 return NPERR_GENERIC_ERROR;
2293 if (!getAuthenticationInfo(protocolStr, hostStr, port, schemeStr, realmStr, username, password))
2294 return NPERR_GENERIC_ERROR;
2296 *usernameLength = username.length();
2297 *usernameStr = static_cast<char*>(NPN_MemAlloc(username.length()));
2298 memcpy(*usernameStr, username.data(), username.length());
2300 *passwordLength = password.length();
2301 *passwordStr = static_cast<char*>(NPN_MemAlloc(password.length()));
2302 memcpy(*passwordStr, password.data(), password.length());
2304 return NPERR_NO_ERROR;
2307 - (char*)resolveURL:(const char*)url forTarget:(const char*)target
2309 CString location = [self resolvedURLStringForURL:url target:target];
2311 if (location.isNull())
2314 // We use strdup here because the caller needs to free it with NPN_MemFree (which calls free).
2315 return strdup(location.data());
2320 @implementation WebNetscapePluginView (Internal)
2322 - (BOOL)_shouldCancelSrcStream
2326 // Check if we should cancel the load
2327 NPBool cancelSrcStream = 0;
2328 if ([_pluginPackage.get() pluginFuncs]->getvalue &&
2329 [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCancelSrcStream, &cancelSrcStream) == NPERR_NO_ERROR && cancelSrcStream)
2335 // Work around Silverlight full screen performance issue by maintaining an accelerated GL pixel format.
2336 // We can safely remove it at some point in the future when both:
2337 // 1) Microsoft releases a genuine fix for 7288546.
2338 // 2) Enough Silverlight users update to the new Silverlight.
2339 // For now, we'll distinguish older broken versions of Silverlight by asking the plug-in if it resolved its full screen badness.
2340 - (void)_workaroundSilverlightFullscreenBug:(BOOL)initializedPlugin
2342 #ifndef BUILDING_ON_LEOPARD
2343 ASSERT(_isSilverlight);
2344 NPBool isFullscreenPerformanceIssueFixed = 0;
2345 NPPluginFuncs *pluginFuncs = [_pluginPackage.get() pluginFuncs];
2346 if (pluginFuncs->getvalue && pluginFuncs->getvalue(plugin, static_cast<NPPVariable>(WKNVSilverlightFullscreenPerformanceIssueFixed), &isFullscreenPerformanceIssueFixed) == NPERR_NO_ERROR && isFullscreenPerformanceIssueFixed)
2349 static CGLPixelFormatObj pixelFormatObject = 0;
2350 static unsigned refCount = 0;
2352 if (initializedPlugin) {
2354 if (refCount == 1) {
2355 const CGLPixelFormatAttribute attributes[] = { kCGLPFAAccelerated, static_cast<CGLPixelFormatAttribute>(0) };
2357 CGLChoosePixelFormat(attributes, &pixelFormatObject, &npix);
2360 ASSERT(pixelFormatObject);
2363 CGLReleasePixelFormat(pixelFormatObject);
2368 - (NPError)_createPlugin
2370 plugin = (NPP)calloc(1, sizeof(NPP_t));
2371 plugin->ndata = self;
2373 ASSERT([_pluginPackage.get() pluginFuncs]->newp);
2375 // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance.
2376 ASSERT(pluginFunctionCallDepth == 0);
2378 PluginMainThreadScheduler::scheduler().registerPlugin(plugin);
2380 _isFlash = [_pluginPackage.get() bundleIdentifier] == "com.macromedia.Flash Player.plugin";
2381 _isSilverlight = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.SilverlightPlugin";
2383 [[self class] setCurrentPluginView:self];
2384 NPError npErr = [_pluginPackage.get() pluginFuncs]->newp((char *)[_MIMEType.get() cString], plugin, _mode, argsCount, cAttributes, cValues, NULL);
2385 [[self class] setCurrentPluginView:nil];
2387 [self _workaroundSilverlightFullscreenBug:YES];
2388 LOG(Plugins, "NPP_New: %d", npErr);
2392 - (void)_destroyPlugin
2394 PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin);
2397 [self _workaroundSilverlightFullscreenBug:NO];
2400 npErr = ![_pluginPackage.get() pluginFuncs]->destroy(plugin, NULL);
2401 LOG(Plugins, "NPP_Destroy: %d", npErr);
2403 if (Frame* frame = core([self webFrame]))
2404 frame->script()->cleanupScriptObjectsForPlugin(self);
2410 - (NSBitmapImageRep *)_printedPluginBitmap
2412 #ifdef NP_NO_QUICKDRAW
2415 // Cannot print plugins that do not implement NPP_Print
2416 if (![_pluginPackage.get() pluginFuncs]->print)
2419 // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into.
2420 // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format.
2421 NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
2422 pixelsWide:window.width
2423 pixelsHigh:window.height
2428 colorSpaceName:NSDeviceRGBColorSpace
2429 bitmapFormat:NSAlphaFirstBitmapFormat
2431 bitsPerPixel:0] autorelease];
2434 // Create a GWorld with the same underlying buffer into which the plugin can draw
2435 ::Rect printGWorldBounds;
2436 SetRect(&printGWorldBounds, 0, 0, window.width, window.height);
2437 GWorldPtr printGWorld;
2438 if (NewGWorldFromPtr(&printGWorld,
2444 (Ptr)[bitmap bitmapData],
2445 [bitmap bytesPerRow]) != noErr) {
2446 LOG_ERROR("Could not create GWorld for printing");
2450 /// Create NPWindow for the GWorld
2451 NPWindow printNPWindow;
2452 printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr
2453 printNPWindow.x = 0;
2454 printNPWindow.y = 0;
2455 printNPWindow.width = window.width;
2456 printNPWindow.height = window.height;
2457 printNPWindow.clipRect.top = 0;
2458 printNPWindow.clipRect.left = 0;
2459 printNPWindow.clipRect.right = window.width;
2460 printNPWindow.clipRect.bottom = window.height;
2461 printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window
2463 // Create embed-mode NPPrint
2465 npPrint.mode = NP_EMBED;
2466 npPrint.print.embedPrint.window = printNPWindow;
2467 npPrint.print.embedPrint.platformPrint = printGWorld;
2469 // Tell the plugin to print into the GWorld
2470 [self willCallPlugInFunction];
2472 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
2473 [_pluginPackage.get() pluginFuncs]->print(plugin, &npPrint);
2475 [self didCallPlugInFunction];
2477 // Don't need the GWorld anymore
2478 DisposeGWorld(printGWorld);
2484 - (void)_redeliverStream
2486 if ([self dataSource] && _isStarted) {
2487 // Deliver what has not been passed to the plug-in up to this point.
2488 if (_dataLengthReceived > 0) {
2489 NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)];
2490 _dataLengthReceived = 0;
2491 [self pluginView:self receivedData:data];
2492 if (![[self dataSource] isLoading]) {
2494 [self pluginView:self receivedError:_error.get()];
2496 [self pluginViewFinishedLoading:self];