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