| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011 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 #include "chrome/browser/ui/views/compact_nav/compact_location_bar_view_host.h" |
| 6 |
| 7 #if defined(TOOLKIT_USES_GTK) |
| 8 #include <gtk/gtk.h> |
| 9 #endif |
| 10 |
| 11 #include <algorithm> |
| 12 |
| 13 #include "base/i18n/rtl.h" |
| 14 #include "chrome/browser/browser_process.h" |
| 15 #include "chrome/browser/platform_util.h" |
| 16 #include "chrome/browser/ui/browser.h" |
| 17 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 18 #include "chrome/browser/ui/view_ids.h" |
| 19 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" |
| 20 #include "chrome/browser/ui/views/compact_nav/compact_location_bar_view.h" |
| 21 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 22 #include "chrome/browser/ui/views/tabs/base_tab_strip.h" |
| 23 #include "content/browser/renderer_host/render_view_host.h" |
| 24 #include "content/browser/tab_contents/tab_contents.h" |
| 25 #include "content/browser/tab_contents/tab_contents_view.h" |
| 26 #include "content/common/notification_source.h" |
| 27 #include "ui/base/animation/slide_animation.h" |
| 28 #include "ui/base/keycodes/keyboard_codes.h" |
| 29 #include "ui/gfx/rect.h" |
| 30 #include "views/controls/scrollbar/native_scroll_bar.h" |
| 31 #include "views/events/event.h" |
| 32 #include "views/focus/external_focus_tracker.h" |
| 33 #include "views/focus/view_storage.h" |
| 34 #include "views/widget/root_view.h" |
| 35 #include "views/widget/widget.h" |
| 36 |
| 37 namespace { |
| 38 |
| 39 const int kHideTimeoutInSeconds = 2; |
| 40 // TODO(stevet): Share this with CompactLocationBarView. This is the actual |
| 41 // height, without the overlap added. |
| 42 const int kCompactNavbarSpacerHeight = 4; |
| 43 const int kBookmarkBarLocationBarOverlap = 2; |
| 44 const int kSpacerLocationbarOverlap = 1; |
| 45 |
| 46 } // namespace |
| 47 |
| 48 // An mouse event observer to detect a mouse click on |
| 49 // BrowserView's content area and hide the location bar. |
| 50 class MouseObserver : public MessageLoopForUI::Observer { |
| 51 public: |
| 52 MouseObserver(CompactLocationBarViewHost* host, BrowserView* view); |
| 53 ~MouseObserver(); |
| 54 |
| 55 // MessageLoopForUI::Observer overrides. |
| 56 #if defined(OS_WIN) |
| 57 virtual void WillProcessMessage(const MSG& native_event) OVERRIDE; |
| 58 virtual void DidProcessMessage(const MSG& native_event) OVERRIDE; |
| 59 #elif defined(OS_LINUX) |
| 60 virtual void WillProcessEvent(GdkEvent* native_event) OVERRIDE; |
| 61 virtual void DidProcessEvent(GdkEvent* native_event) OVERRIDE; |
| 62 #endif |
| 63 |
| 64 void Observe(MessageLoopForUI* loop); |
| 65 void StopObserving(MessageLoopForUI* loop); |
| 66 |
| 67 private: |
| 68 // TODO(mad): would be nice to have this on the views::Event class. |
| 69 bool IsMouseEvent(const views::NativeEvent& native_event); |
| 70 |
| 71 bool IsSameTopLevelWindow(views::NativeEvent native_event); |
| 72 |
| 73 // Tests if the event occurred on the content area, using |
| 74 // root window's coordinates. |
| 75 bool HitContentArea(int x, int y); |
| 76 |
| 77 // Tests if |p| in the root window's coordinate is within the |view|'s bound. |
| 78 bool HitOnScreen(const views::View* view, const gfx::Point& p); |
| 79 |
| 80 CompactLocationBarViewHost* host_; |
| 81 BrowserView* browser_view_; |
| 82 gfx::NativeView top_level_window_; |
| 83 bool observing_; |
| 84 |
| 85 DISALLOW_COPY_AND_ASSIGN(MouseObserver); |
| 86 }; |
| 87 |
| 88 MouseObserver::MouseObserver(CompactLocationBarViewHost* host, |
| 89 BrowserView* view) |
| 90 : host_(host), |
| 91 browser_view_(view), |
| 92 observing_(false) { |
| 93 top_level_window_ = browser_view_->GetWidget()->GetNativeView(); |
| 94 } |
| 95 |
| 96 MouseObserver::~MouseObserver() { |
| 97 StopObserving(MessageLoopForUI::current()); |
| 98 } |
| 99 |
| 100 #if defined(OS_WIN) |
| 101 void MouseObserver::WillProcessMessage(const MSG& native_event) {} |
| 102 void MouseObserver::DidProcessMessage(const MSG& native_event) { |
| 103 #elif defined(OS_LINUX) |
| 104 void MouseObserver::WillProcessEvent(GdkEvent* native_event) OVERRIDE {} |
| 105 void MouseObserver::DidProcessEvent(GdkEvent* native_event) OVERRIDE { |
| 106 #endif |
| 107 // Hide the location bar iff the mouse is pressed on the |
| 108 // BrowserView's content area. |
| 109 if (!IsMouseEvent(native_event)) |
| 110 return; |
| 111 views::MouseEvent event(native_event); |
| 112 if (event.type() == ui::ET_MOUSE_PRESSED && |
| 113 IsSameTopLevelWindow(native_event) && |
| 114 HitContentArea(event.x(), event.y())) { |
| 115 host_->Hide(true); |
| 116 } |
| 117 } |
| 118 |
| 119 void MouseObserver::Observe(MessageLoopForUI* loop) { |
| 120 if (!observing_) { |
| 121 loop->AddObserver(this); |
| 122 observing_ = true; |
| 123 } |
| 124 } |
| 125 |
| 126 void MouseObserver::StopObserving(MessageLoopForUI* loop) { |
| 127 if (observing_) { |
| 128 loop->RemoveObserver(this); |
| 129 observing_ = false; |
| 130 } |
| 131 } |
| 132 |
| 133 bool MouseObserver::IsMouseEvent(const views::NativeEvent& native_event) { |
| 134 #if defined(OS_WIN) |
| 135 return views::IsClientMouseEvent(native_event) || |
| 136 views::IsNonClientMouseEvent(native_event); |
| 137 #elif defined(OS_LINUX) |
| 138 return native_event->type == GDK_MOTION_NOTIFY || |
| 139 native_event->type == GDK_BUTTON_PRESS || |
| 140 native_event->type == GDK_2BUTTON_PRESS || |
| 141 native_event->type == GDK_3BUTTON_PRESS || |
| 142 native_event->type == GDK_BUTTON_RELEASE; |
| 143 #endif |
| 144 } |
| 145 |
| 146 // TODO(mad): Would be nice to have a NativeEvent -> NativeWindow mapping. |
| 147 // Then, with a GetTopLevel receiving a NativeWindow, we could do this in a |
| 148 // platform independent way. |
| 149 bool MouseObserver::IsSameTopLevelWindow(views::NativeEvent native_event) { |
| 150 #if defined(OS_WIN) |
| 151 return platform_util::GetTopLevel(native_event.hwnd) == top_level_window_; |
| 152 #elif defined(OS_LINUX) |
| 153 return gdk_window_get_toplevel( |
| 154 static_cast<GdkEventAny*>(native_event)->window) == |
| 155 top_level_window_->window; |
| 156 #endif |
| 157 } |
| 158 |
| 159 bool MouseObserver::HitContentArea(int x, int y) { |
| 160 gfx::Point p(x, y); |
| 161 // First, exclude the location bar as it's shown on top of |
| 162 // content area. |
| 163 if (HitOnScreen(host_->view(), p)) { |
| 164 return false; |
| 165 } |
| 166 // Treat the bookmark as a content area when it in detached mode. |
| 167 if (browser_view_->GetBookmarkBarView()->IsDetached() && |
| 168 browser_view_->IsBookmarkBarVisible() && |
| 169 HitOnScreen(browser_view_->GetBookmarkBarView(), p)) { |
| 170 return true; |
| 171 } |
| 172 if (HitOnScreen(browser_view_->GetContentsView(), p)) { |
| 173 return true; |
| 174 } |
| 175 return false; |
| 176 } |
| 177 |
| 178 bool MouseObserver::HitOnScreen(const views::View* view, const gfx::Point& p) { |
| 179 gfx::Point origin(0, 0); |
| 180 views::View::ConvertPointToScreen(view, &origin); |
| 181 gfx::Rect new_bounds(origin, view->size()); |
| 182 return new_bounds.Contains(p); |
| 183 } |
| 184 |
| 185 //////////////////////////////////////////////////////////////////////////////// |
| 186 // CompactLocationBarViewHost, public: |
| 187 |
| 188 CompactLocationBarViewHost::CompactLocationBarViewHost( |
| 189 BrowserView* browser_view) : DropdownBarHost(browser_view), |
| 190 current_tab_model_index_(-1), |
| 191 is_observing_(false) { |
| 192 auto_hide_timer_.reset(new base::OneShotTimer<CompactLocationBarViewHost>()); |
| 193 mouse_observer_.reset(new MouseObserver(this, browser_view)); |
| 194 CompactLocationBarView* clbv = new CompactLocationBarView(this); |
| 195 Init(clbv, clbv); |
| 196 } |
| 197 |
| 198 CompactLocationBarViewHost::~CompactLocationBarViewHost() { |
| 199 // This may happen if we are destroyed during cleanup. |
| 200 if (browser_view() && browser_view()->browser() && |
| 201 browser_view()->browser()->tabstrip_model()) { |
| 202 browser_view()->browser()->tabstrip_model()->RemoveObserver(this); |
| 203 } |
| 204 } |
| 205 |
| 206 CompactLocationBarView* CompactLocationBarViewHost:: |
| 207 GetCompactLocationBarView() { |
| 208 return static_cast<CompactLocationBarView*>(view()); |
| 209 } |
| 210 |
| 211 void CompactLocationBarViewHost::MoveWindowIfNecessary( |
| 212 const gfx::Rect& selection_rect, |
| 213 bool no_redraw) { |
| 214 // We only move the window if one is currently shown. If we don't check |
| 215 // this, then SetWidgetPosition below will end up making the Location Bar |
| 216 // visible. |
| 217 if (!IsVisible()) |
| 218 return; |
| 219 |
| 220 gfx::Rect new_pos = GetDialogPosition(selection_rect); |
| 221 SetDialogPosition(new_pos, no_redraw); |
| 222 |
| 223 // May need to redraw our frame to accommodate bookmark bar styles. |
| 224 view()->SchedulePaint(); |
| 225 } |
| 226 |
| 227 //////////////////////////////////////////////////////////////////////////////// |
| 228 // LocationBarView::Delegate implementation: |
| 229 TabContentsWrapper* CompactLocationBarViewHost::GetTabContentsWrapper() const { |
| 230 return browser_view()->browser()->GetSelectedTabContentsWrapper(); |
| 231 } |
| 232 |
| 233 InstantController* CompactLocationBarViewHost::GetInstant() { |
| 234 // TODO(stevet): Re-enable instant for compact nav. |
| 235 // return browser_view()->browser()->instant(); |
| 236 return NULL; |
| 237 } |
| 238 |
| 239 void CompactLocationBarViewHost::OnInputInProgress(bool in_progress) { |
| 240 } |
| 241 |
| 242 //////////////////////////////////////////////////////////////////////////////// |
| 243 // CompactLocationBarViewHost, views::AcceleratorTarget implementation: |
| 244 |
| 245 bool CompactLocationBarViewHost::AcceleratorPressed( |
| 246 const views::Accelerator& accelerator) { |
| 247 if (HasFocus()) { |
| 248 DCHECK(view() != NULL); |
| 249 views::FocusManager* focus_manager = view()->GetFocusManager(); |
| 250 if (focus_manager) |
| 251 focus_manager->ClearFocus(); |
| 252 } |
| 253 Hide(true); |
| 254 return false; |
| 255 } |
| 256 |
| 257 //////////////////////////////////////////////////////////////////////////////// |
| 258 // CompactLocationBarViewHost, views::DropdownBarHost implementation: |
| 259 |
| 260 gfx::Rect CompactLocationBarViewHost::GetDialogPosition( |
| 261 gfx::Rect avoid_overlapping_rect) { |
| 262 if (!browser_view() || !browser_view()->browser() || |
| 263 !browser_view()->browser()->tabstrip_model()) { |
| 264 return gfx::Rect(); |
| 265 } |
| 266 DCHECK_GE(current_tab_model_index_, 0); |
| 267 if (!browser_view()->browser()->tabstrip_model()->ContainsIndex( |
| 268 current_tab_model_index_)) { |
| 269 return gfx::Rect(); |
| 270 } |
| 271 |
| 272 gfx::Rect new_pos = GetBoundsUnderTab(current_tab_model_index_); |
| 273 |
| 274 if (animation_offset() > 0) |
| 275 new_pos.Offset(0, std::min(0, -animation_offset())); |
| 276 return new_pos; |
| 277 } |
| 278 |
| 279 void CompactLocationBarViewHost::SetDialogPosition(const gfx::Rect& new_pos, |
| 280 bool no_redraw) { |
| 281 if (new_pos.IsEmpty()) |
| 282 return; |
| 283 |
| 284 // Make sure the window edges are clipped to just the visible region. We need |
| 285 // to do this before changing position, so that when we animate the closure |
| 286 // of it it doesn't look like the window crumbles into the toolbar. |
| 287 UpdateWindowEdges(new_pos); |
| 288 |
| 289 // TODO(oshima): Animate the window clipping like find-bar. |
| 290 SetWidgetPositionNative(new_pos, no_redraw); |
| 291 } |
| 292 |
| 293 //////////////////////////////////////////////////////////////////////////////// |
| 294 // CompactLocationBarViewHost, views::TabStripModelObserver implementation: |
| 295 |
| 296 void CompactLocationBarViewHost::TabClosingAt(TabStripModel* tab_strip_model, |
| 297 TabContentsWrapper* contents, |
| 298 int index) { |
| 299 // TODO(stevet): We need to relocate the compact navigation bar if the |
| 300 // removed tab is not the one we are currently under but the tabstrip does |
| 301 // not have the ideal location yet because the tabs are animating at this |
| 302 // time. Need to investigate the best way to handle this case. |
| 303 Hide(false); |
| 304 } |
| 305 |
| 306 void CompactLocationBarViewHost::TabSelectedAt(TabContentsWrapper* old_contents, |
| 307 TabContentsWrapper* new_contents, |
| 308 int index, |
| 309 bool user_gesture) { |
| 310 current_tab_model_index_ = index; |
| 311 if (new_contents && new_contents->tab_contents()->is_loading()) { |
| 312 Show(false); |
| 313 } else { |
| 314 Hide(false); |
| 315 } |
| 316 } |
| 317 |
| 318 void CompactLocationBarViewHost::TabMoved(TabContentsWrapper* contents, |
| 319 int from_index, |
| 320 int to_index) { |
| 321 if (from_index == current_tab_model_index_) { |
| 322 UpdateOnTabChange(to_index, false); |
| 323 StartAutoHideTimer(); |
| 324 } |
| 325 } |
| 326 |
| 327 void CompactLocationBarViewHost::TabChangedAt(TabContentsWrapper* contents, |
| 328 int index, |
| 329 TabChangeType change_type) { |
| 330 if (IsCurrentTabIndex(index) && change_type == |
| 331 TabStripModelObserver::LOADING_ONLY) { |
| 332 bool was_not_visible = !IsVisible(); |
| 333 TabContents* tab_contents = contents->tab_contents(); |
| 334 Update(tab_contents, false); |
| 335 if (was_not_visible) { |
| 336 if (tab_contents->is_loading()) { |
| 337 // Register to NavigationController LOAD_STOP so that we can autohide |
| 338 // when loading is done. |
| 339 if (!registrar_.IsRegistered(this, NotificationType::LOAD_STOP, |
| 340 Source<NavigationController>(&tab_contents->controller()))) { |
| 341 registrar_.Add(this, NotificationType::LOAD_STOP, |
| 342 Source<NavigationController>(&tab_contents->controller())); |
| 343 } |
| 344 } else { |
| 345 StartAutoHideTimer(); |
| 346 } |
| 347 } |
| 348 } |
| 349 } |
| 350 |
| 351 void CompactLocationBarViewHost::ActiveTabClicked(int index) { |
| 352 UpdateOnTabChange(index, true); |
| 353 } |
| 354 |
| 355 //////////////////////////////////////////////////////////////////////////////// |
| 356 // CompactLocationBarViewHost, NotificationObserver implementation: |
| 357 |
| 358 void CompactLocationBarViewHost::Observe(NotificationType type, |
| 359 const NotificationSource& source, |
| 360 const NotificationDetails& details) { |
| 361 switch (type.value) { |
| 362 case NotificationType::LOAD_STOP: { |
| 363 StartAutoHideTimer(); |
| 364 // This is one shot deal... |
| 365 registrar_.Remove(this, NotificationType::LOAD_STOP, source); |
| 366 break; |
| 367 } |
| 368 default: |
| 369 NOTREACHED(); |
| 370 } |
| 371 } |
| 372 |
| 373 //////////////////////////////////////////////////////////////////////////////// |
| 374 // CompactLocationBarViewHost public: |
| 375 |
| 376 gfx::Rect CompactLocationBarViewHost::GetBoundsUnderTab(int model_index) const { |
| 377 DCHECK(!browser_view()->UseVerticalTabs()); |
| 378 |
| 379 // Get the position of the left-bottom corner of the tab on the |
| 380 // widget. The widget of the tab is same as the widget of the |
| 381 // BrowserView which is the parent of the host. |
| 382 BaseTabStrip* tabstrip = |
| 383 static_cast<BaseTabStrip*>(browser_view()->tabstrip()); |
| 384 gfx::Rect tab_bounds = |
| 385 tabstrip->ideal_bounds(tabstrip->ModelIndexToTabIndex(model_index)); |
| 386 gfx::Rect navbar_bounds(gfx::Point(tab_bounds.x(), tab_bounds.height()), |
| 387 view()->GetPreferredSize()); |
| 388 |
| 389 // Convert our point to be relative to the widget, since the native code that |
| 390 // draws the dropdown is not in the BrowserView coordinate system. |
| 391 gfx::Point origin = navbar_bounds.origin(); |
| 392 views::View::ConvertPointToWidget(browser_view(), &origin); |
| 393 navbar_bounds.set_origin(origin); |
| 394 |
| 395 // For RTL case x() defines tab right corner. |
| 396 if (base::i18n::IsRTL()) |
| 397 navbar_bounds.Offset(tab_bounds.width(), 0); |
| 398 navbar_bounds.Offset(tabstrip->x(), tabstrip->y()); |
| 399 |
| 400 // The compact location bar must be smaller than browser_width. |
| 401 int width = std::min(browser_view()->width(), |
| 402 view()->GetPreferredSize().width()); |
| 403 |
| 404 // Try to center around the tab. |
| 405 navbar_bounds.set_x(browser_view()->GetMirroredXInView( |
| 406 navbar_bounds.x()) - ((width - tab_bounds.width()) / 2)); |
| 407 |
| 408 // Adjust the location to create the illusion that the compact location bar |
| 409 // is a part of the spacer or bookmark bar, depending on which is showing. |
| 410 if (browser_view()->IsBookmarkBarVisible() && |
| 411 !browser_view()->GetBookmarkBarView()->IsDetached()) { |
| 412 // TODO(stevet): Compact location bar does not have right background image |
| 413 // yet, so kBookmarkBarLocationBarOverlap is tentative. Fix this once UI is |
| 414 // settled. This may be entirely replaced by a popup CLB, anyway. |
| 415 navbar_bounds.Offset(0, |
| 416 browser_view()->GetBookmarkBarView()->bounds().height() + |
| 417 kCompactNavbarSpacerHeight - kBookmarkBarLocationBarOverlap); |
| 418 } else { |
| 419 // TODO(stevet): kSpacerLocationbarOverlap is tentative as well, as above. |
| 420 navbar_bounds.Offset(0, kCompactNavbarSpacerHeight - |
| 421 kSpacerLocationbarOverlap); |
| 422 } |
| 423 |
| 424 // TODO(stevet): Adjust to the right if there is an info bar visible. |
| 425 return navbar_bounds.AdjustToFit(browser_view()->bounds()); |
| 426 } |
| 427 |
| 428 void CompactLocationBarViewHost::Update(TabContents* contents, bool animate) { |
| 429 // Don't animate if the bar is already shown. |
| 430 bool showing_in_same_tab = animation()->IsShowing() && IsCurrentTab(contents); |
| 431 current_tab_model_index_ = browser_view()->browser()->active_index(); |
| 432 Hide(false); |
| 433 GetCompactLocationBarView()->Update(contents); |
| 434 Show(animate && !showing_in_same_tab); |
| 435 // If the tab is loading, we must wait for the notification that it is done. |
| 436 if (contents && !contents->is_loading()) { |
| 437 // This will be a NOOP if we have focus. |
| 438 // We never want to stay up, unless we have focus. |
| 439 StartAutoHideTimer(); |
| 440 } |
| 441 } |
| 442 |
| 443 void CompactLocationBarViewHost::UpdateOnTabChange(int model_index, |
| 444 bool animate) { |
| 445 DCHECK_GE(model_index, 0); |
| 446 if (IsCurrentTabIndex(model_index) && animation()->IsShowing()) { |
| 447 return; |
| 448 } |
| 449 current_tab_model_index_ = model_index; |
| 450 Update(browser_view()->browser()->tabstrip_model()-> |
| 451 GetTabContentsAt(model_index)->tab_contents(), animate); |
| 452 } |
| 453 |
| 454 void CompactLocationBarViewHost::StartAutoHideTimer() { |
| 455 if (!IsVisible() || HasFocus()) |
| 456 return; |
| 457 |
| 458 if (auto_hide_timer_->IsRunning()) { |
| 459 // Restart the timer. |
| 460 auto_hide_timer_->Reset(); |
| 461 } else { |
| 462 auto_hide_timer_->Start(base::TimeDelta::FromSeconds(kHideTimeoutInSeconds), |
| 463 this, &CompactLocationBarViewHost::HideCallback); |
| 464 } |
| 465 } |
| 466 |
| 467 void CompactLocationBarViewHost::CancelAutoHideTimer() { |
| 468 auto_hide_timer_->Stop(); |
| 469 } |
| 470 |
| 471 void CompactLocationBarViewHost::SetEnabled(bool enabled) { |
| 472 if (enabled && !is_observing_) { |
| 473 browser_view()->browser()->tabstrip_model()->AddObserver(this); |
| 474 is_observing_ = true; |
| 475 } else { |
| 476 browser_view()->browser()->tabstrip_model()->RemoveObserver(this); |
| 477 is_observing_ = false; |
| 478 } |
| 479 } |
| 480 |
| 481 void CompactLocationBarViewHost::Show(bool animate) { |
| 482 CancelAutoHideTimer(); |
| 483 mouse_observer_->Observe(MessageLoopForUI::current()); |
| 484 DropdownBarHost::Show(animate); |
| 485 host()->Show(); |
| 486 } |
| 487 |
| 488 void CompactLocationBarViewHost::Hide(bool animate) { |
| 489 CancelAutoHideTimer(); |
| 490 mouse_observer_->StopObserving(MessageLoopForUI::current()); |
| 491 host()->Hide(); |
| 492 DropdownBarHost::Hide(animate); |
| 493 } |
| 494 |
| 495 //////////////////////////////////////////////////////////////////////////////// |
| 496 // CompactLocationBarViewHost private: |
| 497 bool CompactLocationBarViewHost::HasFocus() { |
| 498 DCHECK(view() != NULL); |
| 499 views::FocusManager* focus_manager = view()->GetFocusManager(); |
| 500 return focus_manager && view()->Contains(focus_manager->GetFocusedView()); |
| 501 } |
| 502 |
| 503 void CompactLocationBarViewHost::HideCallback() { |
| 504 if (IsVisible() && !HasFocus()) |
| 505 Hide(true); |
| 506 } |
| 507 |
| 508 bool CompactLocationBarViewHost::IsCurrentTabIndex(int index) { |
| 509 return current_tab_model_index_ == index; |
| 510 } |
| 511 |
| 512 bool CompactLocationBarViewHost::IsCurrentTab(TabContents* contents) { |
| 513 TabStripModel* tab_strip_model = browser_view()->browser()->tabstrip_model(); |
| 514 return tab_strip_model->ContainsIndex(current_tab_model_index_) && |
| 515 tab_strip_model->GetTabContentsAt(current_tab_model_index_)-> |
| 516 tab_contents() == contents; |
| 517 } |
| OLD | NEW |