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