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