Remove some dead code.
[WebKit-https.git] / Source / WebKit / mac / Plugins / WebBaseNetscapePluginView.mm
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #if ENABLE(NETSCAPE_PLUGIN_API)
30
31 #import "WebBaseNetscapePluginView.h"
32
33 #import "WebFrameInternal.h"
34 #import "WebKitLogging.h"
35 #import "WebKitNSStringExtras.h"
36 #import "WebKitSystemInterface.h"
37 #import "WebPluginContainerCheck.h"
38 #import "WebNetscapeContainerCheckContextInfo.h"
39 #import "WebNSURLExtras.h"
40 #import "WebNSURLRequestExtras.h"
41 #import "WebView.h"
42 #import "WebViewInternal.h"
43
44 #import <WebCore/AuthenticationMac.h>
45 #import <WebCore/BitmapImage.h>
46 #import <WebCore/Credential.h>
47 #import <WebCore/CredentialStorage.h>
48 #import <WebCore/Document.h>
49 #import <WebCore/Element.h>
50 #import <WebCore/Frame.h>
51 #import <WebCore/FrameLoader.h>
52 #import <WebCore/HTMLPlugInElement.h>
53 #import <WebCore/HaltablePlugin.h>
54 #import <WebCore/Page.h>
55 #import <WebCore/ProtectionSpace.h>
56 #import <WebCore/RenderView.h>
57 #import <WebCore/RenderWidget.h>
58 #import <WebCore/WebCoreObjCExtras.h>
59 #import <WebKit/DOMPrivate.h>
60 #import <runtime/InitializeThreading.h>
61 #import <wtf/Assertions.h>
62 #import <wtf/Threading.h>
63 #import <wtf/text/CString.h>
64
65 #define LoginWindowDidSwitchFromUserNotification    @"WebLoginWindowDidSwitchFromUserNotification"
66 #define LoginWindowDidSwitchToUserNotification      @"WebLoginWindowDidSwitchToUserNotification"
67
68 static const NSTimeInterval ClearSubstituteImageDelay = 0.5;
69
70 using namespace WebCore;
71
72 class WebHaltablePlugin : public HaltablePlugin {
73 public:
74     WebHaltablePlugin(WebBaseNetscapePluginView* view)
75         : m_view(view)
76     {
77     }
78     
79 private:
80     virtual void halt();
81     virtual void restart();
82     virtual Node* node() const;
83     virtual bool isWindowed() const;
84     virtual String pluginName() const;
85
86     WebBaseNetscapePluginView* m_view;
87 };
88
89 void WebHaltablePlugin::halt()
90 {
91     [m_view halt];
92 }
93
94 void WebHaltablePlugin::restart()
95
96     [m_view resumeFromHalt];
97 }
98     
99 Node* WebHaltablePlugin::node() const
100 {
101     return [m_view element];
102 }
103
104 bool WebHaltablePlugin::isWindowed() const
105 {
106     return false;
107 }
108
109 String WebHaltablePlugin::pluginName() const
110 {
111     return [[m_view pluginPackage] pluginInfo].name;
112 }
113
114 @implementation WebBaseNetscapePluginView
115
116 + (void)initialize
117 {
118     JSC::initializeThreading();
119     WTF::initializeMainThreadToProcessMainThread();
120     WebCoreObjCFinalizeOnMainThread(self);
121     WKSendUserChangeNotifications();
122 }
123
124 - (id)initWithFrame:(NSRect)frame
125       pluginPackage:(WebNetscapePluginPackage *)pluginPackage
126                 URL:(NSURL *)URL
127             baseURL:(NSURL *)baseURL
128            MIMEType:(NSString *)MIME
129       attributeKeys:(NSArray *)keys
130     attributeValues:(NSArray *)values
131        loadManually:(BOOL)loadManually
132             element:(PassRefPtr<WebCore::HTMLPlugInElement>)element
133 {
134     self = [super initWithFrame:frame];
135     if (!self)
136         return nil;
137     
138     _pluginPackage = pluginPackage;
139     _element = element;
140     _sourceURL.adoptNS([URL copy]);
141     _baseURL.adoptNS([baseURL copy]);
142     _MIMEType.adoptNS([MIME copy]);
143     
144 #ifndef BUILDING_ON_LEOPARD
145     // Enable "kiosk mode" when instantiating the QT plug-in inside of Dashboard. See <rdar://problem/6878105>
146     if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.dashboard.client"] &&
147         [_pluginPackage.get() bundleIdentifier] == "com.apple.QuickTime Plugin.plugin") {
148         RetainPtr<NSMutableArray> mutableKeys(AdoptNS, [keys mutableCopy]);
149         RetainPtr<NSMutableArray> mutableValues(AdoptNS, [values mutableCopy]);
150
151         [mutableKeys.get() addObject:@"kioskmode"];
152         [mutableValues.get() addObject:@"true"];
153         [self setAttributeKeys:mutableKeys.get() andValues:mutableValues.get()];
154     } else
155 #endif
156          [self setAttributeKeys:keys andValues:values];
157
158     if (loadManually)
159         _mode = NP_FULL;
160     else
161         _mode = NP_EMBED;
162     
163     _loadManually = loadManually;
164     _haltable = new WebHaltablePlugin(self);
165     return self;
166 }
167
168 - (void)dealloc
169 {
170     ASSERT(!_isStarted);
171
172     [super dealloc];
173 }
174
175 - (void)finalize
176 {
177     ASSERT_MAIN_THREAD();
178     ASSERT(!_isStarted);
179
180     [super finalize];
181 }
182
183 - (WebNetscapePluginPackage *)pluginPackage
184 {
185     return _pluginPackage.get();
186 }
187     
188 - (BOOL)isFlipped
189 {
190     return YES;
191 }
192
193 - (NSURL *)URLWithCString:(const char *)URLCString
194 {
195     if (!URLCString)
196         return nil;
197     
198     CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, URLCString, kCFStringEncodingISOLatin1);
199     ASSERT(string); // All strings should be representable in ISO Latin 1
200     
201     NSString *URLString = [(NSString *)string _web_stringByStrippingReturnCharacters];
202     NSURL *URL = [NSURL _web_URLWithDataAsString:URLString relativeToURL:_baseURL.get()];
203     CFRelease(string);
204     if (!URL)
205         return nil;
206     
207     return URL;
208 }
209
210 - (NSMutableURLRequest *)requestWithURLCString:(const char *)URLCString
211 {
212     NSURL *URL = [self URLWithCString:URLCString];
213     if (!URL)
214         return nil;
215     
216     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
217     Frame* frame = core([self webFrame]);
218     if (!frame)
219         return nil;
220     [request _web_setHTTPReferrer:frame->loader()->outgoingReferrer()];
221     return request;
222 }
223
224 // Methods that subclasses must override
225 - (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values
226 {
227     ASSERT_NOT_REACHED();
228 }
229
230 - (void)handleMouseMoved:(NSEvent *)event
231 {
232     ASSERT_NOT_REACHED();
233 }
234
235 - (void)handleMouseEntered:(NSEvent *)event
236 {
237     ASSERT_NOT_REACHED();
238 }
239
240 - (void)handleMouseExited:(NSEvent *)event
241 {
242     ASSERT_NOT_REACHED();
243 }
244
245 - (void)focusChanged
246 {
247     ASSERT_NOT_REACHED();
248 }
249
250 - (void)windowFocusChanged:(BOOL)hasFocus
251 {
252     ASSERT_NOT_REACHED();
253 }
254
255 - (BOOL)createPlugin
256 {
257     ASSERT_NOT_REACHED();
258     return NO;
259 }
260
261 - (void)loadStream
262 {
263     ASSERT_NOT_REACHED();
264 }
265
266 - (BOOL)shouldStop
267 {
268     ASSERT_NOT_REACHED();
269     return YES;
270 }
271
272 - (void)destroyPlugin
273 {
274     ASSERT_NOT_REACHED();
275 }
276
277 - (void)updateAndSetWindow
278 {
279     ASSERT_NOT_REACHED();
280 }
281
282 - (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character
283 {
284     ASSERT_NOT_REACHED();
285 }
286
287 - (void)privateBrowsingModeDidChange
288 {
289 }
290
291 - (void)removeTrackingRect
292 {
293     if (_trackingTag) {
294         [self removeTrackingRect:_trackingTag];
295         _trackingTag = 0;
296         
297         // Do the following after setting trackingTag to 0 so we don't re-enter.
298         
299         // Balance the retain in resetTrackingRect. Use autorelease in case we hold 
300         // the last reference to the window during tear-down, to avoid crashing AppKit. 
301         [[self window] autorelease];
302     }
303 }
304
305 - (void)resetTrackingRect
306 {
307     [self removeTrackingRect];
308     if (_isStarted) {
309         // Retain the window so that removeTrackingRect can work after the window is closed.
310         [[self window] retain];
311         _trackingTag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO];
312     }
313 }
314
315 - (void)stopTimers
316 {
317     _shouldFireTimers = NO;
318 }
319
320 - (void)startTimers
321 {
322     _shouldFireTimers = YES;
323 }
324
325 - (void)restartTimers
326 {
327     [self stopTimers];
328     
329     if (!_isStarted || [[self window] isMiniaturized])
330         return;
331     
332     [self startTimers];
333 }
334
335 - (NSRect)_windowClipRect
336 {
337     RenderObject* renderer = _element->renderer();
338     if (!renderer || !renderer->view())
339         return NSZeroRect;
340
341     return toRenderWidget(renderer)->windowClipRect();
342 }
343
344 - (NSRect)visibleRect
345 {
346     // WebCore may impose an additional clip (via CSS overflow or clip properties).  Fetch
347     // that clip now.    
348     return NSIntersectionRect([self convertRect:[self _windowClipRect] fromView:nil], [super visibleRect]);
349 }
350
351 - (void)visibleRectDidChange
352 {
353     [self renewGState];
354 }
355
356 - (BOOL)acceptsFirstResponder
357 {
358     return YES;
359 }
360
361 - (void)sendActivateEvent:(BOOL)activate
362 {
363     if (!_isStarted)
364         return;
365     
366     [self windowFocusChanged:activate];
367 }
368
369 - (void)setHasFocus:(BOOL)flag
370 {
371     if (!_isStarted)
372         return;
373     
374     if (_hasFocus == flag)
375         return;
376     
377     _hasFocus = flag;
378     
379     [self focusChanged];
380 }
381
382 - (void)addWindowObservers
383 {
384     ASSERT([self window]);
385     
386     NSWindow *theWindow = [self window];
387     
388     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
389     [notificationCenter addObserver:self selector:@selector(windowWillClose:) 
390                                name:NSWindowWillCloseNotification object:theWindow]; 
391     [notificationCenter addObserver:self selector:@selector(windowBecameKey:)
392                                name:NSWindowDidBecomeKeyNotification object:theWindow];
393     [notificationCenter addObserver:self selector:@selector(windowResignedKey:)
394                                name:NSWindowDidResignKeyNotification object:theWindow];
395     [notificationCenter addObserver:self selector:@selector(windowDidMiniaturize:)
396                                name:NSWindowDidMiniaturizeNotification object:theWindow];
397     [notificationCenter addObserver:self selector:@selector(windowDidDeminiaturize:)
398                                name:NSWindowDidDeminiaturizeNotification object:theWindow];
399     
400     [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchFromUser:)
401                                name:LoginWindowDidSwitchFromUserNotification object:nil];
402     [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchToUser:)
403                                name:LoginWindowDidSwitchToUserNotification object:nil];
404 }
405
406 - (void)removeWindowObservers
407 {
408     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
409     [notificationCenter removeObserver:self name:NSWindowWillCloseNotification        object:nil]; 
410     [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification     object:nil];
411     [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification     object:nil];
412     [notificationCenter removeObserver:self name:NSWindowDidMiniaturizeNotification   object:nil];
413     [notificationCenter removeObserver:self name:NSWindowDidDeminiaturizeNotification object:nil];
414     [notificationCenter removeObserver:self name:LoginWindowDidSwitchFromUserNotification   object:nil];
415     [notificationCenter removeObserver:self name:LoginWindowDidSwitchToUserNotification     object:nil];
416 }
417
418 - (void)start
419 {
420     ASSERT([self currentWindow]);
421     
422     if (_isStarted)
423         return;
424     
425     if (_triedAndFailedToCreatePlugin)
426         return;
427     
428     ASSERT([self webView]);
429     
430     if (![[[self webView] preferences] arePlugInsEnabled])
431         return;
432    
433     Frame* frame = core([self webFrame]);
434     if (!frame)
435         return;
436     Page* page = frame->page();
437     if (!page)
438         return;
439     
440     bool wasDeferring = page->defersLoading();
441     if (!wasDeferring)
442         page->setDefersLoading(true);
443
444     BOOL result = [self createPlugin];
445     
446     if (!wasDeferring)
447         page->setDefersLoading(false);
448
449     if (!result) {
450         _triedAndFailedToCreatePlugin = YES;
451         return;
452     }
453     
454     _isStarted = YES;
455     page->didStartPlugin(_haltable.get());
456
457     [[self webView] addPluginInstanceView:self];
458
459     if ([self currentWindow])
460         [self updateAndSetWindow];
461
462     if ([self window]) {
463         [self addWindowObservers];
464         if ([[self window] isKeyWindow]) {
465             [self sendActivateEvent:YES];
466         }
467         [self restartTimers];
468     }
469     
470     [self resetTrackingRect];
471     
472     [self loadStream];
473 }
474
475 - (void)stop
476 {
477     if (![self shouldStop])
478         return;
479     
480     [self removeTrackingRect];
481     
482     if (!_isStarted)
483         return;
484
485     if (Frame* frame = core([self webFrame])) {
486         if (Page* page = frame->page())
487             page->didStopPlugin(_haltable.get());
488     }
489     
490     _isStarted = NO;
491     
492     [[self webView] removePluginInstanceView:self];
493     
494     // Stop the timers
495     [self stopTimers];
496     
497     // Stop notifications and callbacks.
498     [self removeWindowObservers];
499     
500     [self destroyPlugin];
501 }
502
503 - (void)halt
504 {
505     ASSERT(!_isHalted);
506     ASSERT(_isStarted);
507     Element *element = [self element];
508 #ifndef BUILDING_ON_LEOPARD
509     CGImageRef cgImage = CGImageRetain([core([self webFrame])->nodeImage(element).get() CGImageForProposedRect:nil context:nil hints:nil]);
510 #else
511     RetainPtr<CGImageSourceRef> imageRef(AdoptCF, CGImageSourceCreateWithData((CFDataRef)[core([self webFrame])->nodeImage(element).get() TIFFRepresentation], 0));
512     CGImageRef cgImage = CGImageSourceCreateImageAtIndex(imageRef.get(), 0, 0);
513 #endif
514     ASSERT(cgImage);
515     
516     // BitmapImage will release the passed in CGImage on destruction.
517     RefPtr<Image> nodeImage = BitmapImage::create(cgImage);
518     ASSERT(element->renderer());
519     toRenderWidget(element->renderer())->showSubstituteImage(nodeImage);
520     [self stop];
521     _isHalted = YES;  
522     _hasBeenHalted = YES;
523 }
524
525 - (void)_clearSubstituteImage
526 {
527     Element* element = [self element];
528     if (!element)
529         return;
530     
531     RenderObject* renderer = element->renderer();
532     if (!renderer)
533         return;
534     
535     toRenderWidget(renderer)->showSubstituteImage(0);
536 }
537
538 - (void)resumeFromHalt
539 {
540     ASSERT(_isHalted);
541     ASSERT(!_isStarted);
542     [self start];
543     
544     if (_isStarted)
545         _isHalted = NO;
546     
547     ASSERT([self element]->renderer());
548     // FIXME 7417484: This is a workaround for plug-ins not drawing immediately. We'd like to detect when the
549     // plug-in actually draws instead of just assuming it will do so within 0.5 seconds of being restarted.
550     [self performSelector:@selector(_clearSubstituteImage) withObject:nil afterDelay:ClearSubstituteImageDelay];
551 }
552
553 - (BOOL)isHalted
554 {
555     return _isHalted;
556 }
557
558 - (BOOL)shouldClipOutPlugin
559 {
560     NSWindow *window = [self window];
561     return !window || [window isMiniaturized] || [NSApp isHidden] || ![self isDescendantOf:[[self window] contentView]] || [self isHiddenOrHasHiddenAncestor];
562 }
563
564 - (BOOL)inFlatteningPaint
565 {
566     RenderObject* renderer = _element->renderer();
567     if (renderer && renderer->view()) {
568         if (FrameView* frameView = renderer->view()->frameView())
569             return frameView->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
570     }
571
572     return NO;
573 }
574
575 - (BOOL)supportsSnapshotting
576 {
577     return [_pluginPackage.get() supportsSnapshotting];
578 }
579
580 - (void)cacheSnapshot
581 {
582     NSImage *snapshot = [[NSImage alloc] initWithSize: [self bounds].size];
583     _snapshotting = YES;
584     [snapshot lockFocus];
585     [self drawRect:[self bounds]];
586     [snapshot unlockFocus];
587     _snapshotting = NO;
588     
589     _cachedSnapshot.adoptNS(snapshot);
590 }
591
592 - (void)clearCachedSnapshot
593 {
594     _cachedSnapshot.clear();
595 }
596
597 - (BOOL)hasBeenHalted
598 {
599     return _hasBeenHalted;
600 }
601
602 - (void)viewWillMoveToWindow:(NSWindow *)newWindow
603 {
604     // We must remove the tracking rect before we move to the new window.
605     // Once we move to the new window, it will be too late.
606     [self removeTrackingRect];
607     [self removeWindowObservers];
608     
609     // Workaround for: <rdar://problem/3822871> resignFirstResponder is not sent to first responder view when it is removed from the window
610     [self setHasFocus:NO];
611     
612     if (!newWindow) {
613         if ([[self webView] hostWindow]) {
614             // View will be moved out of the actual window but it still has a host window.
615             [self stopTimers];
616         } else {
617             // View will have no associated windows.
618             [self stop];
619             
620             // Stop observing WebPreferencesChangedInternalNotification -- we only need to observe this when installed in the view hierarchy.
621             // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed.
622             [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedInternalNotification object:nil];
623         }
624     }
625 }
626
627 - (void)viewWillMoveToSuperview:(NSView *)newSuperview
628 {
629     if (!newSuperview) {
630         // Stop the plug-in when it is removed from its superview.  It is not sufficient to do this in -viewWillMoveToWindow:nil, because
631         // the WebView might still has a hostWindow at that point, which prevents the plug-in from being destroyed.
632         // There is no need to start the plug-in when moving into a superview.  -viewDidMoveToWindow takes care of that.
633         [self stop];
634         
635         // Stop observing WebPreferencesChangedInternalNotification -- we only need to observe this when installed in the view hierarchy.
636         // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed.
637         [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedInternalNotification object:nil];
638     }
639 }
640
641 - (void)viewDidMoveToWindow
642 {
643     [self resetTrackingRect];
644     
645     if ([self window]) {
646         // While in the view hierarchy, observe WebPreferencesChangedInternalNotification so that we can start/stop depending
647         // on whether plugins are enabled.
648         [[NSNotificationCenter defaultCenter] addObserver:self
649                                                  selector:@selector(preferencesHaveChanged:)
650                                                      name:WebPreferencesChangedInternalNotification
651                                                    object:nil];
652
653         _isPrivateBrowsingEnabled = [[[self webView] preferences] privateBrowsingEnabled];
654         
655         // View moved to an actual window. Start it if not already started.
656         [self start];
657
658         // Starting the plug-in can result in it removing itself from the window so we need to ensure that we're still in
659         // place before doing anything that requires a window.
660         if ([self window]) {
661             [self restartTimers];
662             [self addWindowObservers];
663         }
664     } else if ([[self webView] hostWindow]) {
665         // View moved out of an actual window, but still has a host window.
666         // Call setWindow to explicitly "clip out" the plug-in from sight.
667         // FIXME: It would be nice to do this where we call stopNullEvents in viewWillMoveToWindow.
668         [self updateAndSetWindow];
669     }
670 }
671
672 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
673 {
674     if (!hostWindow && ![self window]) {
675         // View will have no associated windows.
676         [self stop];
677         
678         // Remove WebPreferencesChangedInternalNotification observer -- we will observe once again when we move back into the window
679         [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedInternalNotification object:nil];
680     }
681 }
682
683 - (void)viewDidMoveToHostWindow
684 {
685     if ([[self webView] hostWindow]) {
686         // View now has an associated window. Start it if not already started.
687         [self start];
688     }
689 }
690
691 // MARK: NOTIFICATIONS
692
693 - (void)windowWillClose:(NSNotification *)notification 
694 {
695     [self stop]; 
696
697
698 - (void)windowBecameKey:(NSNotification *)notification
699 {
700     [self sendActivateEvent:YES];
701     [self invalidatePluginContentRect:[self bounds]];
702     [self restartTimers];
703 }
704
705 - (void)windowResignedKey:(NSNotification *)notification
706 {
707     [self sendActivateEvent:NO];
708     [self invalidatePluginContentRect:[self bounds]];
709     [self restartTimers];
710 }
711
712 - (void)windowDidMiniaturize:(NSNotification *)notification
713 {
714     [self stopTimers];
715 }
716
717 - (void)windowDidDeminiaturize:(NSNotification *)notification
718 {
719     [self restartTimers];
720 }
721
722 - (void)loginWindowDidSwitchFromUser:(NSNotification *)notification
723 {
724     [self stopTimers];
725 }
726
727 -(void)loginWindowDidSwitchToUser:(NSNotification *)notification
728 {
729     [self restartTimers];
730 }
731
732 - (void)preferencesHaveChanged:(NSNotification *)notification
733 {
734     WebPreferences *preferences = [[self webView] preferences];
735
736     if ([notification object] != preferences)
737         return;
738     
739     BOOL arePlugInsEnabled = [preferences arePlugInsEnabled];
740     if (_isStarted != arePlugInsEnabled) {
741         if (arePlugInsEnabled) {
742             if ([self currentWindow]) {
743                 [self start];
744             }
745         } else {
746             [self stop];
747             [self invalidatePluginContentRect:[self bounds]];
748         }
749     }
750     
751     BOOL isPrivateBrowsingEnabled = [preferences privateBrowsingEnabled];
752     if (isPrivateBrowsingEnabled != _isPrivateBrowsingEnabled) {
753         _isPrivateBrowsingEnabled = isPrivateBrowsingEnabled;
754         [self privateBrowsingModeDidChange];
755     }
756 }
757
758 - (void)renewGState
759 {
760     [super renewGState];
761     
762     // -renewGState is called whenever the view's geometry changes.  It's a little hacky to override this method, but
763     // much safer than walking up the view hierarchy and observing frame/bounds changed notifications, since you don't
764     // have to track subsequent changes to the view hierarchy and add/remove notification observers.
765     // NSOpenGLView uses the exact same technique to reshape its OpenGL surface.
766     
767     // All of the work this method does may safely be skipped if the view is not in a window.  When the view
768     // is moved back into a window, everything should be set up correctly.
769     if (![self window])
770         return;
771     
772     [self updateAndSetWindow];
773     
774     [self resetTrackingRect];
775     
776     // Check to see if the plugin view is completely obscured (scrolled out of view, for example).
777     // For performance reasons, we send null events at a lower rate to plugins which are obscured.
778     BOOL oldIsObscured = _isCompletelyObscured;
779     _isCompletelyObscured = NSIsEmptyRect([self visibleRect]);
780     if (_isCompletelyObscured != oldIsObscured)
781         [self restartTimers];
782 }
783
784 - (BOOL)becomeFirstResponder
785 {
786     [self setHasFocus:YES];
787     return YES;
788 }
789
790 - (BOOL)resignFirstResponder
791 {
792     [self setHasFocus:NO];    
793     return YES;
794 }
795
796 - (WebDataSource *)dataSource
797 {
798     return [[self webFrame] _dataSource];
799 }
800
801 - (WebFrame *)webFrame
802 {
803     return kit(_element->document()->frame());
804 }
805
806 - (WebView *)webView
807 {
808     return [[self webFrame] webView];
809 }
810
811 - (NSWindow *)currentWindow
812 {
813     return [self window] ? [self window] : [[self webView] hostWindow];
814 }
815
816 - (WebCore::HTMLPlugInElement*)element
817 {
818     return _element.get();
819 }
820
821 - (void)cut:(id)sender
822 {
823     [self sendModifierEventWithKeyCode:7 character:'x'];
824 }
825
826 - (void)copy:(id)sender
827 {
828     [self sendModifierEventWithKeyCode:8 character:'c'];
829 }
830
831 - (void)paste:(id)sender
832 {
833     [self sendModifierEventWithKeyCode:9 character:'v'];
834 }
835
836 - (void)selectAll:(id)sender
837 {
838     [self sendModifierEventWithKeyCode:0 character:'a'];
839 }
840
841 // AppKit doesn't call mouseDown or mouseUp on right-click. Simulate control-click
842 // mouseDown and mouseUp so plug-ins get the right-click event as they do in Carbon (3125743).
843 - (void)rightMouseDown:(NSEvent *)theEvent
844 {
845     [self mouseDown:theEvent];
846 }
847
848 - (void)rightMouseUp:(NSEvent *)theEvent
849 {
850     [self mouseUp:theEvent];
851 }
852
853
854 - (BOOL)convertFromX:(double)sourceX andY:(double)sourceY space:(NPCoordinateSpace)sourceSpace
855                  toX:(double *)destX andY:(double *)destY space:(NPCoordinateSpace)destSpace
856 {
857     // Nothing to do
858     if (sourceSpace == destSpace) {
859         if (destX)
860             *destX = sourceX;
861         if (destY)
862             *destY = sourceY;
863         return YES;
864     }
865     
866     NSPoint sourcePoint = NSMakePoint(sourceX, sourceY);
867     
868     NSPoint sourcePointInScreenSpace;
869     
870     // First convert to screen space
871     switch (sourceSpace) {
872         case NPCoordinateSpacePlugin:
873             sourcePointInScreenSpace = [self convertPoint:sourcePoint toView:nil];
874             sourcePointInScreenSpace = [[self currentWindow] convertBaseToScreen:sourcePointInScreenSpace];
875             break;
876             
877         case NPCoordinateSpaceWindow:
878             sourcePointInScreenSpace = [[self currentWindow] convertBaseToScreen:sourcePoint];
879             break;
880             
881         case NPCoordinateSpaceFlippedWindow:
882             sourcePoint.y = [[self currentWindow] frame].size.height - sourcePoint.y;
883             sourcePointInScreenSpace = [[self currentWindow] convertBaseToScreen:sourcePoint];
884             break;
885             
886         case NPCoordinateSpaceScreen:
887             sourcePointInScreenSpace = sourcePoint;
888             break;
889             
890         case NPCoordinateSpaceFlippedScreen:
891             sourcePoint.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - sourcePoint.y;
892             sourcePointInScreenSpace = sourcePoint;
893             break;
894         default:
895             return FALSE;
896     }
897     
898     NSPoint destPoint;
899     
900     // Then convert back to the destination space
901     switch (destSpace) {
902         case NPCoordinateSpacePlugin:
903             destPoint = [[self currentWindow] convertScreenToBase:sourcePointInScreenSpace];
904             destPoint = [self convertPoint:destPoint fromView:nil];
905             break;
906             
907         case NPCoordinateSpaceWindow:
908             destPoint = [[self currentWindow] convertScreenToBase:sourcePointInScreenSpace];
909             break;
910             
911         case NPCoordinateSpaceFlippedWindow:
912             destPoint = [[self currentWindow] convertScreenToBase:sourcePointInScreenSpace];
913             destPoint.y = [[self currentWindow] frame].size.height - destPoint.y;
914             break;
915             
916         case NPCoordinateSpaceScreen:
917             destPoint = sourcePointInScreenSpace;
918             break;
919             
920         case NPCoordinateSpaceFlippedScreen:
921             destPoint = sourcePointInScreenSpace;
922             destPoint.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - destPoint.y;
923             break;
924             
925         default:
926             return FALSE;
927     }
928     
929     if (destX)
930         *destX = destPoint.x;
931     if (destY)
932         *destY = destPoint.y;
933     
934     return TRUE;
935 }
936
937
938 - (CString)resolvedURLStringForURL:(const char*)url target:(const char*)target
939 {
940     String relativeURLString = String::fromUTF8(url);
941     if (relativeURLString.isNull())
942         return CString();
943     
944     Frame* frame = core([self webFrame]);
945     if (!frame)
946         return CString();
947
948     Frame* targetFrame = frame->tree()->find(String::fromUTF8(target));
949     if (!targetFrame)
950         return CString();
951     
952     if (!frame->document()->securityOrigin()->canAccess(targetFrame->document()->securityOrigin()))
953         return CString();
954   
955     KURL absoluteURL = targetFrame->loader()->completeURL(relativeURLString);
956     return absoluteURL.string().utf8();
957 }
958
959 - (void)invalidatePluginContentRect:(NSRect)rect
960 {
961     if (RenderBoxModelObject *renderer = toRenderBoxModelObject(_element->renderer())) {
962         IntRect contentRect(rect);
963         contentRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
964         
965         renderer->repaintRectangle(contentRect);
966     }
967 }
968
969 - (NSRect)actualVisibleRectInWindow
970 {
971     RenderObject* renderer = _element->renderer();
972     if (!renderer || !renderer->view())
973         return NSZeroRect;
974
975     FrameView* frameView = renderer->view()->frameView();
976     if (!frameView)
977         return NSZeroRect;
978
979     IntRect widgetRect = renderer->absoluteClippedOverflowRect();
980     widgetRect = frameView->contentsToWindow(widgetRect);
981     return intersection(toRenderWidget(renderer)->windowClipRect(), widgetRect);
982 }
983
984 - (CALayer *)pluginLayer
985 {
986     ASSERT_NOT_REACHED();
987     return nil;
988 }
989
990 @end
991
992 namespace WebKit {
993
994 bool getAuthenticationInfo(const char* protocolStr, const char* hostStr, int32_t port, const char* schemeStr, const char* realmStr,
995                            CString& username, CString& password)
996 {
997     if (strcasecmp(protocolStr, "http") != 0 && 
998         strcasecmp(protocolStr, "https") != 0)
999         return false;
1000
1001     NSString *host = [NSString stringWithUTF8String:hostStr];
1002     if (!hostStr)
1003         return false;
1004     
1005     NSString *protocol = [NSString stringWithUTF8String:protocolStr];
1006     if (!protocol)
1007         return false;
1008     
1009     NSString *realm = [NSString stringWithUTF8String:realmStr];
1010     if (!realm)
1011         return NPERR_GENERIC_ERROR;
1012     
1013     NSString *authenticationMethod = NSURLAuthenticationMethodDefault;
1014     if (!strcasecmp(protocolStr, "http")) {
1015         if (!strcasecmp(schemeStr, "basic"))
1016             authenticationMethod = NSURLAuthenticationMethodHTTPBasic;
1017         else if (!strcasecmp(schemeStr, "digest"))
1018             authenticationMethod = NSURLAuthenticationMethodHTTPDigest;
1019     }
1020     
1021     RetainPtr<NSURLProtectionSpace> protectionSpace(AdoptNS, [[NSURLProtectionSpace alloc] initWithHost:host port:port protocol:protocol realm:realm authenticationMethod:authenticationMethod]);
1022     
1023     NSURLCredential *credential = mac(CredentialStorage::get(core(protectionSpace.get())));
1024     if (!credential)
1025         credential = [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:protectionSpace.get()];
1026     if (!credential)
1027         return false;
1028   
1029     if (![credential hasPassword])
1030         return false;
1031     
1032     username = [[credential user] UTF8String];
1033     password = [[credential password] UTF8String];
1034     
1035     return true;
1036 }
1037     
1038 } // namespace WebKit
1039
1040 #endif //  ENABLE(NETSCAPE_PLUGIN_API)
1041