diff -r 000000000000 -r 4f2f89ce4247 WebKit/mac/Plugins/WebBaseNetscapePluginView.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,1070 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if ENABLE(NETSCAPE_PLUGIN_API) + +#import "WebBaseNetscapePluginView.h" + +#import "WebFrameInternal.h" +#import "WebKitLogging.h" +#import "WebKitNSStringExtras.h" +#import "WebKitSystemInterface.h" +#import "WebPluginContainerCheck.h" +#import "WebNetscapeContainerCheckContextInfo.h" +#import "WebNSURLExtras.h" +#import "WebNSURLRequestExtras.h" +#import "WebView.h" +#import "WebViewInternal.h" + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification" +#define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification" + +static const NSTimeInterval ClearSubstituteImageDelay = 0.5; + +using namespace WebCore; + +class WebHaltablePlugin : public HaltablePlugin { +public: + WebHaltablePlugin(WebBaseNetscapePluginView* view) + : m_view(view) + { + } + +private: + virtual void halt(); + virtual void restart(); + virtual Node* node() const; + virtual bool isWindowed() const; + virtual String pluginName() const; + + WebBaseNetscapePluginView* m_view; +}; + +void WebHaltablePlugin::halt() +{ + [m_view halt]; +} + +void WebHaltablePlugin::restart() +{ + [m_view resumeFromHalt]; +} + +Node* WebHaltablePlugin::node() const +{ + return [m_view element]; +} + +bool WebHaltablePlugin::isWindowed() const +{ + return false; +} + +String WebHaltablePlugin::pluginName() const +{ + return [[m_view pluginPackage] pluginInfo].name; +} + +@implementation WebBaseNetscapePluginView + ++ (void)initialize +{ + JSC::initializeThreading(); + WTF::initializeMainThreadToProcessMainThread(); +#ifndef BUILDING_ON_TIGER + WebCoreObjCFinalizeOnMainThread(self); +#endif + WKSendUserChangeNotifications(); +} + +- (id)initWithFrame:(NSRect)frame + pluginPackage:(WebNetscapePluginPackage *)pluginPackage + URL:(NSURL *)URL + baseURL:(NSURL *)baseURL + MIMEType:(NSString *)MIME + attributeKeys:(NSArray *)keys + attributeValues:(NSArray *)values + loadManually:(BOOL)loadManually + element:(PassRefPtr)element +{ + self = [super initWithFrame:frame]; + if (!self) + return nil; + + _pluginPackage = pluginPackage; + _element = element; + _sourceURL.adoptNS([URL copy]); + _baseURL.adoptNS([baseURL copy]); + _MIMEType.adoptNS([MIME copy]); + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + // Enable "kiosk mode" when instantiating the QT plug-in inside of Dashboard. See + if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.dashboard.client"] && + [_pluginPackage.get() bundleIdentifier] == "com.apple.QuickTime Plugin.plugin") { + RetainPtr mutableKeys(AdoptNS, [keys mutableCopy]); + RetainPtr mutableValues(AdoptNS, [values mutableCopy]); + + [mutableKeys.get() addObject:@"kioskmode"]; + [mutableValues.get() addObject:@"true"]; + [self setAttributeKeys:mutableKeys.get() andValues:mutableValues.get()]; + } else +#endif + [self setAttributeKeys:keys andValues:values]; + + if (loadManually) + _mode = NP_FULL; + else + _mode = NP_EMBED; + + _loadManually = loadManually; + _haltable = new WebHaltablePlugin(self); + return self; +} + +- (void)dealloc +{ + ASSERT(!_isStarted); + + [super dealloc]; +} + +- (void)finalize +{ + ASSERT_MAIN_THREAD(); + ASSERT(!_isStarted); + + [super finalize]; +} + +- (WebNetscapePluginPackage *)pluginPackage +{ + return _pluginPackage.get(); +} + +- (BOOL)isFlipped +{ + return YES; +} + +- (NSURL *)URLWithCString:(const char *)URLCString +{ + if (!URLCString) + return nil; + + CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, URLCString, kCFStringEncodingISOLatin1); + ASSERT(string); // All strings should be representable in ISO Latin 1 + + NSString *URLString = [(NSString *)string _web_stringByStrippingReturnCharacters]; + NSURL *URL = [NSURL _web_URLWithDataAsString:URLString relativeToURL:_baseURL.get()]; + CFRelease(string); + if (!URL) + return nil; + + return URL; +} + +- (NSMutableURLRequest *)requestWithURLCString:(const char *)URLCString +{ + NSURL *URL = [self URLWithCString:URLCString]; + if (!URL) + return nil; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + Frame* frame = core([self webFrame]); + if (!frame) + return nil; + [request _web_setHTTPReferrer:frame->loader()->outgoingReferrer()]; + return request; +} + +// Methods that subclasses must override +- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values +{ + ASSERT_NOT_REACHED(); +} + +- (void)handleMouseMoved:(NSEvent *)event +{ + ASSERT_NOT_REACHED(); +} + +- (void)handleMouseEntered:(NSEvent *)event +{ + ASSERT_NOT_REACHED(); +} + +- (void)handleMouseExited:(NSEvent *)event +{ + ASSERT_NOT_REACHED(); +} + +- (void)focusChanged +{ + ASSERT_NOT_REACHED(); +} + +- (void)windowFocusChanged:(BOOL)hasFocus +{ + ASSERT_NOT_REACHED(); +} + +- (BOOL)createPlugin +{ + ASSERT_NOT_REACHED(); + return NO; +} + +- (void)loadStream +{ + ASSERT_NOT_REACHED(); +} + +- (BOOL)shouldStop +{ + ASSERT_NOT_REACHED(); + return YES; +} + +- (void)destroyPlugin +{ + ASSERT_NOT_REACHED(); +} + +- (void)updateAndSetWindow +{ + ASSERT_NOT_REACHED(); +} + +- (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character +{ + ASSERT_NOT_REACHED(); +} + +- (void)privateBrowsingModeDidChange +{ +} + +- (void)removeTrackingRect +{ + if (_trackingTag) { + [self removeTrackingRect:_trackingTag]; + _trackingTag = 0; + + // Do the following after setting trackingTag to 0 so we don't re-enter. + + // Balance the retain in resetTrackingRect. Use autorelease in case we hold + // the last reference to the window during tear-down, to avoid crashing AppKit. + [[self window] autorelease]; + } +} + +- (void)resetTrackingRect +{ + [self removeTrackingRect]; + if (_isStarted) { + // Retain the window so that removeTrackingRect can work after the window is closed. + [[self window] retain]; + _trackingTag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO]; + } +} + +- (void)stopTimers +{ + _shouldFireTimers = NO; +} + +- (void)startTimers +{ + _shouldFireTimers = YES; +} + +- (void)restartTimers +{ + ASSERT([self window]); + + [self stopTimers]; + + if (!_isStarted || [[self window] isMiniaturized]) + return; + + [self startTimers]; +} + +- (NSRect)_windowClipRect +{ + RenderObject* renderer = _element->renderer(); + if (!renderer || !renderer->view()) + return NSZeroRect; + + return toRenderWidget(renderer)->windowClipRect(); +} + +- (NSRect)visibleRect +{ + // WebCore may impose an additional clip (via CSS overflow or clip properties). Fetch + // that clip now. + return NSIntersectionRect([self convertRect:[self _windowClipRect] fromView:nil], [super visibleRect]); +} + +- (void)visibleRectDidChange +{ + [self renewGState]; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (void)sendActivateEvent:(BOOL)activate +{ + if (!_isStarted) + return; + + [self windowFocusChanged:activate]; +} + +- (void)setHasFocus:(BOOL)flag +{ + if (!_isStarted) + return; + + if (_hasFocus == flag) + return; + + _hasFocus = flag; + + [self focusChanged]; +} + +- (void)addWindowObservers +{ + ASSERT([self window]); + + NSWindow *theWindow = [self window]; + + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification object:theWindow]; + [notificationCenter addObserver:self selector:@selector(windowBecameKey:) + name:NSWindowDidBecomeKeyNotification object:theWindow]; + [notificationCenter addObserver:self selector:@selector(windowResignedKey:) + name:NSWindowDidResignKeyNotification object:theWindow]; + [notificationCenter addObserver:self selector:@selector(windowDidMiniaturize:) + name:NSWindowDidMiniaturizeNotification object:theWindow]; + [notificationCenter addObserver:self selector:@selector(windowDidDeminiaturize:) + name:NSWindowDidDeminiaturizeNotification object:theWindow]; + + [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchFromUser:) + name:LoginWindowDidSwitchFromUserNotification object:nil]; + [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchToUser:) + name:LoginWindowDidSwitchToUserNotification object:nil]; +} + +- (void)removeWindowObservers +{ + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter removeObserver:self name:NSWindowWillCloseNotification object:nil]; + [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; + [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification object:nil]; + [notificationCenter removeObserver:self name:NSWindowDidMiniaturizeNotification object:nil]; + [notificationCenter removeObserver:self name:NSWindowDidDeminiaturizeNotification object:nil]; + [notificationCenter removeObserver:self name:LoginWindowDidSwitchFromUserNotification object:nil]; + [notificationCenter removeObserver:self name:LoginWindowDidSwitchToUserNotification object:nil]; +} + +- (void)start +{ + ASSERT([self currentWindow]); + + if (_isStarted) + return; + + if (_triedAndFailedToCreatePlugin) + return; + + ASSERT([self webView]); + + if (![[[self webView] preferences] arePlugInsEnabled]) + return; + + Frame* frame = core([self webFrame]); + if (!frame) + return; + Page* page = frame->page(); + if (!page) + return; + + bool wasDeferring = page->defersLoading(); + if (!wasDeferring) + page->setDefersLoading(true); + + BOOL result = [self createPlugin]; + + if (!wasDeferring) + page->setDefersLoading(false); + + if (!result) { + _triedAndFailedToCreatePlugin = YES; + return; + } + + _isStarted = YES; + page->didStartPlugin(_haltable.get()); + + [[self webView] addPluginInstanceView:self]; + + if ([self currentWindow]) + [self updateAndSetWindow]; + + if ([self window]) { + [self addWindowObservers]; + if ([[self window] isKeyWindow]) { + [self sendActivateEvent:YES]; + } + [self restartTimers]; + } + + [self resetTrackingRect]; + + [self loadStream]; +} + +- (void)stop +{ + if (![self shouldStop]) + return; + + [self removeTrackingRect]; + + if (!_isStarted) + return; + + if (Frame* frame = core([self webFrame])) { + if (Page* page = frame->page()) + page->didStopPlugin(_haltable.get()); + } + + _isStarted = NO; + + [[self webView] removePluginInstanceView:self]; + + // Stop the timers + [self stopTimers]; + + // Stop notifications and callbacks. + [self removeWindowObservers]; + + [self destroyPlugin]; +} + +- (void)halt +{ + ASSERT(!_isHalted); + ASSERT(_isStarted); + Element *element = [self element]; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + CGImageRef cgImage = CGImageRetain([core([self webFrame])->nodeImage(element) CGImageForProposedRect:nil context:nil hints:nil]); +#else + RetainPtr imageRef(AdoptCF, CGImageSourceCreateWithData((CFDataRef)[core([self webFrame])->nodeImage(element) TIFFRepresentation], 0)); + CGImageRef cgImage = CGImageSourceCreateImageAtIndex(imageRef.get(), 0, 0); +#endif + ASSERT(cgImage); + + // BitmapImage will release the passed in CGImage on destruction. + RefPtr nodeImage = BitmapImage::create(cgImage); + ASSERT(element->renderer()); + toRenderWidget(element->renderer())->showSubstituteImage(nodeImage); + [self stop]; + _isHalted = YES; + _hasBeenHalted = YES; +} + +- (void)_clearSubstituteImage +{ + Element* element = [self element]; + if (!element) + return; + + RenderObject* renderer = element->renderer(); + if (!renderer) + return; + + toRenderWidget(renderer)->showSubstituteImage(0); +} + +- (void)resumeFromHalt +{ + ASSERT(_isHalted); + ASSERT(!_isStarted); + [self start]; + + if (_isStarted) + _isHalted = NO; + + ASSERT([self element]->renderer()); + // FIXME 7417484: This is a workaround for plug-ins not drawing immediately. We'd like to detect when the + // plug-in actually draws instead of just assuming it will do so within 0.5 seconds of being restarted. + [self performSelector:@selector(_clearSubstituteImage) withObject:nil afterDelay:ClearSubstituteImageDelay]; +} + +- (BOOL)isHalted +{ + return _isHalted; +} + +- (BOOL)shouldClipOutPlugin +{ + NSWindow *window = [self window]; + return !window || [window isMiniaturized] || [NSApp isHidden] || ![self isDescendantOf:[[self window] contentView]] || [self isHiddenOrHasHiddenAncestor]; +} + +- (BOOL)inFlatteningPaint +{ + RenderObject* renderer = _element->renderer(); + if (renderer && renderer->view()) { + if (FrameView* frameView = renderer->view()->frameView()) + return frameView->paintBehavior() & PaintBehaviorFlattenCompositingLayers; + } + + return NO; +} + +- (BOOL)supportsSnapshotting +{ + return [_pluginPackage.get() supportsSnapshotting]; +} + +- (BOOL)hasBeenHalted +{ + return _hasBeenHalted; +} + +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + // We must remove the tracking rect before we move to the new window. + // Once we move to the new window, it will be too late. + [self removeTrackingRect]; + [self removeWindowObservers]; + + // Workaround for: resignFirstResponder is not sent to first responder view when it is removed from the window + [self setHasFocus:NO]; + + if (!newWindow) { + if ([[self webView] hostWindow]) { + // View will be moved out of the actual window but it still has a host window. + [self stopTimers]; + } else { + // View will have no associated windows. + [self stop]; + + // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy. + // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed. + [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil]; + } + } +} + +- (void)viewWillMoveToSuperview:(NSView *)newSuperview +{ + if (!newSuperview) { + // Stop the plug-in when it is removed from its superview. It is not sufficient to do this in -viewWillMoveToWindow:nil, because + // the WebView might still has a hostWindow at that point, which prevents the plug-in from being destroyed. + // There is no need to start the plug-in when moving into a superview. -viewDidMoveToWindow takes care of that. + [self stop]; + + // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy. + // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed. + [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil]; + } +} + +- (void)viewDidMoveToWindow +{ + [self resetTrackingRect]; + + if ([self window]) { + // While in the view hierarchy, observe WebPreferencesChangedNotification so that we can start/stop depending + // on whether plugins are enabled. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(preferencesHaveChanged:) + name:WebPreferencesChangedNotification + object:nil]; + + _isPrivateBrowsingEnabled = [[[self webView] preferences] privateBrowsingEnabled]; + + // View moved to an actual window. Start it if not already started. + [self start]; + + // Starting the plug-in can result in it removing itself from the window so we need to ensure that we're still in + // place before doing anything that requires a window. + if ([self window]) { + [self restartTimers]; + [self addWindowObservers]; + } + } else if ([[self webView] hostWindow]) { + // View moved out of an actual window, but still has a host window. + // Call setWindow to explicitly "clip out" the plug-in from sight. + // FIXME: It would be nice to do this where we call stopNullEvents in viewWillMoveToWindow. + [self updateAndSetWindow]; + } +} + +- (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow +{ + if (!hostWindow && ![self window]) { + // View will have no associated windows. + [self stop]; + + // Remove WebPreferencesChangedNotification observer -- we will observe once again when we move back into the window + [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil]; + } +} + +- (void)viewDidMoveToHostWindow +{ + if ([[self webView] hostWindow]) { + // View now has an associated window. Start it if not already started. + [self start]; + } +} + +#pragma mark NOTIFICATIONS + +- (void)windowWillClose:(NSNotification *)notification +{ + [self stop]; +} + +- (void)windowBecameKey:(NSNotification *)notification +{ + [self sendActivateEvent:YES]; + [self invalidatePluginContentRect:[self bounds]]; + [self restartTimers]; +} + +- (void)windowResignedKey:(NSNotification *)notification +{ + [self sendActivateEvent:NO]; + [self invalidatePluginContentRect:[self bounds]]; + [self restartTimers]; +} + +- (void)windowDidMiniaturize:(NSNotification *)notification +{ + [self stopTimers]; +} + +- (void)windowDidDeminiaturize:(NSNotification *)notification +{ + [self restartTimers]; +} + +- (void)loginWindowDidSwitchFromUser:(NSNotification *)notification +{ + [self stopTimers]; +} + +-(void)loginWindowDidSwitchToUser:(NSNotification *)notification +{ + [self restartTimers]; +} + +- (void)preferencesHaveChanged:(NSNotification *)notification +{ + WebPreferences *preferences = [[self webView] preferences]; + + if ([notification object] != preferences) + return; + + BOOL arePlugInsEnabled = [preferences arePlugInsEnabled]; + if (_isStarted != arePlugInsEnabled) { + if (arePlugInsEnabled) { + if ([self currentWindow]) { + [self start]; + } + } else { + [self stop]; + [self invalidatePluginContentRect:[self bounds]]; + } + } + + BOOL isPrivateBrowsingEnabled = [preferences privateBrowsingEnabled]; + if (isPrivateBrowsingEnabled != _isPrivateBrowsingEnabled) { + _isPrivateBrowsingEnabled = isPrivateBrowsingEnabled; + [self privateBrowsingModeDidChange]; + } +} + +- (void)renewGState +{ + [super renewGState]; + + // -renewGState is called whenever the view's geometry changes. It's a little hacky to override this method, but + // much safer than walking up the view hierarchy and observing frame/bounds changed notifications, since you don't + // have to track subsequent changes to the view hierarchy and add/remove notification observers. + // NSOpenGLView uses the exact same technique to reshape its OpenGL surface. + + // All of the work this method does may safely be skipped if the view is not in a window. When the view + // is moved back into a window, everything should be set up correctly. + if (![self window]) + return; + + [self updateAndSetWindow]; + + [self resetTrackingRect]; + + // Check to see if the plugin view is completely obscured (scrolled out of view, for example). + // For performance reasons, we send null events at a lower rate to plugins which are obscured. + BOOL oldIsObscured = _isCompletelyObscured; + _isCompletelyObscured = NSIsEmptyRect([self visibleRect]); + if (_isCompletelyObscured != oldIsObscured) + [self restartTimers]; +} + +- (BOOL)becomeFirstResponder +{ + [self setHasFocus:YES]; + return YES; +} + +- (BOOL)resignFirstResponder +{ + [self setHasFocus:NO]; + return YES; +} + +- (WebDataSource *)dataSource +{ + return [[self webFrame] _dataSource]; +} + +- (WebFrame *)webFrame +{ + return kit(_element->document()->frame()); +} + +- (WebView *)webView +{ + return [[self webFrame] webView]; +} + +- (NSWindow *)currentWindow +{ + return [self window] ? [self window] : [[self webView] hostWindow]; +} + +- (WebCore::HTMLPlugInElement*)element +{ + return _element.get(); +} + +- (void)cut:(id)sender +{ + [self sendModifierEventWithKeyCode:7 character:'x']; +} + +- (void)copy:(id)sender +{ + [self sendModifierEventWithKeyCode:8 character:'c']; +} + +- (void)paste:(id)sender +{ + [self sendModifierEventWithKeyCode:9 character:'v']; +} + +- (void)selectAll:(id)sender +{ + [self sendModifierEventWithKeyCode:0 character:'a']; +} + +// AppKit doesn't call mouseDown or mouseUp on right-click. Simulate control-click +// mouseDown and mouseUp so plug-ins get the right-click event as they do in Carbon (3125743). +- (void)rightMouseDown:(NSEvent *)theEvent +{ + [self mouseDown:theEvent]; +} + +- (void)rightMouseUp:(NSEvent *)theEvent +{ + [self mouseUp:theEvent]; +} + + +- (BOOL)convertFromX:(double)sourceX andY:(double)sourceY space:(NPCoordinateSpace)sourceSpace + toX:(double *)destX andY:(double *)destY space:(NPCoordinateSpace)destSpace +{ + // Nothing to do + if (sourceSpace == destSpace) + return TRUE; + + NSPoint sourcePoint = NSMakePoint(sourceX, sourceY); + + NSPoint sourcePointInScreenSpace; + + // First convert to screen space + switch (sourceSpace) { + case NPCoordinateSpacePlugin: + sourcePointInScreenSpace = [self convertPoint:sourcePoint toView:nil]; + sourcePointInScreenSpace = [[self currentWindow] convertBaseToScreen:sourcePointInScreenSpace]; + break; + + case NPCoordinateSpaceWindow: + sourcePointInScreenSpace = [[self currentWindow] convertBaseToScreen:sourcePoint]; + break; + + case NPCoordinateSpaceFlippedWindow: + sourcePoint.y = [[self currentWindow] frame].size.height - sourcePoint.y; + sourcePointInScreenSpace = [[self currentWindow] convertBaseToScreen:sourcePoint]; + break; + + case NPCoordinateSpaceScreen: + sourcePointInScreenSpace = sourcePoint; + break; + + case NPCoordinateSpaceFlippedScreen: + sourcePoint.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - sourcePoint.y; + sourcePointInScreenSpace = sourcePoint; + break; + default: + return FALSE; + } + + NSPoint destPoint; + + // Then convert back to the destination space + switch (destSpace) { + case NPCoordinateSpacePlugin: + destPoint = [[self currentWindow] convertScreenToBase:sourcePointInScreenSpace]; + destPoint = [self convertPoint:destPoint fromView:nil]; + break; + + case NPCoordinateSpaceWindow: + destPoint = [[self currentWindow] convertScreenToBase:sourcePointInScreenSpace]; + break; + + case NPCoordinateSpaceFlippedWindow: + destPoint = [[self currentWindow] convertScreenToBase:sourcePointInScreenSpace]; + destPoint.y = [[self currentWindow] frame].size.height - destPoint.y; + break; + + case NPCoordinateSpaceScreen: + destPoint = sourcePointInScreenSpace; + break; + + case NPCoordinateSpaceFlippedScreen: + destPoint = sourcePointInScreenSpace; + destPoint.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - destPoint.y; + break; + + default: + return FALSE; + } + + if (destX) + *destX = destPoint.x; + if (destY) + *destY = destPoint.y; + + return TRUE; +} + + +- (CString)resolvedURLStringForURL:(const char*)url target:(const char*)target +{ + String relativeURLString = String::fromUTF8(url); + if (relativeURLString.isNull()) + return CString(); + + Frame* frame = core([self webFrame]); + if (!frame) + return CString(); + + Frame* targetFrame = frame->tree()->find(String::fromUTF8(target)); + if (!targetFrame) + return CString(); + + if (!frame->document()->securityOrigin()->canAccess(targetFrame->document()->securityOrigin())) + return CString(); + + KURL absoluteURL = targetFrame->loader()->completeURL(relativeURLString); + return absoluteURL.string().utf8(); +} + +- (void)invalidatePluginContentRect:(NSRect)rect +{ + if (RenderBoxModelObject *renderer = toRenderBoxModelObject(_element->renderer())) { + IntRect contentRect(rect); + contentRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop()); + + renderer->repaintRectangle(contentRect); + } +} + +#ifndef BUILDING_ON_TIGER +- (CALayer *)pluginLayer +{ + ASSERT_NOT_REACHED(); + return nil; +} +#endif + +@end + +namespace WebKit { + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +CString proxiesForURL(NSURL *url) +{ + RetainPtr systemProxies(AdoptCF, CFNetworkCopySystemProxySettings()); + if (!systemProxies) + return "DIRECT"; + + RetainPtr proxiesForURL(AdoptCF, CFNetworkCopyProxiesForURL((CFURLRef)url, systemProxies.get())); + CFIndex proxyCount = proxiesForURL ? CFArrayGetCount(proxiesForURL.get()) : 0; + if (!proxyCount) + return "DIRECT"; + + // proxiesForURL is a CFArray of CFDictionaries. Each dictionary represents a proxy. + // The format of the result should be: + // "PROXY host[:port]" (for HTTP proxy) or + // "SOCKS host[:port]" (for SOCKS proxy) or + // A combination of the above, separated by semicolon, in the order that they should be tried. + String proxies; + for (CFIndex i = 0; i < proxyCount; ++i) { + CFDictionaryRef proxy = static_cast(CFArrayGetValueAtIndex(proxiesForURL.get(), i)); + if (!proxy) + continue; + + CFStringRef type = static_cast(CFDictionaryGetValue(proxy, kCFProxyTypeKey)); + bool isHTTP = type == kCFProxyTypeHTTP || type == kCFProxyTypeHTTPS; + bool isSOCKS = type == kCFProxyTypeSOCKS; + + // We can only report HTTP and SOCKS proxies. + if (!isHTTP && !isSOCKS) + continue; + + CFStringRef host = static_cast(CFDictionaryGetValue(proxy, kCFProxyHostNameKey)); + CFNumberRef port = static_cast(CFDictionaryGetValue(proxy, kCFProxyPortNumberKey)); + + // If we are inserting multiple entries, add a separator + if (!proxies.isEmpty()) + proxies += ";"; + + if (isHTTP) + proxies += "PROXY "; + else if (isSOCKS) + proxies += "SOCKS "; + + proxies += host; + + if (port) { + SInt32 intPort; + CFNumberGetValue(port, kCFNumberSInt32Type, &intPort); + + proxies += ":" + String::number(intPort); + } + } + + if (proxies.isEmpty()) + return "DIRECT"; + + return proxies.utf8(); +} +#endif + +bool getAuthenticationInfo(const char* protocolStr, const char* hostStr, int32_t port, const char* schemeStr, const char* realmStr, + CString& username, CString& password) +{ + if (strcasecmp(protocolStr, "http") != 0 && + strcasecmp(protocolStr, "https") != 0) + return false; + + NSString *host = [NSString stringWithUTF8String:hostStr]; + if (!hostStr) + return false; + + NSString *protocol = [NSString stringWithUTF8String:protocolStr]; + if (!protocol) + return false; + + NSString *realm = [NSString stringWithUTF8String:realmStr]; + if (!realm) + return NPERR_GENERIC_ERROR; + + NSString *authenticationMethod = NSURLAuthenticationMethodDefault; + if (!strcasecmp(protocolStr, "http")) { + if (!strcasecmp(schemeStr, "basic")) + authenticationMethod = NSURLAuthenticationMethodHTTPBasic; + else if (!strcasecmp(schemeStr, "digest")) + authenticationMethod = NSURLAuthenticationMethodHTTPDigest; + } + + RetainPtr protectionSpace(AdoptNS, [[NSURLProtectionSpace alloc] initWithHost:host port:port protocol:protocol realm:realm authenticationMethod:authenticationMethod]); + + NSURLCredential *credential = mac(CredentialStorage::get(core(protectionSpace.get()))); + if (!credential) + credential = [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:protectionSpace.get()]; + if (!credential) + return false; + + if (![credential hasPassword]) + return false; + + username = [[credential user] UTF8String]; + password = [[credential password] UTF8String]; + + return true; +} + +} // namespace WebKit + +#endif // ENABLE(NETSCAPE_PLUGIN_API) +