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