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