Home | History | Annotate | Download | only in Plugins
      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 #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 
    996 namespace WebKit {
    997 
    998 bool 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