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 "WebBaseNetscapePluginView.h"
33 #import "WebDataSourceInternal.h"
34 #import "WebDefaultUIDelegate.h"
35 #import "WebFrameInternal.h"
36 #import "WebFrameView.h"
37 #import "WebGraphicsExtras.h"
38 #import "WebKitLogging.h"
39 #import "WebKitNSStringExtras.h"
40 #import "WebKitSystemInterface.h"
41 #import "WebNSDataExtras.h"
42 #import "WebNSDictionaryExtras.h"
43 #import "WebNSObjectExtras.h"
44 #import "WebNSURLExtras.h"
45 #import "WebNSURLRequestExtras.h"
46 #import "WebNSViewExtras.h"
47 #import "WebNetscapePluginPackage.h"
48 #import "WebBaseNetscapePluginStream.h"
49 #import "WebNetscapePluginEventHandler.h"
50 #import "WebNullPluginView.h"
51 #import "WebPreferences.h"
52 #import "WebViewInternal.h"
53 #import "WebUIDelegatePrivate.h"
54 #import <Carbon/Carbon.h>
55 #import <runtime/JSLock.h>
56 #import <WebCore/npruntime_impl.h>
57 #import <WebCore/Document.h>
58 #import <WebCore/DocumentLoader.h>
59 #import <WebCore/Element.h>
60 #import <WebCore/Frame.h>
61 #import <WebCore/FrameLoader.h>
62 #import <WebCore/FrameTree.h>
63 #import <WebCore/Page.h>
64 #import <WebCore/PluginMainThreadScheduler.h>
65 #import <WebCore/ScriptController.h>
66 #import <WebCore/SoftLinking.h>
67 #import <WebCore/WebCoreObjCExtras.h>
68 #import <WebKit/nptextinput.h>
69 #import <WebKit/DOMPrivate.h>
70 #import <WebKit/WebUIDelegate.h>
71 #import <wtf/Assertions.h>
72 #import <objc/objc-runtime.h>
74 using namespace WebCore;
76 #define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification"
77 #define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification"
79 static inline bool isDrawingModelQuickDraw(NPDrawingModel drawingModel)
81 #ifndef NP_NO_QUICKDRAW
82 return drawingModel == NPDrawingModelQuickDraw;
88 @interface WebBaseNetscapePluginView (Internal)
89 - (void)_viewHasMoved;
90 - (NPError)_createPlugin;
91 - (void)_destroyPlugin;
92 - (NSBitmapImageRep *)_printedPluginBitmap;
93 - (void)_redeliverStream;
96 static WebBaseNetscapePluginView *currentPluginView = nil;
98 typedef struct OpaquePortState* PortState;
100 static const double ThrottledTimerInterval = 0.25;
102 class PluginTimer : public TimerBase {
104 typedef void (*TimerFunc)(NPP npp, uint32 timerID);
106 PluginTimer(NPP npp, uint32 timerID, uint32 interval, NPBool repeat, TimerFunc timerFunc)
109 , m_interval(interval)
111 , m_timerFunc(timerFunc)
115 void start(bool throttle)
119 double timeInterval = throttle ? ThrottledTimerInterval : m_interval / 1000.0;
121 startRepeating(timeInterval);
123 startOneShot(timeInterval);
129 m_timerFunc(m_npp, m_timerID);
138 TimerFunc m_timerFunc;
141 #ifndef NP_NO_QUICKDRAW
143 // QuickDraw is not available in 64-bit
149 RgnHandle oldClipRegion;
150 RgnHandle oldVisibleRegion;
151 RgnHandle clipRegion;
155 #endif /* NP_NO_QUICKDRAW */
158 CGContextRef context;
161 @class NSTextInputContext;
162 @interface NSResponder (AppKitDetails)
163 - (NSTextInputContext *)inputContext;
166 @interface WebPluginRequest : NSObject
168 NSURLRequest *_request;
169 NSString *_frameName;
171 BOOL _didStartFromUserGesture;
172 BOOL _sendNotification;
175 - (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture;
177 - (NSURLRequest *)request;
178 - (NSString *)frameName;
179 - (void *)notifyData;
180 - (BOOL)isCurrentEventUserGesture;
181 - (BOOL)sendNotification;
185 @interface NSData (WebPluginDataExtras)
186 - (BOOL)_web_startsWithBlankLine;
187 - (NSInteger)_web_locationAfterFirstBlankLine;
190 @interface WebBaseNetscapePluginView (ForwardDeclarations)
191 - (void)setWindowIfNecessary;
192 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification;
195 @implementation WebBaseNetscapePluginView
199 #ifndef BUILDING_ON_TIGER
200 WebCoreObjCFinalizeOnMainThread(self);
202 WKSendUserChangeNotifications();
207 - (BOOL)superviewsHaveSuperviews
209 NSView *contentView = [[self window] contentView];
211 for (view = self; view != nil; view = [view superview]) {
212 if (view == contentView) {
220 // The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers
221 // the entire window frame (or structure region to use the Carbon term) rather then just the window content.
222 // We can remove this when <rdar://problem/4201099> is fixed.
223 - (void)fixWindowPort
225 #ifndef NP_NO_QUICKDRAW
226 ASSERT(isDrawingModelQuickDraw(drawingModel));
228 NSWindow *currentWindow = [self currentWindow];
229 if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")])
232 float windowHeight = [currentWindow frame].size.height;
233 NSView *contentView = [currentWindow contentView];
234 NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates
238 SetPort(GetWindowPort((WindowRef)[currentWindow windowRef]));
240 MovePortTo(static_cast<short>(contentRect.origin.x), /* Flip Y */ static_cast<short>(windowHeight - NSMaxY(contentRect)));
241 PortSize(static_cast<short>(contentRect.size.width), static_cast<short>(contentRect.size.height));
247 #ifndef NP_NO_QUICKDRAW
248 static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context)
250 UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) & kCGBitmapByteOrderMask;
251 if (byteOrder == kCGBitmapByteOrderDefault)
252 switch (CGBitmapContextGetBitsPerPixel(context)) {
254 byteOrder = kCGBitmapByteOrder16Host;
257 byteOrder = kCGBitmapByteOrder32Host;
261 case kCGBitmapByteOrder16Little:
262 return k16LE555PixelFormat;
263 case kCGBitmapByteOrder32Little:
264 return k32BGRAPixelFormat;
265 case kCGBitmapByteOrder16Big:
266 return k16BE555PixelFormat;
267 case kCGBitmapByteOrder32Big:
268 return k32ARGBPixelFormat;
270 ASSERT_NOT_REACHED();
274 static inline void getNPRect(const CGRect& cgr, NPRect& npr)
276 npr.top = static_cast<uint16>(cgr.origin.y);
277 npr.left = static_cast<uint16>(cgr.origin.x);
278 npr.bottom = static_cast<uint16>(CGRectGetMaxY(cgr));
279 npr.right = static_cast<uint16>(CGRectGetMaxX(cgr));
284 static inline void getNPRect(const NSRect& nr, NPRect& npr)
286 npr.top = static_cast<uint16>(nr.origin.y);
287 npr.left = static_cast<uint16>(nr.origin.x);
288 npr.bottom = static_cast<uint16>(NSMaxY(nr));
289 npr.right = static_cast<uint16>(NSMaxX(nr));
292 - (NSRect)visibleRect
294 // WebCore may impose an additional clip (via CSS overflow or clip properties). Fetch
296 return NSIntersectionRect([self convertRect:[_element.get() _windowClipRect] fromView:nil], [super visibleRect]);
299 - (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate
301 ASSERT(drawingModel != NPDrawingModelCoreAnimation);
302 ASSERT([self currentWindow] != nil);
304 // Use AppKit to convert view coordinates to NSWindow coordinates.
305 NSRect boundsInWindow = [self convertRect:[self bounds] toView:nil];
306 NSRect visibleRectInWindow = [self convertRect:[self visibleRect] toView:nil];
308 // Flip Y to convert NSWindow coordinates to top-left-based window coordinates.
309 float borderViewHeight = [[self currentWindow] frame].size.height;
310 boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow);
311 visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow);
313 #ifndef NP_NO_QUICKDRAW
314 WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
317 // Look at the Carbon port to convert top-left-based window coordinates into top-left-based content coordinates.
318 if (isDrawingModelQuickDraw(drawingModel)) {
319 // If drawing with QuickDraw, fix the window port so that it has the same bounds as the NSWindow's
320 // content view. This makes it easier to convert between AppKit view and QuickDraw port coordinates.
321 [self fixWindowPort];
324 CGrafPtr port = GetWindowPort(windowRef);
325 GetPortBounds(port, &portBounds);
327 PixMap *pix = *GetPortPixMap(port);
328 boundsInWindow.origin.x += pix->bounds.left - portBounds.left;
329 boundsInWindow.origin.y += pix->bounds.top - portBounds.top;
330 visibleRectInWindow.origin.x += pix->bounds.left - portBounds.left;
331 visibleRectInWindow.origin.y += pix->bounds.top - portBounds.top;
335 window.type = NPWindowTypeWindow;
336 window.x = (int32)boundsInWindow.origin.x;
337 window.y = (int32)boundsInWindow.origin.y;
338 window.width = static_cast<uint32>(NSWidth(boundsInWindow));
339 window.height = static_cast<uint32>(NSHeight(boundsInWindow));
341 // "Clip-out" the plug-in when:
342 // 1) it's not really in a window or off-screen or has no height or width.
343 // 2) window.x is a "big negative number" which is how WebCore expresses off-screen widgets.
344 // 3) the window is miniaturized or the app is hidden
345 // 4) we're inside of viewWillMoveToWindow: with a nil window. In this case, superviews may already have nil
346 // superviews and nil windows and results from convertRect:toView: are incorrect.
347 NSWindow *realWindow = [self window];
348 if (window.width <= 0 || window.height <= 0 || window.x < -100000
349 || realWindow == nil || [realWindow isMiniaturized]
351 || ![self superviewsHaveSuperviews]
352 || [self isHiddenOrHasHiddenAncestor]) {
354 // The following code tries to give plug-ins the same size they will eventually have.
355 // The specifiedWidth and specifiedHeight variables are used to predict the size that
356 // WebCore will eventually resize us to.
358 // The QuickTime plug-in has problems if you give it a width or height of 0.
359 // Since other plug-ins also might have the same sort of trouble, we make sure
360 // to always give plug-ins a size other than 0,0.
362 if (window.width <= 0)
363 window.width = specifiedWidth > 0 ? specifiedWidth : 100;
364 if (window.height <= 0)
365 window.height = specifiedHeight > 0 ? specifiedHeight : 100;
367 window.clipRect.bottom = window.clipRect.top;
368 window.clipRect.left = window.clipRect.right;
370 getNPRect(visibleRectInWindow, window.clipRect);
373 // Save the port state, set up the port for entry into the plugin
375 switch (drawingModel) {
376 #ifndef NP_NO_QUICKDRAW
377 case NPDrawingModelQuickDraw: {
380 CGrafPtr port = GetWindowPort(windowRef);
381 GetPortBounds(port, &portBounds);
382 nPort.qdPort.port = port;
383 nPort.qdPort.portx = (int32)-boundsInWindow.origin.x;
384 nPort.qdPort.porty = (int32)-boundsInWindow.origin.y;
385 window.window = &nPort;
387 PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD));
388 portState = (PortState)qdPortState;
390 GetGWorld(&qdPortState->oldPort, &qdPortState->oldDevice);
392 qdPortState->oldOrigin.h = portBounds.left;
393 qdPortState->oldOrigin.v = portBounds.top;
395 qdPortState->oldClipRegion = NewRgn();
396 GetPortClipRegion(port, qdPortState->oldClipRegion);
398 qdPortState->oldVisibleRegion = NewRgn();
399 GetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
401 RgnHandle clipRegion = NewRgn();
402 qdPortState->clipRegion = clipRegion;
404 CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
405 if (currentContext && WKCGContextIsBitmapContext(currentContext)) {
406 // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData
407 // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext
408 // returns true, it still might not be a context we need to create a GWorld for; for example
409 // transparency layers will return true, but return 0 for CGBitmapContextGetData.
410 void* offscreenData = CGBitmapContextGetData(currentContext);
412 // If the current context is an offscreen bitmap, then create a GWorld for it.
413 ::Rect offscreenBounds;
414 offscreenBounds.top = 0;
415 offscreenBounds.left = 0;
416 offscreenBounds.right = CGBitmapContextGetWidth(currentContext);
417 offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext);
418 GWorldPtr newOffscreenGWorld;
419 QDErr err = NewGWorldFromPtr(&newOffscreenGWorld,
420 getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0,
421 static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext));
422 ASSERT(newOffscreenGWorld && !err);
425 DisposeGWorld(offscreenGWorld);
426 offscreenGWorld = newOffscreenGWorld;
428 SetGWorld(offscreenGWorld, NULL);
430 port = offscreenGWorld;
432 nPort.qdPort.port = port;
433 boundsInWindow = [self bounds];
435 // Generate a QD origin based on the current affine transform for currentContext.
436 CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext);
437 CGPoint origin = {0,0};
438 CGPoint axisFlip = {1,1};
439 origin = CGPointApplyAffineTransform(origin, offscreenMatrix);
440 axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix);
442 // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that.
443 origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x);
444 origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y);
446 nPort.qdPort.portx = static_cast<int32>(-boundsInWindow.origin.x + origin.x);
447 nPort.qdPort.porty = static_cast<int32>(-boundsInWindow.origin.y - origin.y);
450 window.window = &nPort;
452 // Use the clip bounds from the context instead of the bounds we created
453 // from the window above.
454 getNPRect(CGRectOffset(CGContextGetClipBoundingBox(currentContext), -origin.x, origin.y), window.clipRect);
459 MacSetRectRgn(clipRegion,
460 window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty,
461 window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty);
463 // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
464 if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
465 // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are
466 // not going to be redrawn this update. This forces plug-ins to play nice with z-index ordering.
468 RgnHandle viewClipRegion = NewRgn();
470 // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
471 // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
472 // knows about the true set of dirty rects.
473 NSView *opaqueAncestor = [self opaqueAncestor];
474 const NSRect *dirtyRects;
475 NSInteger dirtyRectCount, dirtyRectIndex;
476 [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
478 for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) {
479 NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor];
480 if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) {
481 // Create a region for this dirty rect
482 RgnHandle dirtyRectRegion = NewRgn();
483 SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect)));
485 // Union this dirty rect with the rest of the dirty rects
486 UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion);
487 DisposeRgn(dirtyRectRegion);
491 // Intersect the dirty region with the clip region, so that we only draw over dirty parts
492 SectRgn(clipRegion, viewClipRegion, clipRegion);
493 DisposeRgn(viewClipRegion);
497 // Switch to the port and set it up.
500 ForeColor(blackColor);
501 BackColor(whiteColor);
502 SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty);
503 SetPortClipRegion(nPort.qdPort.port, clipRegion);
506 // AppKit may have tried to help us by doing a BeginUpdate.
507 // But the invalid region at that level didn't include AppKit's notion of what was not valid.
508 // We reset the port's visible region to counteract what BeginUpdate did.
509 SetPortVisibleRegion(nPort.qdPort.port, clipRegion);
510 InvalWindowRgn(windowRef, clipRegion);
513 qdPortState->forUpdate = forUpdate;
516 #endif /* NP_NO_QUICKDRAW */
518 case NPDrawingModelCoreGraphics: {
519 ASSERT([NSView focusView] == self);
521 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
523 PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG));
524 portState = (PortState)cgPortState;
525 cgPortState->context = context;
527 // Update the plugin's window/context
529 nPort.cgPort.window = (NPNSWindow *)[self currentWindow];
531 nPort.cgPort.window = _eventHandler->platformWindow([self currentWindow]);
532 #endif /* NP_NO_CARBON */
533 nPort.cgPort.context = context;
534 window.window = &nPort.cgPort;
536 // Save current graphics context's state; will be restored by -restorePortState:
537 CGContextSaveGState(context);
539 // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
540 if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
541 // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
542 // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
543 // knows about the true set of dirty rects.
544 NSView *opaqueAncestor = [self opaqueAncestor];
545 const NSRect *dirtyRects;
547 [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count];
548 Vector<CGRect, 16> convertedDirtyRects;
549 convertedDirtyRects.resize(count);
550 for (int i = 0; i < count; ++i)
551 reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor];
552 CGContextClipToRects(context, convertedDirtyRects.data(), count);
559 ASSERT_NOT_REACHED();
567 - (PortState)saveAndSetNewPortState
569 return [self saveAndSetNewPortStateForUpdate:NO];
572 - (void)restorePortState:(PortState)portState
574 if (drawingModel == NPDrawingModelCoreAnimation)
577 ASSERT([self currentWindow]);
580 switch (drawingModel) {
581 #ifndef NP_NO_QUICKDRAW
582 case NPDrawingModelQuickDraw: {
583 PortState_QD *qdPortState = (PortState_QD *)portState;
584 WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
585 CGrafPtr port = GetWindowPort(windowRef);
589 if (qdPortState->forUpdate)
590 ValidWindowRgn(windowRef, qdPortState->clipRegion);
592 SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v);
594 SetPortClipRegion(port, qdPortState->oldClipRegion);
595 if (qdPortState->forUpdate)
596 SetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
598 DisposeRgn(qdPortState->oldClipRegion);
599 DisposeRgn(qdPortState->oldVisibleRegion);
600 DisposeRgn(qdPortState->clipRegion);
602 SetGWorld(qdPortState->oldPort, qdPortState->oldDevice);
605 #endif /* NP_NO_QUICKDRAW */
607 case NPDrawingModelCoreGraphics:
608 ASSERT([NSView focusView] == self);
609 ASSERT(((PortState_CG *)portState)->context == nPort.cgPort.context);
610 CGContextRestoreGState(nPort.cgPort.context);
614 ASSERT_NOT_REACHED();
619 - (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect
628 ASSERT(NPP_HandleEvent);
630 // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
631 // We probably don't want more general reentrancy protection; we are really
632 // protecting only against this one case, which actually comes up when
633 // you first install the SVG viewer plug-in.
637 Frame* frame = core([self webFrame]);
640 Page* page = frame->page();
644 bool wasDeferring = page->defersLoading();
646 page->setDefersLoading(true);
648 // Can only send drawRect (updateEvt) to CoreGraphics plugins when actually drawing
649 ASSERT((drawingModel != NPDrawingModelCoreGraphics) || !eventIsDrawRect || [NSView focusView] == self);
651 PortState portState = NULL;
653 if (isDrawingModelQuickDraw(drawingModel) || (drawingModel != NPDrawingModelCoreAnimation && eventIsDrawRect)) {
654 // In CoreGraphics mode, the port state only needs to be saved/set when redrawing the plug-in view.
655 // The plug-in is not allowed to draw at any other time.
656 portState = [self saveAndSetNewPortStateForUpdate:eventIsDrawRect];
657 // We may have changed the window, so inform the plug-in.
658 [self setWindowIfNecessary];
661 #if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW)
662 // Draw green to help debug.
663 // If we see any green we know something's wrong.
664 // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined.
665 if (isDrawingModelQuickDraw(drawingModel) && eventIsDrawRect) {
666 ForeColor(greenColor);
667 const ::Rect bigRect = { -10000, -10000, 10000, 10000 };
669 ForeColor(blackColor);
673 // Temporarily retain self in case the plug-in view is released while sending an event.
674 [[self retain] autorelease];
677 [self willCallPlugInFunction];
679 JSC::JSLock::DropAllLocks dropAllLocks(false);
680 acceptedEvent = NPP_HandleEvent(plugin, event);
682 [self didCallPlugInFunction];
685 if ([self currentWindow])
686 [self restorePortState:portState];
691 page->setDefersLoading(false);
693 return acceptedEvent;
696 - (void)sendActivateEvent:(BOOL)activate
701 _eventHandler->windowFocusChanged(activate);
704 - (void)sendDrawRectEvent:(NSRect)rect
706 ASSERT(_eventHandler);
708 _eventHandler->drawRect(rect);
714 _eventHandler->stopTimers();
716 shouldFireTimers = NO;
721 HashMap<uint32, PluginTimer*>::const_iterator end = timers->end();
722 for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
723 PluginTimer* timer = it->second;
728 - (void)restartTimers
730 ASSERT([self window]);
732 if (shouldFireTimers)
735 if (!isStarted || [[self window] isMiniaturized])
738 shouldFireTimers = YES;
740 // If the plugin is completely obscured (scrolled out of view, for example), then we will
741 // send null events at a reduced rate.
742 _eventHandler->startTimers(isCompletelyObscured);
747 HashMap<uint32, PluginTimer*>::const_iterator end = timers->end();
748 for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
749 PluginTimer* timer = it->second;
750 ASSERT(!timer->isActive());
751 timer->start(isCompletelyObscured);
755 - (BOOL)acceptsFirstResponder
760 - (void)setHasFocus:(BOOL)flag
765 if (hasFocus == flag)
770 // We need to null check the event handler here because
771 // the plug-in view can resign focus after it's been stopped
772 // and the event handler has been deleted.
774 _eventHandler->focusChanged(hasFocus);
777 - (BOOL)becomeFirstResponder
779 [self setHasFocus:YES];
783 - (BOOL)resignFirstResponder
785 [self setHasFocus:NO];
789 // AppKit doesn't call mouseDown or mouseUp on right-click. Simulate control-click
790 // mouseDown and mouseUp so plug-ins get the right-click event as they do in Carbon (3125743).
791 - (void)rightMouseDown:(NSEvent *)theEvent
793 [self mouseDown:theEvent];
796 - (void)rightMouseUp:(NSEvent *)theEvent
798 [self mouseUp:theEvent];
801 - (void)mouseDown:(NSEvent *)theEvent
806 _eventHandler->mouseDown(theEvent);
809 - (void)mouseUp:(NSEvent *)theEvent
814 _eventHandler->mouseUp(theEvent);
817 - (void)mouseEntered:(NSEvent *)theEvent
822 _eventHandler->mouseEntered(theEvent);
825 - (void)mouseExited:(NSEvent *)theEvent
830 _eventHandler->mouseExited(theEvent);
832 // 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
833 // current cursor is otherwise. Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin.
834 [[NSCursor arrowCursor] set];
837 // We can't name this method mouseMoved because we don't want to override
838 // the NSView mouseMoved implementation.
839 - (void)handleMouseMoved:(NSEvent *)theEvent
844 _eventHandler->mouseMoved(theEvent);
847 - (void)mouseDragged:(NSEvent *)theEvent
852 _eventHandler->mouseDragged(theEvent);
855 - (void)scrollWheel:(NSEvent *)theEvent
858 [super scrollWheel:theEvent];
862 if (!_eventHandler->scrollWheel(theEvent))
863 [super scrollWheel:theEvent];
866 - (void)keyUp:(NSEvent *)theEvent
871 _eventHandler->keyUp(theEvent);
874 - (void)keyDown:(NSEvent *)theEvent
879 _eventHandler->keyDown(theEvent);
882 - (void)flagsChanged:(NSEvent *)theEvent
887 _eventHandler->flagsChanged(theEvent);
890 - (void)cut:(id)sender
895 _eventHandler->keyDown([NSApp currentEvent]);
898 - (void)copy:(id)sender
903 _eventHandler->keyDown([NSApp currentEvent]);
906 - (void)paste:(id)sender
911 _eventHandler->keyDown([NSApp currentEvent]);
914 - (void)selectAll:(id)sender
919 _eventHandler->keyDown([NSApp currentEvent]);
922 #pragma mark WEB_NETSCAPE_PLUGIN
924 - (BOOL)isNewWindowEqualToOldWindow
926 ASSERT(drawingModel != NPDrawingModelCoreAnimation);
928 if (window.x != lastSetWindow.x)
930 if (window.y != lastSetWindow.y)
932 if (window.width != lastSetWindow.width)
934 if (window.height != lastSetWindow.height)
936 if (window.clipRect.top != lastSetWindow.clipRect.top)
938 if (window.clipRect.left != lastSetWindow.clipRect.left)
940 if (window.clipRect.bottom != lastSetWindow.clipRect.bottom)
942 if (window.clipRect.right != lastSetWindow.clipRect.right)
944 if (window.type != lastSetWindow.type)
947 switch (drawingModel) {
948 #ifndef NP_NO_QUICKDRAW
949 case NPDrawingModelQuickDraw:
950 if (nPort.qdPort.portx != lastSetPort.qdPort.portx)
952 if (nPort.qdPort.porty != lastSetPort.qdPort.porty)
954 if (nPort.qdPort.port != lastSetPort.qdPort.port)
957 #endif /* NP_NO_QUICKDRAW */
959 case NPDrawingModelCoreGraphics:
960 if (nPort.cgPort.window != lastSetPort.cgPort.window)
962 if (nPort.cgPort.context != lastSetPort.cgPort.context)
967 ASSERT_NOT_REACHED();
974 - (void)updateAndSetWindow
976 ASSERT(drawingModel != NPDrawingModelCoreAnimation);
978 // A plug-in can only update if it's (1) already been started (2) isn't stopped
979 // and (3) is able to draw on-screen. To meet condition (3) the plug-in must not
980 // be hidden and be attached to a window. QuickDraw plug-ins are an important
981 // excpetion to rule (3) because they manually must be told when to stop writing
982 // bits to the window backing store, thus to do so requires a new call to
983 // NPP_SetWindow() with an empty NPWindow struct.
986 #ifdef NP_NO_QUICKDRAW
990 if (drawingModel != NPDrawingModelQuickDraw && ![self canDraw])
992 #endif // NP_NO_QUICKDRAW
994 BOOL didLockFocus = [NSView focusView] != self && [self lockFocusIfCanDraw];
996 if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel)) {
997 [self setWindowIfNecessary];
1004 PortState portState = [self saveAndSetNewPortState];
1006 [self setWindowIfNecessary];
1007 [self restorePortState:portState];
1014 - (void)setWindowIfNecessary
1016 ASSERT(drawingModel != NPDrawingModelCoreAnimation);
1022 if (![self isNewWindowEqualToOldWindow]) {
1023 // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
1024 // We probably don't want more general reentrancy protection; we are really
1025 // protecting only against this one case, which actually comes up when
1026 // you first install the SVG viewer plug-in.
1028 ASSERT(!inSetWindow);
1032 // A CoreGraphics plugin's window may only be set while the plugin is being updated
1033 ASSERT((drawingModel != NPDrawingModelCoreGraphics) || [NSView focusView] == self);
1035 [self willCallPlugInFunction];
1037 JSC::JSLock::DropAllLocks dropAllLocks(false);
1038 npErr = NPP_SetWindow(plugin, &window);
1040 [self didCallPlugInFunction];
1044 switch (drawingModel) {
1045 #ifndef NP_NO_QUICKDRAW
1046 case NPDrawingModelQuickDraw:
1047 LOG(Plugins, "NPP_SetWindow (QuickDraw): %d, port=0x%08x, window.x:%d window.y:%d window.width:%d window.height:%d",
1048 npErr, (int)nPort.qdPort.port, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
1050 #endif /* NP_NO_QUICKDRAW */
1052 case NPDrawingModelCoreGraphics:
1053 LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d",
1054 npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
1058 ASSERT_NOT_REACHED();
1061 #endif /* !defined(NDEBUG) */
1063 lastSetWindow = window;
1064 lastSetPort = nPort;
1068 - (void)removeTrackingRect
1071 [self removeTrackingRect:trackingTag];
1074 // Do the following after setting trackingTag to 0 so we don't re-enter.
1076 // Balance the retain in resetTrackingRect. Use autorelease in case we hold
1077 // the last reference to the window during tear-down, to avoid crashing AppKit.
1078 [[self window] autorelease];
1082 - (void)resetTrackingRect
1084 [self removeTrackingRect];
1086 // Retain the window so that removeTrackingRect can work after the window is closed.
1087 [[self window] retain];
1088 trackingTag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO];
1092 + (void)setCurrentPluginView:(WebBaseNetscapePluginView *)view
1094 currentPluginView = view;
1097 + (WebBaseNetscapePluginView *)currentPluginView
1099 return currentPluginView;
1109 if (_loadManually) {
1110 [self _redeliverStream];
1114 // If the OBJECT/EMBED tag has no SRC, the URL is passed to us as "".
1115 // Check for this and don't start a load in this case.
1116 if (_sourceURL && ![_sourceURL.get() _web_isEmpty]) {
1117 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_sourceURL.get()];
1118 [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()];
1119 [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO];
1123 - (void)addWindowObservers
1125 ASSERT([self window]);
1127 NSWindow *theWindow = [self window];
1129 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
1130 [notificationCenter addObserver:self selector:@selector(windowWillClose:)
1131 name:NSWindowWillCloseNotification object:theWindow];
1132 [notificationCenter addObserver:self selector:@selector(windowBecameKey:)
1133 name:NSWindowDidBecomeKeyNotification object:theWindow];
1134 [notificationCenter addObserver:self selector:@selector(windowResignedKey:)
1135 name:NSWindowDidResignKeyNotification object:theWindow];
1136 [notificationCenter addObserver:self selector:@selector(windowDidMiniaturize:)
1137 name:NSWindowDidMiniaturizeNotification object:theWindow];
1138 [notificationCenter addObserver:self selector:@selector(windowDidDeminiaturize:)
1139 name:NSWindowDidDeminiaturizeNotification object:theWindow];
1141 [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchFromUser:)
1142 name:LoginWindowDidSwitchFromUserNotification object:nil];
1143 [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchToUser:)
1144 name:LoginWindowDidSwitchToUserNotification object:nil];
1147 - (void)removeWindowObservers
1149 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
1150 [notificationCenter removeObserver:self name:NSWindowWillCloseNotification object:nil];
1151 [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
1152 [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
1153 [notificationCenter removeObserver:self name:NSWindowDidMiniaturizeNotification object:nil];
1154 [notificationCenter removeObserver:self name:NSWindowDidDeminiaturizeNotification object:nil];
1155 [notificationCenter removeObserver:self name:LoginWindowDidSwitchFromUserNotification object:nil];
1156 [notificationCenter removeObserver:self name:LoginWindowDidSwitchToUserNotification object:nil];
1161 ASSERT([self currentWindow]);
1166 if (![self canStart])
1169 ASSERT([self webView]);
1171 if (![[[self webView] preferences] arePlugInsEnabled])
1174 // Open the plug-in package so it remains loaded while our plugin uses it
1175 [_pluginPackage.get() open];
1177 // Initialize drawingModel to an invalid value so that we can detect when the plugin does not specify a drawingModel
1178 drawingModel = (NPDrawingModel)-1;
1180 // Initialize eventModel to an invalid value so that we can detect when the plugin does not specify an event model.
1181 eventModel = (NPEventModel)-1;
1183 NPError npErr = [self _createPlugin];
1184 if (npErr != NPERR_NO_ERROR) {
1185 LOG_ERROR("NPP_New failed with error: %d", npErr);
1186 [self _destroyPlugin];
1187 [_pluginPackage.get() close];
1191 if (drawingModel == (NPDrawingModel)-1) {
1192 #ifndef NP_NO_QUICKDRAW
1193 // Default to QuickDraw if the plugin did not specify a drawing model.
1194 drawingModel = NPDrawingModelQuickDraw;
1196 // QuickDraw is not available, so we can't default to it. Instead, default to CoreGraphics.
1197 drawingModel = NPDrawingModelCoreGraphics;
1201 if (eventModel == (NPEventModel)-1) {
1202 // If the plug-in did not specify a drawing model we default to Carbon when it is available.
1203 #ifndef NP_NO_CARBON
1204 eventModel = NPEventModelCarbon;
1206 eventModel = NPEventModelCocoa;
1207 #endif // NP_NO_CARBON
1210 #ifndef NP_NO_CARBON
1211 if (eventModel == NPEventModelCocoa && isDrawingModelQuickDraw(drawingModel)) {
1212 LOG(Plugins, "Plugin can't use use Cocoa event model with QuickDraw drawing model: %@", _pluginPackage.get());
1213 [self _destroyPlugin];
1214 [_pluginPackage.get() close];
1218 #endif // NP_NO_CARBON
1220 #ifndef BUILDING_ON_TIGER
1221 if (drawingModel == NPDrawingModelCoreAnimation) {
1223 if (NPP_GetValue(plugin, NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) {
1225 // The plug-in gives us a retained layer.
1226 _layer.adoptNS((CALayer *)value);
1227 [self setWantsLayer:YES];
1228 [self setLayer:_layer.get()];
1229 LOG(Plugins, "%@ is using Core Animation drawing model with layer %@", _pluginPackage.get(), _layer.get());
1236 // Create the event handler
1237 _eventHandler.set(WebNetscapePluginEventHandler::create(self));
1239 // Get the text input vtable
1240 if (eventModel == NPEventModelCocoa) {
1241 [self willCallPlugInFunction];
1243 JSC::JSLock::DropAllLocks dropAllLocks(false);
1244 NPPluginTextInputFuncs *value;
1245 if (NPP_GetValue(plugin, NPPVpluginTextInputFuncs, &value) == NPERR_NO_ERROR && value)
1246 textInputFuncs = value;
1248 [self didCallPlugInFunction];
1252 [[self webView] addPluginInstanceView:self];
1254 if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel))
1255 [self updateAndSetWindow];
1257 if ([self window]) {
1258 [self addWindowObservers];
1259 if ([[self window] isKeyWindow]) {
1260 [self sendActivateEvent:YES];
1262 [self restartTimers];
1265 [self resetTrackingRect];
1274 // If we're already calling a plug-in function, do not call NPP_Destroy(). The plug-in function we are calling
1275 // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said
1276 // plugin-function returns.
1277 // See <rdar://problem/4480737>.
1278 if (pluginFunctionCallDepth > 0) {
1279 shouldStopSoon = YES;
1283 [self removeTrackingRect];
1290 [[self webView] removePluginInstanceView:self];
1292 // To stop active streams it's necessary to invoke stop() on a copy
1293 // of streams. This is because calling WebNetscapePluginStream::stop() also has the side effect
1294 // of removing a stream from this hash set.
1295 Vector<RefPtr<WebNetscapePluginStream> > streamsCopy;
1296 copyToVector(streams, streamsCopy);
1297 for (size_t i = 0; i < streamsCopy.size(); i++)
1298 streamsCopy[i]->stop();
1303 // Stop notifications and callbacks.
1304 [self removeWindowObservers];
1305 [[_pendingFrameLoads.get() allKeys] makeObjectsPerformSelector:@selector(_setInternalLoadDelegate:) withObject:nil];
1306 [NSObject cancelPreviousPerformRequestsWithTarget:self];
1308 // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted.
1309 lastSetWindow.type = (NPWindowType)0;
1313 [self _destroyPlugin];
1314 [_pluginPackage.get() close];
1316 _eventHandler.clear();
1326 - (NPEventModel)eventModel
1331 - (WebDataSource *)dataSource
1333 WebFrame *webFrame = kit(core(_element.get())->document()->frame());
1334 return [webFrame _dataSource];
1337 - (WebFrame *)webFrame
1339 return [[self dataSource] webFrame];
1342 - (WebView *)webView
1344 return [[self webFrame] webView];
1347 - (NSWindow *)currentWindow
1349 return [self window] ? [self window] : [[self webView] hostWindow];
1357 - (WebNetscapePluginPackage *)pluginPackage
1359 return _pluginPackage.get();
1362 - (void)setPluginPackage:(WebNetscapePluginPackage *)thePluginPackage;
1364 _pluginPackage = thePluginPackage;
1366 NPP_New = [_pluginPackage.get() NPP_New];
1367 NPP_Destroy = [_pluginPackage.get() NPP_Destroy];
1368 NPP_SetWindow = [_pluginPackage.get() NPP_SetWindow];
1369 NPP_NewStream = [_pluginPackage.get() NPP_NewStream];
1370 NPP_WriteReady = [_pluginPackage.get() NPP_WriteReady];
1371 NPP_Write = [_pluginPackage.get() NPP_Write];
1372 NPP_StreamAsFile = [_pluginPackage.get() NPP_StreamAsFile];
1373 NPP_DestroyStream = [_pluginPackage.get() NPP_DestroyStream];
1374 NPP_HandleEvent = [_pluginPackage.get() NPP_HandleEvent];
1375 NPP_URLNotify = [_pluginPackage.get() NPP_URLNotify];
1376 NPP_GetValue = [_pluginPackage.get() NPP_GetValue];
1377 NPP_SetValue = [_pluginPackage.get() NPP_SetValue];
1378 NPP_Print = [_pluginPackage.get() NPP_Print];
1381 - (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values;
1383 ASSERT([keys count] == [values count]);
1385 // Convert the attributes to 2 C string arrays.
1386 // These arrays are passed to NPP_New, but the strings need to be
1387 // modifiable and live the entire life of the plugin.
1389 // The Java plug-in requires the first argument to be the base URL
1390 if ([_MIMEType.get() isEqualToString:@"application/x-java-applet"]) {
1391 cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *));
1392 cValues = (char **)malloc(([values count] + 1) * sizeof(char *));
1393 cAttributes[0] = strdup("DOCBASE");
1394 cValues[0] = strdup([_baseURL.get() _web_URLCString]);
1397 cAttributes = (char **)malloc([keys count] * sizeof(char *));
1398 cValues = (char **)malloc([values count] * sizeof(char *));
1401 BOOL isWMP = [[[_pluginPackage.get() bundle] bundleIdentifier] isEqualToString:@"com.microsoft.WMP.defaultplugin"];
1404 unsigned count = [keys count];
1405 for (i = 0; i < count; i++) {
1406 NSString *key = [keys objectAtIndex:i];
1407 NSString *value = [values objectAtIndex:i];
1408 if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) {
1409 specifiedHeight = [value intValue];
1410 } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) {
1411 specifiedWidth = [value intValue];
1413 // Avoid Window Media Player crash when these attributes are present.
1414 if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) {
1417 cAttributes[argsCount] = strdup([key UTF8String]);
1418 cValues[argsCount] = strdup([value UTF8String]);
1419 LOG(Plugins, "%@ = %@", key, value);
1426 - (id)initWithFrame:(NSRect)frame
1427 pluginPackage:(WebNetscapePluginPackage *)thePluginPackage
1429 baseURL:(NSURL *)theBaseURL
1430 MIMEType:(NSString *)MIME
1431 attributeKeys:(NSArray *)keys
1432 attributeValues:(NSArray *)values
1433 loadManually:(BOOL)loadManually
1434 DOMElement:(DOMElement *)anElement
1436 [super initWithFrame:frame];
1438 _pendingFrameLoads.adoptNS([[NSMutableDictionary alloc] init]);
1440 // load the plug-in if it is not already loaded
1441 if (![thePluginPackage load]) {
1445 [self setPluginPackage:thePluginPackage];
1447 _element = anElement;
1448 _sourceURL.adoptNS([theURL copy]);
1449 _baseURL.adoptNS([theBaseURL copy]);
1451 [self setAttributeKeys:keys andValues:values];
1457 _loadManually = loadManually;
1461 - (id)initWithFrame:(NSRect)frame
1463 ASSERT_NOT_REACHED();
1469 #ifndef NP_NO_QUICKDRAW
1470 if (offscreenGWorld)
1471 DisposeGWorld(offscreenGWorld);
1474 for (unsigned i = 0; i < argsCount; i++) {
1475 free(cAttributes[i]);
1481 ASSERT(!_eventHandler);
1484 deleteAllValues(*timers);
1489 - (void)disconnectStream:(WebNetscapePluginStream*)stream
1491 streams.remove(stream);
1506 ASSERT_MAIN_THREAD();
1514 - (void)drawRect:(NSRect)rect
1516 if (drawingModel == NPDrawingModelCoreAnimation)
1522 if ([NSGraphicsContext currentContextDrawingToScreen])
1523 [self sendDrawRectEvent:rect];
1525 NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap];
1526 if (printedPluginBitmap) {
1527 // Flip the bitmap before drawing because the QuickDraw port is flipped relative
1529 CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
1530 CGContextSaveGState(cgContext);
1531 NSRect bounds = [self bounds];
1532 CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds));
1533 CGContextScaleCTM(cgContext, 1.0f, -1.0f);
1534 [printedPluginBitmap drawInRect:bounds];
1535 CGContextRestoreGState(cgContext);
1547 [super renewGState];
1549 // -renewGState is called whenever the view's geometry changes. It's a little hacky to override this method, but
1550 // much safer than walking up the view hierarchy and observing frame/bounds changed notifications, since you don't
1551 // have to track subsequent changes to the view hierarchy and add/remove notification observers.
1552 // NSOpenGLView uses the exact same technique to reshape its OpenGL surface.
1553 [self _viewHasMoved];
1556 -(void)tellQuickTimeToChill
1558 #ifndef NP_NO_QUICKDRAW
1559 ASSERT(isDrawingModelQuickDraw(drawingModel));
1561 // Make a call to the secret QuickDraw API that makes QuickTime calm down.
1562 WindowRef windowRef = (WindowRef)[[self window] windowRef];
1566 CGrafPtr port = GetWindowPort(windowRef);
1568 GetPortBounds(port, &bounds);
1569 WKCallDrawingNotification(port, &bounds);
1570 #endif /* NP_NO_QUICKDRAW */
1573 - (void)viewWillMoveToWindow:(NSWindow *)newWindow
1575 if (isDrawingModelQuickDraw(drawingModel))
1576 [self tellQuickTimeToChill];
1578 // We must remove the tracking rect before we move to the new window.
1579 // Once we move to the new window, it will be too late.
1580 [self removeTrackingRect];
1581 [self removeWindowObservers];
1583 // Workaround for: <rdar://problem/3822871> resignFirstResponder is not sent to first responder view when it is removed from the window
1584 [self setHasFocus:NO];
1587 if ([[self webView] hostWindow]) {
1588 // View will be moved out of the actual window but it still has a host window.
1591 // View will have no associated windows.
1594 // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy.
1595 // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed.
1596 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
1601 - (void)viewWillMoveToSuperview:(NSView *)newSuperview
1603 if (!newSuperview) {
1604 // Stop the plug-in when it is removed from its superview. It is not sufficient to do this in -viewWillMoveToWindow:nil, because
1605 // the WebView might still has a hostWindow at that point, which prevents the plug-in from being destroyed.
1606 // There is no need to start the plug-in when moving into a superview. -viewDidMoveToWindow takes care of that.
1609 // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy.
1610 // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed.
1611 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
1615 - (void)viewDidMoveToWindow
1617 [self resetTrackingRect];
1619 if ([self window]) {
1620 // While in the view hierarchy, observe WebPreferencesChangedNotification so that we can start/stop depending
1621 // on whether plugins are enabled.
1622 [[NSNotificationCenter defaultCenter] addObserver:self
1623 selector:@selector(preferencesHaveChanged:)
1624 name:WebPreferencesChangedNotification
1627 // View moved to an actual window. Start it if not already started.
1629 [self restartTimers];
1630 [self addWindowObservers];
1631 } else if ([[self webView] hostWindow]) {
1632 // View moved out of an actual window, but still has a host window.
1633 // Call setWindow to explicitly "clip out" the plug-in from sight.
1634 // FIXME: It would be nice to do this where we call stopNullEvents in viewWillMoveToWindow.
1635 [self updateAndSetWindow];
1639 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
1641 if (!hostWindow && ![self window]) {
1642 // View will have no associated windows.
1645 // Remove WebPreferencesChangedNotification observer -- we will observe once again when we move back into the window
1646 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
1650 - (void)viewDidMoveToHostWindow
1652 if ([[self webView] hostWindow]) {
1653 // View now has an associated window. Start it if not already started.
1658 #pragma mark NOTIFICATIONS
1660 - (void)windowWillClose:(NSNotification *)notification
1665 - (void)windowBecameKey:(NSNotification *)notification
1667 [self sendActivateEvent:YES];
1668 [self setNeedsDisplay:YES];
1669 [self restartTimers];
1670 #ifndef NP_NO_CARBON
1671 SetUserFocusWindow((WindowRef)[[self window] windowRef]);
1672 #endif // NP_NO_CARBON
1675 - (void)windowResignedKey:(NSNotification *)notification
1677 [self sendActivateEvent:NO];
1678 [self setNeedsDisplay:YES];
1679 [self restartTimers];
1682 - (void)windowDidMiniaturize:(NSNotification *)notification
1687 - (void)windowDidDeminiaturize:(NSNotification *)notification
1692 - (void)loginWindowDidSwitchFromUser:(NSNotification *)notification
1697 -(void)loginWindowDidSwitchToUser:(NSNotification *)notification
1699 [self restartTimers];
1702 - (void)preferencesHaveChanged:(NSNotification *)notification
1704 WebPreferences *preferences = [[self webView] preferences];
1705 BOOL arePlugInsEnabled = [preferences arePlugInsEnabled];
1707 if ([notification object] == preferences && isStarted != arePlugInsEnabled) {
1708 if (arePlugInsEnabled) {
1709 if ([self currentWindow]) {
1714 [self setNeedsDisplay:YES];
1719 - (NPObject *)createPluginScriptableObject
1721 if (!NPP_GetValue || ![self isStarted])
1724 NPObject *value = NULL;
1726 [self willCallPlugInFunction];
1728 JSC::JSLock::DropAllLocks dropAllLocks(false);
1729 error = NPP_GetValue(plugin, NPPVpluginScriptableNPObject, &value);
1731 [self didCallPlugInFunction];
1732 if (error != NPERR_NO_ERROR)
1738 - (void)willCallPlugInFunction
1742 // Could try to prevent infinite recursion here, but it's probably not worth the effort.
1743 pluginFunctionCallDepth++;
1746 - (void)didCallPlugInFunction
1748 ASSERT(pluginFunctionCallDepth > 0);
1749 pluginFunctionCallDepth--;
1751 // If -stop was called while we were calling into a plug-in function, and we're no longer
1752 // inside a plug-in function, stop now.
1753 if (pluginFunctionCallDepth == 0 && shouldStopSoon) {
1754 shouldStopSoon = NO;
1759 -(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
1761 ASSERT(_loadManually);
1762 ASSERT(!_manualStream);
1764 _manualStream = WebNetscapePluginStream::create(core([self webFrame])->loader());
1767 - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
1769 ASSERT(_loadManually);
1770 ASSERT(_manualStream);
1772 _dataLengthReceived += [data length];
1774 if (![self isStarted])
1777 if (!_manualStream->plugin()) {
1779 _manualStream->setRequestURL([[[self dataSource] request] URL]);
1780 _manualStream->setPlugin([self plugin]);
1781 ASSERT(_manualStream->plugin());
1783 _manualStream->startStreamWithResponse([[self dataSource] response]);
1786 if (_manualStream->plugin())
1787 _manualStream->didReceiveData(0, static_cast<const char *>([data bytes]), [data length]);
1790 - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
1792 ASSERT(_loadManually);
1796 if (![self isStarted]) {
1800 _manualStream->destroyStreamWithError(error);
1803 - (void)pluginViewFinishedLoading:(NSView *)pluginView
1805 ASSERT(_loadManually);
1806 ASSERT(_manualStream);
1808 if ([self isStarted])
1809 _manualStream->didFinishLoading(0);
1812 #pragma mark NSTextInput implementation
1814 - (NSTextInputContext *)inputContext
1816 #ifndef NP_NO_CARBON
1817 if (![self isStarted] || eventModel == NPEventModelCarbon)
1821 return [super inputContext];
1824 - (BOOL)hasMarkedText
1826 ASSERT(eventModel == NPEventModelCocoa);
1827 ASSERT([self isStarted]);
1829 if (textInputFuncs && textInputFuncs->hasMarkedText)
1830 return textInputFuncs->hasMarkedText(plugin);
1835 - (void)insertText:(id)aString
1837 ASSERT(eventModel == NPEventModelCocoa);
1838 ASSERT([self isStarted]);
1840 if (textInputFuncs && textInputFuncs->insertText)
1841 textInputFuncs->insertText(plugin, aString);
1844 - (NSRange)markedRange
1846 ASSERT(eventModel == NPEventModelCocoa);
1847 ASSERT([self isStarted]);
1849 if (textInputFuncs && textInputFuncs->markedRange)
1850 return textInputFuncs->markedRange(plugin);
1852 return NSMakeRange(NSNotFound, 0);
1855 - (NSRange)selectedRange
1857 ASSERT(eventModel == NPEventModelCocoa);
1858 ASSERT([self isStarted]);
1860 if (textInputFuncs && textInputFuncs->selectedRange)
1861 return textInputFuncs->selectedRange(plugin);
1863 return NSMakeRange(NSNotFound, 0);
1866 - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange
1868 ASSERT(eventModel == NPEventModelCocoa);
1869 ASSERT([self isStarted]);
1871 if (textInputFuncs && textInputFuncs->setMarkedText)
1872 textInputFuncs->setMarkedText(plugin, aString, selRange);
1877 ASSERT(eventModel == NPEventModelCocoa);
1878 ASSERT([self isStarted]);
1880 if (textInputFuncs && textInputFuncs->unmarkText)
1881 textInputFuncs->unmarkText(plugin);
1884 - (NSArray *)validAttributesForMarkedText
1886 ASSERT(eventModel == NPEventModelCocoa);
1887 ASSERT([self isStarted]);
1889 if (textInputFuncs && textInputFuncs->validAttributesForMarkedText)
1890 return textInputFuncs->validAttributesForMarkedText(plugin);
1892 return [NSArray array];
1895 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
1897 ASSERT(eventModel == NPEventModelCocoa);
1898 ASSERT([self isStarted]);
1900 if (textInputFuncs && textInputFuncs->attributedSubstringFromRange)
1901 return textInputFuncs->attributedSubstringFromRange(plugin, theRange);
1906 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1908 ASSERT(eventModel == NPEventModelCocoa);
1909 ASSERT([self isStarted]);
1911 if (textInputFuncs && textInputFuncs->characterIndexForPoint) {
1912 // Convert the point to window coordinates
1913 NSPoint point = [[self window] convertScreenToBase:thePoint];
1915 // And view coordinates
1916 point = [self convertPoint:point fromView:nil];
1918 return textInputFuncs->characterIndexForPoint(plugin, point);
1924 - (void)doCommandBySelector:(SEL)aSelector
1926 ASSERT(eventModel == NPEventModelCocoa);
1927 ASSERT([self isStarted]);
1929 if (textInputFuncs && textInputFuncs->doCommandBySelector)
1930 textInputFuncs->doCommandBySelector(plugin, aSelector);
1933 - (NSRect)firstRectForCharacterRange:(NSRange)theRange
1935 ASSERT(eventModel == NPEventModelCocoa);
1936 ASSERT([self isStarted]);
1938 if (textInputFuncs && textInputFuncs->firstRectForCharacterRange) {
1939 NSRect rect = textInputFuncs->firstRectForCharacterRange(plugin, theRange);
1941 // Convert the rect to window coordinates
1942 rect = [self convertRect:rect toView:nil];
1944 // Convert the rect location to screen coordinates
1945 rect.origin = [[self window] convertBaseToScreen:rect.origin];
1953 // test for 10.4 because of <rdar://problem/4243463>
1954 #ifdef BUILDING_ON_TIGER
1955 - (long)conversationIdentifier
1960 - (NSInteger)conversationIdentifier
1962 return (NSInteger)self;
1968 @implementation WebBaseNetscapePluginView (WebNPPCallbacks)
1970 - (NSMutableURLRequest *)requestWithURLCString:(const char *)URLCString
1975 CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, URLCString, kCFStringEncodingISOLatin1);
1976 ASSERT(string); // All strings should be representable in ISO Latin 1
1978 NSString *URLString = [(NSString *)string _web_stringByStrippingReturnCharacters];
1979 NSURL *URL = [NSURL _web_URLWithDataAsString:URLString relativeToURL:_baseURL.get()];
1984 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
1985 Frame* frame = core([self webFrame]);
1988 [request _web_setHTTPReferrer:frame->loader()->outgoingReferrer()];
1992 - (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest
1994 // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called
1995 // if we are stopped since this method is called after a delay and we call
1996 // cancelPreviousPerformRequestsWithTarget inside of stop.
2001 NSURL *URL = [[JSPluginRequest request] URL];
2002 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
2005 NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]];
2007 // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
2012 if ([JSPluginRequest frameName] != nil) {
2013 // FIXME: If the result is a string, we probably want to put that string into the frame.
2014 if ([JSPluginRequest sendNotification]) {
2015 [self willCallPlugInFunction];
2017 JSC::JSLock::DropAllLocks dropAllLocks(false);
2018 NPP_URLNotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]);
2020 [self didCallPlugInFunction];
2022 } else if ([result length] > 0) {
2023 // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
2024 NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
2026 RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create([NSURLRequest requestWithURL:URL], plugin, [JSPluginRequest sendNotification], [JSPluginRequest notifyData]);
2028 RetainPtr<NSURLResponse> response(AdoptNS, [[NSURLResponse alloc] initWithURL:URL
2029 MIMEType:@"text/plain"
2030 expectedContentLength:[JSData length]
2031 textEncodingName:nil]);
2033 stream->startStreamWithResponse(response.get());
2034 stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]);
2035 stream->didFinishLoading(0);
2039 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason
2043 WebPluginRequest *pluginRequest = [_pendingFrameLoads.get() objectForKey:webFrame];
2044 ASSERT(pluginRequest != nil);
2045 ASSERT([pluginRequest sendNotification]);
2047 [self willCallPlugInFunction];
2049 JSC::JSLock::DropAllLocks dropAllLocks(false);
2050 NPP_URLNotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]);
2052 [self didCallPlugInFunction];
2054 [_pendingFrameLoads.get() removeObjectForKey:webFrame];
2055 [webFrame _setInternalLoadDelegate:nil];
2058 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error
2060 NPReason reason = NPRES_DONE;
2062 reason = WebNetscapePluginStream::reasonForError(error);
2063 [self webFrame:webFrame didFinishLoadWithReason:reason];
2066 - (void)loadPluginRequest:(WebPluginRequest *)pluginRequest
2068 NSURLRequest *request = [pluginRequest request];
2069 NSString *frameName = [pluginRequest frameName];
2070 WebFrame *frame = nil;
2072 NSURL *URL = [request URL];
2073 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
2075 ASSERT(frameName || JSString);
2078 // FIXME - need to get rid of this window creation which
2079 // bypasses normal targeted link handling
2080 frame = kit(core([self webFrame])->loader()->findFrameForNavigation(frameName));
2082 WebView *currentWebView = [self webView];
2083 NSDictionary *features = [[NSDictionary alloc] init];
2084 WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
2085 createWebViewWithRequest:nil
2086 windowFeatures:features];
2090 if ([pluginRequest sendNotification]) {
2091 [self willCallPlugInFunction];
2093 JSC::JSLock::DropAllLocks dropAllLocks(false);
2094 NPP_URLNotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]);
2096 [self didCallPlugInFunction];
2101 frame = [newWebView mainFrame];
2102 core(frame)->tree()->setName(frameName);
2103 [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
2108 ASSERT(frame == nil || [self webFrame] == frame);
2109 [self evaluateJavaScriptPluginRequest:pluginRequest];
2111 [frame loadRequest:request];
2112 if ([pluginRequest sendNotification]) {
2113 // Check if another plug-in view or even this view is waiting for the frame to load.
2114 // If it is, tell it that the load was cancelled because it will be anyway.
2115 WebBaseNetscapePluginView *view = [frame _internalLoadDelegate];
2117 ASSERT([view isKindOfClass:[WebBaseNetscapePluginView class]]);
2118 [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK];
2120 [_pendingFrameLoads.get() _webkit_setObject:pluginRequest forUncopiedKey:frame];
2121 [frame _setInternalLoadDelegate:self];
2126 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification
2128 NSURL *URL = [request URL];
2131 return NPERR_INVALID_URL;
2133 // Don't allow requests to be loaded when the document loader is stopping all loaders.
2134 if ([[self dataSource] _documentLoader]->isStopping())
2135 return NPERR_GENERIC_ERROR;
2137 NSString *target = nil;
2139 // Find the frame given the target string.
2140 target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding];
2142 WebFrame *frame = [self webFrame];
2144 // don't let a plugin start any loads if it is no longer part of a document that is being
2145 // displayed unless the loads are in the same frame as the plugin.
2146 if ([[self dataSource] _documentLoader] != core([self webFrame])->loader()->activeDocumentLoader() &&
2147 (!cTarget || [frame findFrameNamed:target] != frame)) {
2148 return NPERR_GENERIC_ERROR;
2151 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
2152 if (JSString != nil) {
2153 if (![[[self webView] preferences] isJavaScriptEnabled]) {
2154 // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
2155 return NPERR_GENERIC_ERROR;
2156 } else if (cTarget == NULL && _mode == NP_FULL) {
2157 // Don't allow a JavaScript request from a standalone plug-in that is self-targetted
2158 // because this can cause the user to be redirected to a blank page (3424039).
2159 return NPERR_INVALID_PARAM;
2162 if (!FrameLoader::canLoad(URL, String(), core([self webFrame])->document()))
2163 return NPERR_GENERIC_ERROR;
2166 if (cTarget || JSString) {
2167 // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
2168 // want to potentially kill the plug-in inside of its URL request.
2170 if (JSString && target && [frame findFrameNamed:target] != frame) {
2171 // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
2172 return NPERR_INVALID_PARAM;
2175 bool currentEventIsUserGesture = false;
2177 currentEventIsUserGesture = _eventHandler->currentEventIsUserGesture();
2179 WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request
2181 notifyData:notifyData
2182 sendNotification:sendNotification
2183 didStartFromUserGesture:currentEventIsUserGesture];
2184 [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0];
2185 [pluginRequest release];
2187 RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create(request, plugin, sendNotification, notifyData);
2189 streams.add(stream.get());
2193 return NPERR_NO_ERROR;
2196 -(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData
2198 LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget);
2200 NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
2201 return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES];
2204 -(NPError)getURL:(const char *)URLCString target:(const char *)cTarget
2206 LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget);
2208 NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
2209 return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO];
2212 - (NPError)_postURL:(const char *)URLCString
2213 target:(const char *)target
2215 buf:(const char *)buf
2217 notifyData:(void *)notifyData
2218 sendNotification:(BOOL)sendNotification
2219 allowHeaders:(BOOL)allowHeaders
2221 if (!URLCString || !len || !buf) {
2222 return NPERR_INVALID_PARAM;
2225 NSData *postData = nil;
2228 // If we're posting a file, buf is either a file URL or a path to the file.
2229 NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1);
2231 return NPERR_INVALID_PARAM;
2233 NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString];
2235 if ([fileURL isFileURL]) {
2236 path = [fileURL path];
2240 postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
2241 CFRelease(bufString);
2243 return NPERR_FILE_NOT_FOUND;
2246 postData = [NSData dataWithBytes:buf length:len];
2249 if ([postData length] == 0) {
2250 return NPERR_INVALID_PARAM;
2253 NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
2254 [request setHTTPMethod:@"POST"];
2257 if ([postData _web_startsWithBlankLine]) {
2258 postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)];
2260 NSInteger location = [postData _web_locationAfterFirstBlankLine];
2261 if (location != NSNotFound) {
2262 // If the blank line is somewhere in the middle of postData, everything before is the header.
2263 NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)];
2264 NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
2265 unsigned dataLength = [postData length] - location;
2267 // Sometimes plugins like to set Content-Length themselves when they post,
2268 // but WebFoundation does not like that. So we will remove the header
2269 // and instead truncate the data to the requested length.
2270 NSString *contentLength = [header objectForKey:@"Content-Length"];
2272 if (contentLength != nil)
2273 dataLength = MIN((unsigned)[contentLength intValue], dataLength);
2274 [header removeObjectForKey:@"Content-Length"];
2276 if ([header count] > 0) {
2277 [request setAllHTTPHeaderFields:header];
2279 // Everything after the blank line is the actual content of the POST.
2280 postData = [postData subdataWithRange:NSMakeRange(location, dataLength)];
2284 if ([postData length] == 0) {
2285 return NPERR_INVALID_PARAM;
2289 // Plug-ins expect to receive uncached data when doing a POST (3347134).
2290 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
2291 [request setHTTPBody:postData];
2293 return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification];
2296 - (NPError)postURLNotify:(const char *)URLCString
2297 target:(const char *)target
2299 buf:(const char *)buf
2301 notifyData:(void *)notifyData
2303 LOG(Plugins, "NPN_PostURLNotify: %s", URLCString);
2304 return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES];
2307 -(NPError)postURL:(const char *)URLCString
2308 target:(const char *)target
2310 buf:(const char *)buf
2313 LOG(Plugins, "NPN_PostURL: %s", URLCString);
2314 // As documented, only allow headers to be specified via NPP_PostURL when using a file.
2315 return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file];
2318 -(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream
2320 LOG(Plugins, "NPN_NewStream");
2321 return NPERR_GENERIC_ERROR;
2324 -(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer
2326 LOG(Plugins, "NPN_Write");
2327 return NPERR_GENERIC_ERROR;
2330 -(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason
2332 LOG(Plugins, "NPN_DestroyStream");
2333 // This function does a sanity check to ensure that the NPStream provided actually
2334 // belongs to the plug-in that provided it, which fixes a crash in the DivX
2335 // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203
2336 if (!stream || WebNetscapePluginStream::ownerForStream(stream) != plugin) {
2337 LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream);
2338 return NPERR_INVALID_INSTANCE_ERROR;
2341 WebNetscapePluginStream* browserStream = static_cast<WebNetscapePluginStream*>(stream->ndata);
2342 browserStream->cancelLoadAndDestroyStreamWithError(browserStream->errorForReason(reason));
2344 return NPERR_NO_ERROR;
2347 - (const char *)userAgent
2349 return [[[self webView] userAgentForURL:_baseURL.get()] UTF8String];
2352 -(void)status:(const char *)message
2355 LOG_ERROR("NPN_Status passed a NULL status message");
2359 CFStringRef status = CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8);
2361 LOG_ERROR("NPN_Status: the message was not valid UTF-8");
2365 LOG(Plugins, "NPN_Status: %@", status);
2366 WebView *wv = [self webView];
2367 [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status];
2371 -(void)invalidateRect:(NPRect *)invalidRect
2373 LOG(Plugins, "NPN_InvalidateRect");
2374 [self setNeedsDisplayInRect:NSMakeRect(invalidRect->left, invalidRect->top,
2375 (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)];
2383 - (void)invalidateRegion:(NPRegion)invalidRegion
2385 LOG(Plugins, "NPN_InvalidateRegion");
2386 NSRect invalidRect = NSZeroRect;
2387 switch (drawingModel) {
2388 #ifndef NP_NO_QUICKDRAW
2389 case NPDrawingModelQuickDraw:
2392 GetRegionBounds((NPQDRegion)invalidRegion, &qdRect);
2393 invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top);
2396 #endif /* NP_NO_QUICKDRAW */
2398 case NPDrawingModelCoreGraphics:
2400 CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion);
2401 invalidRect = *(NSRect*)&cgRect;
2405 ASSERT_NOT_REACHED();
2409 [self setNeedsDisplayInRect:invalidRect];
2414 LOG(Plugins, "forceRedraw");
2415 [self setNeedsDisplay:YES];
2416 [[self window] displayIfNeeded];
2419 static NPBrowserTextInputFuncs *browserTextInputFuncs()
2421 static NPBrowserTextInputFuncs inputFuncs = {
2423 sizeof(NPBrowserTextInputFuncs),
2424 NPN_MarkedTextAbandoned,
2425 NPN_MarkedTextSelectionChanged
2431 - (NPError)getVariable:(NPNVariable)variable value:(void *)value
2434 case NPNVWindowNPObject:
2436 Frame* frame = core([self webFrame]);
2437 NPObject* windowScriptObject = frame ? frame->script()->windowScriptNPObject() : 0;
2439 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
2440 if (windowScriptObject)
2441 _NPN_RetainObject(windowScriptObject);
2443 void **v = (void **)value;
2444 *v = windowScriptObject;
2446 return NPERR_NO_ERROR;
2449 case NPNVPluginElementNPObject:
2452 return NPERR_GENERIC_ERROR;
2454 NPObject *plugInScriptObject = (NPObject *)[_element.get() _NPObject];
2456 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
2457 if (plugInScriptObject)
2458 _NPN_RetainObject(plugInScriptObject);
2460 void **v = (void **)value;
2461 *v = plugInScriptObject;
2463 return NPERR_NO_ERROR;
2466 case NPNVpluginDrawingModel:
2468 *(NPDrawingModel *)value = drawingModel;
2469 return NPERR_NO_ERROR;
2472 #ifndef NP_NO_QUICKDRAW
2473 case NPNVsupportsQuickDrawBool:
2475 *(NPBool *)value = TRUE;
2476 return NPERR_NO_ERROR;
2478 #endif /* NP_NO_QUICKDRAW */
2480 case NPNVsupportsCoreGraphicsBool:
2482 *(NPBool *)value = TRUE;
2483 return NPERR_NO_ERROR;
2486 case NPNVsupportsOpenGLBool:
2488 *(NPBool *)value = FALSE;
2489 return NPERR_NO_ERROR;
2492 case NPNVsupportsCoreAnimationBool:
2494 #ifdef BUILDING_ON_TIGER
2495 *(NPBool *)value = FALSE;
2497 *(NPBool *)value = TRUE;
2499 return NPERR_NO_ERROR;
2502 #ifndef NP_NO_CARBON
2503 case NPNVsupportsCarbonBool:
2505 *(NPBool *)value = TRUE;
2506 return NPERR_NO_ERROR;
2508 #endif /* NP_NO_CARBON */
2510 case NPNVsupportsCocoaBool:
2512 *(NPBool *)value = TRUE;
2513 return NPERR_NO_ERROR;
2516 case NPNVbrowserTextInputFuncs:
2518 if (eventModel == NPEventModelCocoa) {
2519 *(NPBrowserTextInputFuncs **)value = browserTextInputFuncs();
2520 return NPERR_NO_ERROR;
2527 return NPERR_GENERIC_ERROR;
2530 - (NPError)setVariable:(NPPVariable)variable value:(void *)value
2533 case NPPVpluginDrawingModel:
2535 // Can only set drawing model inside NPP_New()
2536 if (self != [[self class] currentPluginView])
2537 return NPERR_GENERIC_ERROR;
2539 // Check for valid, supported drawing model
2540 NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value;
2541 switch (newDrawingModel) {
2542 // Supported drawing models:
2543 #ifndef NP_NO_QUICKDRAW
2544 case NPDrawingModelQuickDraw:
2546 case NPDrawingModelCoreGraphics:
2547 #ifndef BUILDING_ON_TIGER
2548 case NPDrawingModelCoreAnimation:
2550 drawingModel = newDrawingModel;
2551 return NPERR_NO_ERROR;
2554 // Unsupported (or unknown) drawing models:
2556 LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", _eventHandler.get(), drawingModel);
2557 return NPERR_GENERIC_ERROR;
2561 case NPPVpluginEventModel:
2563 // Can only set event model inside NPP_New()
2564 if (self != [[self class] currentPluginView])
2565 return NPERR_GENERIC_ERROR;
2567 // Check for valid, supported event model
2568 NPEventModel newEventModel = (NPEventModel)(uintptr_t)value;
2569 switch (newEventModel) {
2570 // Supported event models:
2571 #ifndef NP_NO_CARBON
2572 case NPEventModelCarbon:
2574 case NPEventModelCocoa:
2575 eventModel = newEventModel;
2576 return NPERR_NO_ERROR;
2578 // Unsupported (or unknown) event models:
2580 LOG(Plugins, "Plugin %@ uses unsupported event model: %d", _eventHandler.get(), eventModel);
2581 return NPERR_GENERIC_ERROR;
2586 return NPERR_GENERIC_ERROR;
2590 - (uint32)scheduleTimerWithInterval:(uint32)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32 timerID))timerFunc
2596 timers = new HashMap<uint32, PluginTimer*>;
2598 uint32 timerID = ++currentTimerID;
2600 PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc);
2601 timers->set(timerID, timer);
2603 if (shouldFireTimers)
2604 timer->start(isCompletelyObscured);
2609 - (void)unscheduleTimer:(uint32)timerID
2614 if (PluginTimer* timer = timers->take(timerID))
2618 - (NPError)popUpContextMenu:(NPMenu *)menu
2620 NSEvent *currentEvent = [NSApp currentEvent];
2622 // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent.
2624 return NPERR_GENERIC_ERROR;
2626 [NSMenu popUpContextMenu:(NSMenu *)menu withEvent:currentEvent forView:self];
2627 return NPERR_NO_ERROR;
2632 @implementation WebPluginRequest
2634 - (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture
2637 _didStartFromUserGesture = currentEventIsUserGesture;
2638 _request = [request retain];
2639 _frameName = [frameName retain];
2640 _notifyData = notifyData;
2641 _sendNotification = sendNotification;
2648 [_frameName release];
2652 - (NSURLRequest *)request
2657 - (NSString *)frameName
2662 - (BOOL)isCurrentEventUserGesture
2664 return _didStartFromUserGesture;
2667 - (BOOL)sendNotification
2669 return _sendNotification;
2672 - (void *)notifyData
2679 @implementation WebBaseNetscapePluginView (Internal)
2681 - (NPError)_createPlugin
2683 plugin = (NPP)calloc(1, sizeof(NPP_t));
2684 plugin->ndata = self;
2688 // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance.
2689 ASSERT(pluginFunctionCallDepth == 0);
2691 Frame* frame = core([self webFrame]);
2693 return NPERR_GENERIC_ERROR;
2694 Page* page = frame->page();
2696 return NPERR_GENERIC_ERROR;
2698 bool wasDeferring = page->defersLoading();
2700 page->setDefersLoading(true);
2702 PluginMainThreadScheduler::scheduler().registerPlugin(plugin);
2704 [[self class] setCurrentPluginView:self];
2705 NPError npErr = NPP_New((char *)[_MIMEType.get() cString], plugin, _mode, argsCount, cAttributes, cValues, NULL);
2706 [[self class] setCurrentPluginView:nil];
2709 page->setDefersLoading(false);
2711 LOG(Plugins, "NPP_New: %d", npErr);
2715 - (void)_destroyPlugin
2717 PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin);
2720 npErr = NPP_Destroy(plugin, NULL);
2721 LOG(Plugins, "NPP_Destroy: %d", npErr);
2723 if (Frame* frame = core([self webFrame]))
2724 frame->script()->cleanupScriptObjectsForPlugin(self);
2730 - (void)_viewHasMoved
2732 // All of the work this method does may safely be skipped if the view is not in a window. When the view
2733 // is moved back into a window, everything should be set up correctly.
2737 if (isDrawingModelQuickDraw(drawingModel))
2738 [self tellQuickTimeToChill];
2740 if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel))
2741 [self updateAndSetWindow];
2743 [self resetTrackingRect];
2745 // Check to see if the plugin view is completely obscured (scrolled out of view, for example).
2746 // For performance reasons, we send null events at a lower rate to plugins which are obscured.
2747 BOOL oldIsObscured = isCompletelyObscured;
2748 isCompletelyObscured = NSIsEmptyRect([self visibleRect]);
2749 if (isCompletelyObscured != oldIsObscured)
2750 [self restartTimers];
2753 - (NSBitmapImageRep *)_printedPluginBitmap
2755 #ifdef NP_NO_QUICKDRAW
2758 // Cannot print plugins that do not implement NPP_Print
2762 // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into.
2763 // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format.
2764 NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
2765 pixelsWide:window.width
2766 pixelsHigh:window.height
2771 colorSpaceName:NSDeviceRGBColorSpace
2772 bitmapFormat:NSAlphaFirstBitmapFormat
2774 bitsPerPixel:0] autorelease];
2777 // Create a GWorld with the same underlying buffer into which the plugin can draw
2778 ::Rect printGWorldBounds;
2779 SetRect(&printGWorldBounds, 0, 0, window.width, window.height);
2780 GWorldPtr printGWorld;
2781 if (NewGWorldFromPtr(&printGWorld,
2787 (Ptr)[bitmap bitmapData],
2788 [bitmap bytesPerRow]) != noErr) {
2789 LOG_ERROR("Could not create GWorld for printing");
2793 /// Create NPWindow for the GWorld
2794 NPWindow printNPWindow;
2795 printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr
2796 printNPWindow.x = 0;
2797 printNPWindow.y = 0;
2798 printNPWindow.width = window.width;
2799 printNPWindow.height = window.height;
2800 printNPWindow.clipRect.top = 0;
2801 printNPWindow.clipRect.left = 0;
2802 printNPWindow.clipRect.right = window.width;
2803 printNPWindow.clipRect.bottom = window.height;
2804 printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window
2806 // Create embed-mode NPPrint
2808 npPrint.mode = NP_EMBED;
2809 npPrint.print.embedPrint.window = printNPWindow;
2810 npPrint.print.embedPrint.platformPrint = printGWorld;
2812 // Tell the plugin to print into the GWorld
2813 [self willCallPlugInFunction];
2815 JSC::JSLock::DropAllLocks dropAllLocks(false);
2816 NPP_Print(plugin, &npPrint);
2818 [self didCallPlugInFunction];
2820 // Don't need the GWorld anymore
2821 DisposeGWorld(printGWorld);
2827 - (void)_redeliverStream
2829 if ([self dataSource] && [self isStarted]) {
2830 // Deliver what has not been passed to the plug-in up to this point.
2831 if (_dataLengthReceived > 0) {
2832 NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)];
2833 _dataLengthReceived = 0;
2834 [self pluginView:self receivedData:data];
2835 if (![[self dataSource] isLoading]) {
2837 [self pluginView:self receivedError:_error.get()];
2839 [self pluginViewFinishedLoading:self];
2847 @implementation NSData (PluginExtras)
2849 - (BOOL)_web_startsWithBlankLine
2851 return [self length] > 0 && ((const char *)[self bytes])[0] == '\n';
2855 - (NSInteger)_web_locationAfterFirstBlankLine
2857 const char *bytes = (const char *)[self bytes];
2858 unsigned length = [self length];
2861 for (i = 0; i < length - 4; i++) {
2863 // Support for Acrobat. It sends "\n\n".
2864 if (bytes[i] == '\n' && bytes[i+1] == '\n') {
2868 // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
2869 if (bytes[i] == '\r' && bytes[i+1] == '\n') {
2873 } else if (bytes[i] == '\n') {
2874 // Support for Director. It sends "\r\n\n" (3880387).
2876 } else if (bytes[i] == '\r' && bytes[i+1] == '\n') {
2877 // Support for Flash. It sends "\r\n\r\n" (3758113).