web_contents_view_mac.mm revision effb81e5f8246d0db0270817048dc992db66e9fb
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import <Carbon/Carbon.h> 6 7#import "content/browser/web_contents/web_contents_view_mac.h" 8 9#include <string> 10 11#import "base/mac/scoped_sending_event.h" 12#include "base/message_loop/message_loop.h" 13#import "base/message_loop/message_pump_mac.h" 14#include "content/browser/renderer_host/popup_menu_helper_mac.h" 15#include "content/browser/renderer_host/render_view_host_factory.h" 16#include "content/browser/renderer_host/render_view_host_impl.h" 17#include "content/browser/renderer_host/render_widget_host_view_mac.h" 18#include "content/browser/web_contents/web_contents_impl.h" 19#import "content/browser/web_contents/web_drag_dest_mac.h" 20#import "content/browser/web_contents/web_drag_source_mac.h" 21#include "content/common/view_messages.h" 22#include "content/public/browser/web_contents_delegate.h" 23#include "content/public/browser/web_contents_view_delegate.h" 24#include "skia/ext/skia_utils_mac.h" 25#import "third_party/mozilla/NSPasteboard+Utils.h" 26#include "ui/base/clipboard/custom_data_helper.h" 27#import "ui/base/cocoa/focus_tracker.h" 28#include "ui/base/dragdrop/cocoa_dnd_util.h" 29#include "ui/gfx/image/image_skia_util_mac.h" 30 31using blink::WebDragOperation; 32using blink::WebDragOperationsMask; 33using content::DropData; 34using content::PopupMenuHelper; 35using content::RenderViewHostFactory; 36using content::RenderWidgetHostView; 37using content::RenderWidgetHostViewMac; 38using content::WebContents; 39using content::WebContentsImpl; 40using content::WebContentsViewMac; 41 42// Ensure that the blink::WebDragOperation enum values stay in sync with 43// NSDragOperation constants, since the code below static_casts between 'em. 44#define COMPILE_ASSERT_MATCHING_ENUM(name) \ 45 COMPILE_ASSERT(int(NS##name) == int(blink::Web##name), enum_mismatch_##name) 46COMPILE_ASSERT_MATCHING_ENUM(DragOperationNone); 47COMPILE_ASSERT_MATCHING_ENUM(DragOperationCopy); 48COMPILE_ASSERT_MATCHING_ENUM(DragOperationLink); 49COMPILE_ASSERT_MATCHING_ENUM(DragOperationGeneric); 50COMPILE_ASSERT_MATCHING_ENUM(DragOperationPrivate); 51COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove); 52COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete); 53COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery); 54 55@interface WebContentsViewCocoa (Private) 56- (id)initWithWebContentsViewMac:(WebContentsViewMac*)w; 57- (void)registerDragTypes; 58- (void)setCurrentDragOperation:(NSDragOperation)operation; 59- (DropData*)dropData; 60- (void)startDragWithDropData:(const DropData&)dropData 61 dragOperationMask:(NSDragOperation)operationMask 62 image:(NSImage*)image 63 offset:(NSPoint)offset; 64- (void)cancelDeferredClose; 65- (void)clearWebContentsView; 66- (void)closeTabAfterEvent; 67- (void)viewDidBecomeFirstResponder:(NSNotification*)notification; 68@end 69 70namespace content { 71WebContentsViewPort* CreateWebContentsView( 72 WebContentsImpl* web_contents, 73 WebContentsViewDelegate* delegate, 74 RenderViewHostDelegateView** render_view_host_delegate_view) { 75 WebContentsViewMac* rv = new WebContentsViewMac(web_contents, delegate); 76 *render_view_host_delegate_view = rv; 77 return rv; 78} 79 80WebContentsViewMac::WebContentsViewMac(WebContentsImpl* web_contents, 81 WebContentsViewDelegate* delegate) 82 : web_contents_(web_contents), 83 delegate_(delegate), 84 allow_overlapping_views_(false), 85 overlay_view_(NULL), 86 underlay_view_(NULL) { 87} 88 89WebContentsViewMac::~WebContentsViewMac() { 90 // This handles the case where a renderer close call was deferred 91 // while the user was operating a UI control which resulted in a 92 // close. In that case, the Cocoa view outlives the 93 // WebContentsViewMac instance due to Cocoa retain count. 94 [cocoa_view_ cancelDeferredClose]; 95 [cocoa_view_ clearWebContentsView]; 96} 97 98gfx::NativeView WebContentsViewMac::GetNativeView() const { 99 return cocoa_view_.get(); 100} 101 102gfx::NativeView WebContentsViewMac::GetContentNativeView() const { 103 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView(); 104 if (!rwhv) 105 return NULL; 106 return rwhv->GetNativeView(); 107} 108 109gfx::NativeWindow WebContentsViewMac::GetTopLevelNativeWindow() const { 110 return [cocoa_view_.get() window]; 111} 112 113void WebContentsViewMac::GetContainerBounds(gfx::Rect* out) const { 114 // Convert bounds to window coordinate space. 115 NSRect bounds = 116 [cocoa_view_.get() convertRect:[cocoa_view_.get() bounds] toView:nil]; 117 118 // Convert bounds to screen coordinate space. 119 NSWindow* window = [cocoa_view_.get() window]; 120 bounds.origin = [window convertBaseToScreen:bounds.origin]; 121 122 // Flip y to account for screen flip. 123 NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; 124 bounds.origin.y = [screen frame].size.height - bounds.origin.y 125 - bounds.size.height; 126 *out = gfx::Rect(NSRectToCGRect(bounds)); 127} 128 129void WebContentsViewMac::StartDragging( 130 const DropData& drop_data, 131 WebDragOperationsMask allowed_operations, 132 const gfx::ImageSkia& image, 133 const gfx::Vector2d& image_offset, 134 const DragEventSourceInfo& event_info) { 135 // By allowing nested tasks, the code below also allows Close(), 136 // which would deallocate |this|. The same problem can occur while 137 // processing -sendEvent:, so Close() is deferred in that case. 138 // Drags from web content do not come via -sendEvent:, this sets the 139 // same flag -sendEvent: would. 140 base::mac::ScopedSendingEvent sending_event_scoper; 141 142 // The drag invokes a nested event loop, arrange to continue 143 // processing events. 144 base::MessageLoop::ScopedNestableTaskAllower allow( 145 base::MessageLoop::current()); 146 NSDragOperation mask = static_cast<NSDragOperation>(allowed_operations); 147 NSPoint offset = NSPointFromCGPoint( 148 gfx::PointAtOffsetFromOrigin(image_offset).ToCGPoint()); 149 [cocoa_view_ startDragWithDropData:drop_data 150 dragOperationMask:mask 151 image:gfx::NSImageFromImageSkia(image) 152 offset:offset]; 153} 154 155void WebContentsViewMac::OnTabCrashed(base::TerminationStatus /* status */, 156 int /* error_code */) { 157} 158 159void WebContentsViewMac::SizeContents(const gfx::Size& size) { 160 // TODO(brettw | japhet) This is a hack and should be removed. 161 // See web_contents_view.h. 162 // Note(erikchen): This method has /never/ worked correctly. I've removed the 163 // previous implementation. 164} 165 166void WebContentsViewMac::Focus() { 167 NSWindow* window = [cocoa_view_.get() window]; 168 [window makeFirstResponder:GetContentNativeView()]; 169 if (![window isVisible]) 170 return; 171 [window makeKeyAndOrderFront:nil]; 172} 173 174void WebContentsViewMac::SetInitialFocus() { 175 if (web_contents_->FocusLocationBarByDefault()) 176 web_contents_->SetFocusToLocationBar(false); 177 else 178 [[cocoa_view_.get() window] makeFirstResponder:GetContentNativeView()]; 179} 180 181void WebContentsViewMac::StoreFocus() { 182 // We're explicitly being asked to store focus, so don't worry if there's 183 // already a view saved. 184 focus_tracker_.reset( 185 [[FocusTracker alloc] initWithWindow:[cocoa_view_ window]]); 186} 187 188void WebContentsViewMac::RestoreFocus() { 189 // TODO(avi): Could we be restoring a view that's no longer in the key view 190 // chain? 191 if (!(focus_tracker_.get() && 192 [focus_tracker_ restoreFocusInWindow:[cocoa_view_ window]])) { 193 // Fall back to the default focus behavior if we could not restore focus. 194 // TODO(shess): If location-bar gets focus by default, this will 195 // select-all in the field. If there was a specific selection in 196 // the field when we navigated away from it, we should restore 197 // that selection. 198 SetInitialFocus(); 199 } 200 201 focus_tracker_.reset(nil); 202} 203 204DropData* WebContentsViewMac::GetDropData() const { 205 return [cocoa_view_ dropData]; 206} 207 208void WebContentsViewMac::UpdateDragCursor(WebDragOperation operation) { 209 [cocoa_view_ setCurrentDragOperation: operation]; 210} 211 212void WebContentsViewMac::GotFocus() { 213 // This is only used in the views FocusManager stuff but it bleeds through 214 // all subclasses. http://crbug.com/21875 215} 216 217// This is called when the renderer asks us to take focus back (i.e., it has 218// iterated past the last focusable element on the page). 219void WebContentsViewMac::TakeFocus(bool reverse) { 220 if (reverse) { 221 [[cocoa_view_ window] selectPreviousKeyView:cocoa_view_.get()]; 222 } else { 223 [[cocoa_view_ window] selectNextKeyView:cocoa_view_.get()]; 224 } 225} 226 227void WebContentsViewMac::ShowContextMenu( 228 content::RenderFrameHost* render_frame_host, 229 const ContextMenuParams& params) { 230 // Allow delegates to handle the context menu operation first. 231 if (web_contents_->GetDelegate() && 232 web_contents_->GetDelegate()->HandleContextMenu(params)) { 233 return; 234 } 235 236 if (delegate()) 237 delegate()->ShowContextMenu(render_frame_host, params); 238 else 239 DLOG(ERROR) << "Cannot show context menus without a delegate."; 240} 241 242// Display a popup menu for WebKit using Cocoa widgets. 243void WebContentsViewMac::ShowPopupMenu( 244 const gfx::Rect& bounds, 245 int item_height, 246 double item_font_size, 247 int selected_item, 248 const std::vector<MenuItem>& items, 249 bool right_aligned, 250 bool allow_multiple_selection) { 251 popup_menu_helper_.reset( 252 new PopupMenuHelper(web_contents_->GetRenderViewHost())); 253 popup_menu_helper_->ShowPopupMenu(bounds, item_height, item_font_size, 254 selected_item, items, right_aligned, 255 allow_multiple_selection); 256 popup_menu_helper_.reset(); 257} 258 259void WebContentsViewMac::HidePopupMenu() { 260 if (popup_menu_helper_) 261 popup_menu_helper_->Hide(); 262} 263 264gfx::Rect WebContentsViewMac::GetViewBounds() const { 265 // This method is not currently used on mac. 266 NOTIMPLEMENTED(); 267 return gfx::Rect(); 268} 269 270void WebContentsViewMac::SetAllowOverlappingViews(bool overlapping) { 271 if (allow_overlapping_views_ == overlapping) 272 return; 273 274 allow_overlapping_views_ = overlapping; 275 RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>( 276 web_contents_->GetRenderWidgetHostView()); 277 if (view) 278 view->SetAllowOverlappingViews(allow_overlapping_views_); 279} 280 281bool WebContentsViewMac::GetAllowOverlappingViews() const { 282 return allow_overlapping_views_; 283} 284 285void WebContentsViewMac::SetOverlayView( 286 WebContentsView* overlay, const gfx::Point& offset) { 287 DCHECK(!underlay_view_); 288 if (overlay_view_) 289 RemoveOverlayView(); 290 291 overlay_view_ = static_cast<WebContentsViewMac*>(overlay); 292 DCHECK(!overlay_view_->overlay_view_); 293 overlay_view_->underlay_view_ = this; 294 overlay_view_offset_ = offset; 295 UpdateRenderWidgetHostViewOverlay(); 296} 297 298void WebContentsViewMac::RemoveOverlayView() { 299 DCHECK(overlay_view_); 300 301 RenderWidgetHostViewMac* rwhv = static_cast<RenderWidgetHostViewMac*>( 302 web_contents_->GetRenderWidgetHostView()); 303 if (rwhv) 304 rwhv->RemoveOverlayView(); 305 306 overlay_view_->underlay_view_ = NULL; 307 overlay_view_ = NULL; 308} 309 310void WebContentsViewMac::UpdateRenderWidgetHostViewOverlay() { 311 RenderWidgetHostViewMac* rwhv = static_cast<RenderWidgetHostViewMac*>( 312 web_contents_->GetRenderWidgetHostView()); 313 if (!rwhv) 314 return; 315 316 if (overlay_view_) { 317 RenderWidgetHostViewMac* overlay_rwhv = 318 static_cast<RenderWidgetHostViewMac*>( 319 overlay_view_->web_contents_->GetRenderWidgetHostView()); 320 if (overlay_rwhv) 321 rwhv->SetOverlayView(overlay_rwhv, overlay_view_offset_); 322 } 323 324 if (underlay_view_) { 325 RenderWidgetHostViewMac* underlay_rwhv = 326 static_cast<RenderWidgetHostViewMac*>( 327 underlay_view_->web_contents_->GetRenderWidgetHostView()); 328 if (underlay_rwhv) 329 underlay_rwhv->SetOverlayView(rwhv, underlay_view_->overlay_view_offset_); 330 } 331} 332 333void WebContentsViewMac::CreateView( 334 const gfx::Size& initial_size, gfx::NativeView context) { 335 WebContentsViewCocoa* view = 336 [[WebContentsViewCocoa alloc] initWithWebContentsViewMac:this]; 337 cocoa_view_.reset(view); 338} 339 340RenderWidgetHostView* WebContentsViewMac::CreateViewForWidget( 341 RenderWidgetHost* render_widget_host) { 342 if (render_widget_host->GetView()) { 343 // During testing, the view will already be set up in most cases to the 344 // test view, so we don't want to clobber it with a real one. To verify that 345 // this actually is happening (and somebody isn't accidentally creating the 346 // view twice), we check for the RVH Factory, which will be set when we're 347 // making special ones (which go along with the special views). 348 DCHECK(RenderViewHostFactory::has_factory()); 349 return render_widget_host->GetView(); 350 } 351 352 RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>( 353 RenderWidgetHostView::CreateViewForWidget(render_widget_host)); 354 if (delegate()) { 355 base::scoped_nsobject<NSObject<RenderWidgetHostViewMacDelegate> > 356 rw_delegate( 357 delegate()->CreateRenderWidgetHostViewDelegate(render_widget_host)); 358 359 view->SetDelegate(rw_delegate.get()); 360 } 361 view->SetAllowOverlappingViews(allow_overlapping_views_); 362 363 // Fancy layout comes later; for now just make it our size and resize it 364 // with us. In case there are other siblings of the content area, we want 365 // to make sure the content area is on the bottom so other things draw over 366 // it. 367 NSView* view_view = view->GetNativeView(); 368 [view_view setFrame:[cocoa_view_.get() bounds]]; 369 [view_view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 370 // Add the new view below all other views; this also keeps it below any 371 // overlay view installed. 372 [cocoa_view_.get() addSubview:view_view 373 positioned:NSWindowBelow 374 relativeTo:nil]; 375 // For some reason known only to Cocoa, the autorecalculation of the key view 376 // loop set on the window doesn't set the next key view when the subview is 377 // added. On 10.6 things magically work fine; on 10.5 they fail 378 // <http://crbug.com/61493>. Digging into Cocoa key view loop code yielded 379 // madness; TODO(avi,rohit): look at this again and figure out what's really 380 // going on. 381 [cocoa_view_.get() setNextKeyView:view_view]; 382 return view; 383} 384 385RenderWidgetHostView* WebContentsViewMac::CreateViewForPopupWidget( 386 RenderWidgetHost* render_widget_host) { 387 return RenderWidgetHostViewPort::CreateViewForWidget(render_widget_host); 388} 389 390void WebContentsViewMac::SetPageTitle(const base::string16& title) { 391 // Meaningless on the Mac; widgets don't have a "title" attribute 392} 393 394 395void WebContentsViewMac::RenderViewCreated(RenderViewHost* host) { 396 // We want updates whenever the intrinsic width of the webpage changes. 397 // Put the RenderView into that mode. The preferred width is used for example 398 // when the "zoom" button in the browser window is clicked. 399 host->EnablePreferredSizeMode(); 400} 401 402void WebContentsViewMac::RenderViewSwappedIn(RenderViewHost* host) { 403 UpdateRenderWidgetHostViewOverlay(); 404} 405 406void WebContentsViewMac::SetOverscrollControllerEnabled(bool enabled) { 407} 408 409bool WebContentsViewMac::IsEventTracking() const { 410 return base::MessagePumpMac::IsHandlingSendEvent(); 411} 412 413// Arrange to call CloseTab() after we're back to the main event loop. 414// The obvious way to do this would be PostNonNestableTask(), but that 415// will fire when the event-tracking loop polls for events. So we 416// need to bounce the message via Cocoa, instead. 417void WebContentsViewMac::CloseTabAfterEventTracking() { 418 [cocoa_view_ cancelDeferredClose]; 419 [cocoa_view_ performSelector:@selector(closeTabAfterEvent) 420 withObject:nil 421 afterDelay:0.0]; 422} 423 424void WebContentsViewMac::CloseTab() { 425 web_contents_->Close(web_contents_->GetRenderViewHost()); 426} 427 428} // namespace content 429 430@implementation WebContentsViewCocoa 431 432- (id)initWithWebContentsViewMac:(WebContentsViewMac*)w { 433 self = [super initWithFrame:NSZeroRect]; 434 if (self != nil) { 435 webContentsView_ = w; 436 dragDest_.reset( 437 [[WebDragDest alloc] initWithWebContentsImpl:[self webContents]]); 438 [self registerDragTypes]; 439 440 [[NSNotificationCenter defaultCenter] 441 addObserver:self 442 selector:@selector(viewDidBecomeFirstResponder:) 443 name:kViewDidBecomeFirstResponder 444 object:nil]; 445 446 if (webContentsView_->delegate()) { 447 [dragDest_ setDragDelegate:webContentsView_->delegate()-> 448 GetDragDestDelegate()]; 449 } 450 } 451 return self; 452} 453 454- (void)dealloc { 455 // Cancel any deferred tab closes, just in case. 456 [self cancelDeferredClose]; 457 458 // This probably isn't strictly necessary, but can't hurt. 459 [self unregisterDraggedTypes]; 460 461 [[NSNotificationCenter defaultCenter] removeObserver:self]; 462 463 [super dealloc]; 464} 465 466// Registers for the view for the appropriate drag types. 467- (void)registerDragTypes { 468 NSArray* types = [NSArray arrayWithObjects: 469 ui::kChromeDragDummyPboardType, 470 kWebURLsWithTitlesPboardType, 471 NSURLPboardType, 472 NSStringPboardType, 473 NSHTMLPboardType, 474 NSRTFPboardType, 475 NSFilenamesPboardType, 476 ui::kWebCustomDataPboardType, 477 nil]; 478 [self registerForDraggedTypes:types]; 479} 480 481- (void)setCurrentDragOperation:(NSDragOperation)operation { 482 [dragDest_ setCurrentOperation:operation]; 483} 484 485- (DropData*)dropData { 486 return [dragDest_ currentDropData]; 487} 488 489- (WebContentsImpl*)webContents { 490 if (webContentsView_ == NULL) 491 return NULL; 492 return webContentsView_->web_contents(); 493} 494 495- (void)mouseEvent:(NSEvent*)theEvent { 496 WebContentsImpl* webContents = [self webContents]; 497 if (webContents && webContents->GetDelegate()) { 498 NSPoint location = [NSEvent mouseLocation]; 499 if ([theEvent type] == NSMouseMoved) 500 webContents->GetDelegate()->ContentsMouseEvent( 501 webContents, gfx::Point(location.x, location.y), true); 502 if ([theEvent type] == NSMouseExited) 503 webContents->GetDelegate()->ContentsMouseEvent( 504 webContents, gfx::Point(location.x, location.y), false); 505 } 506} 507 508- (void)setMouseDownCanMoveWindow:(BOOL)canMove { 509 mouseDownCanMoveWindow_ = canMove; 510} 511 512- (BOOL)mouseDownCanMoveWindow { 513 // This is needed to prevent mouseDowns from moving the window 514 // around. The default implementation returns YES only for opaque 515 // views. WebContentsViewCocoa does not draw itself in any way, but 516 // its subviews do paint their entire frames. Returning NO here 517 // saves us the effort of overriding this method in every possible 518 // subview. 519 return mouseDownCanMoveWindow_; 520} 521 522- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type { 523 [dragSource_ lazyWriteToPasteboard:sender 524 forType:type]; 525} 526 527- (void)startDragWithDropData:(const DropData&)dropData 528 dragOperationMask:(NSDragOperation)operationMask 529 image:(NSImage*)image 530 offset:(NSPoint)offset { 531 dragSource_.reset([[WebDragSource alloc] 532 initWithContents:[self webContents] 533 view:self 534 dropData:&dropData 535 image:image 536 offset:offset 537 pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard] 538 dragOperationMask:operationMask]); 539 [dragSource_ startDrag]; 540} 541 542// NSDraggingSource methods 543 544// Returns what kind of drag operations are available. This is a required 545// method for NSDraggingSource. 546- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { 547 if (dragSource_) 548 return [dragSource_ draggingSourceOperationMaskForLocal:isLocal]; 549 // No web drag source - this is the case for dragging a file from the 550 // downloads manager. Default to copy operation. Note: It is desirable to 551 // allow the user to either move or copy, but this requires additional 552 // plumbing to update the download item's path once its moved. 553 return NSDragOperationCopy; 554} 555 556// Called when a drag initiated in our view ends. 557- (void)draggedImage:(NSImage*)anImage 558 endedAt:(NSPoint)screenPoint 559 operation:(NSDragOperation)operation { 560 [dragSource_ endDragAt:screenPoint operation:operation]; 561 562 // Might as well throw out this object now. 563 dragSource_.reset(); 564} 565 566// Called when a drag initiated in our view moves. 567- (void)draggedImage:(NSImage*)draggedImage movedTo:(NSPoint)screenPoint { 568 [dragSource_ moveDragTo:screenPoint]; 569} 570 571// Called when a file drag is dropped and the promised files need to be written. 572- (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest { 573 if (![dropDest isFileURL]) 574 return nil; 575 576 NSString* fileName = [dragSource_ dragPromisedFileTo:[dropDest path]]; 577 if (!fileName) 578 return nil; 579 580 return @[ fileName ]; 581} 582 583// NSDraggingDestination methods 584 585- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { 586 return [dragDest_ draggingEntered:sender view:self]; 587} 588 589- (void)draggingExited:(id<NSDraggingInfo>)sender { 590 [dragDest_ draggingExited:sender]; 591} 592 593- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { 594 return [dragDest_ draggingUpdated:sender view:self]; 595} 596 597- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { 598 return [dragDest_ performDragOperation:sender view:self]; 599} 600 601- (void)cancelDeferredClose { 602 SEL aSel = @selector(closeTabAfterEvent); 603 [NSObject cancelPreviousPerformRequestsWithTarget:self 604 selector:aSel 605 object:nil]; 606} 607 608- (void)clearWebContentsView { 609 webContentsView_ = NULL; 610 [dragSource_ clearWebContentsView]; 611} 612 613- (void)closeTabAfterEvent { 614 webContentsView_->CloseTab(); 615} 616 617- (void)viewDidBecomeFirstResponder:(NSNotification*)notification { 618 NSView* view = [notification object]; 619 if (![[self subviews] containsObject:view]) 620 return; 621 622 NSSelectionDirection direction = 623 [[[notification userInfo] objectForKey:kSelectionDirection] 624 unsignedIntegerValue]; 625 if (direction == NSDirectSelection) 626 return; 627 628 [self webContents]-> 629 FocusThroughTabTraversal(direction == NSSelectingPrevious); 630} 631 632// When the subviews require a layout, their size should be reset to the size 633// of this view. (It is possible for the size to get out of sync as an 634// optimization in preparation for an upcoming WebContentsView resize. 635// http://crbug.com/264207) 636- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { 637 for (NSView* subview in self.subviews) 638 [subview setFrame:self.bounds]; 639} 640 641@end 642