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