Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/frame/browser_view_layout.h" | 5 #include "chrome/browser/ui/views/frame/browser_view_layout.h" |
| 6 | 6 |
| 7 #include "base/observer_list.h" | 7 #include "base/observer_list.h" |
| 8 #include "chrome/browser/profiles/profile.h" | 8 #include "chrome/browser/profiles/profile.h" |
| 9 #include "chrome/browser/ui/browser_finder.h" | 9 #include "chrome/browser/ui/browser_finder.h" |
| 10 #include "chrome/browser/ui/find_bar/find_bar.h" | 10 #include "chrome/browser/ui/find_bar/find_bar.h" |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 #include "chrome/browser/ui/views/tabs/tab_strip.h" | 22 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
| 23 #include "chrome/browser/ui/views/toolbar_view.h" | 23 #include "chrome/browser/ui/views/toolbar_view.h" |
| 24 #include "chrome/browser/ui/web_contents_modal_dialog_host.h" | 24 #include "chrome/browser/ui/web_contents_modal_dialog_host.h" |
| 25 #include "ui/base/hit_test.h" | 25 #include "ui/base/hit_test.h" |
| 26 #include "ui/gfx/point.h" | 26 #include "ui/gfx/point.h" |
| 27 #include "ui/gfx/scrollbar_size.h" | 27 #include "ui/gfx/scrollbar_size.h" |
| 28 #include "ui/gfx/size.h" | 28 #include "ui/gfx/size.h" |
| 29 #include "ui/views/controls/single_split_view.h" | 29 #include "ui/views/controls/single_split_view.h" |
| 30 #include "ui/views/controls/webview/webview.h" | 30 #include "ui/views/controls/webview/webview.h" |
| 31 | 31 |
| 32 using views::View; | |
| 33 | |
| 32 namespace { | 34 namespace { |
| 33 | 35 |
| 34 // The visible height of the shadow above the tabs. Clicks in this area are | 36 // The visible height of the shadow above the tabs. Clicks in this area are |
| 35 // treated as clicks to the frame, rather than clicks to the tab. | 37 // treated as clicks to the frame, rather than clicks to the tab. |
| 36 const int kTabShadowSize = 2; | 38 const int kTabShadowSize = 2; |
| 37 // The vertical overlap between the TabStrip and the Toolbar. | |
| 38 const int kToolbarTabStripVerticalOverlap = 3; | |
| 39 // The number of pixels the bookmark bar should overlap the spacer by if the | 39 // The number of pixels the bookmark bar should overlap the spacer by if the |
| 40 // spacer is visible. | 40 // spacer is visible. |
| 41 const int kSpacerBookmarkBarOverlap = 1; | 41 const int kSpacerBookmarkBarOverlap = 1; |
| 42 // The number of pixels the metro switcher is offset from the right edge. | 42 // The number of pixels the metro switcher is offset from the right edge. |
| 43 const int kWindowSwitcherOffsetX = 7; | 43 const int kWindowSwitcherOffsetX = 7; |
| 44 // The number of pixels the constrained window should overlap the bottom | 44 // The number of pixels the constrained window should overlap the bottom |
| 45 // of the omnibox. | 45 // of the omnibox. |
| 46 const int kConstrainedWindowOverlap = 3; | 46 const int kConstrainedWindowOverlap = 3; |
| 47 | 47 |
| 48 // Combines View::ConvertPointToTarget and View::HitTest for a given |point|. | 48 // Combines View::ConvertPointToTarget and View::HitTest for a given |point|. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 93 observer_list_.RemoveObserver(observer); | 93 observer_list_.RemoveObserver(observer); |
| 94 } | 94 } |
| 95 | 95 |
| 96 const BrowserViewLayout* browser_view_layout_; | 96 const BrowserViewLayout* browser_view_layout_; |
| 97 | 97 |
| 98 ObserverList<WebContentsModalDialogHostObserver> observer_list_; | 98 ObserverList<WebContentsModalDialogHostObserver> observer_list_; |
| 99 | 99 |
| 100 DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogHostViews); | 100 DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogHostViews); |
| 101 }; | 101 }; |
| 102 | 102 |
| 103 // static | |
| 104 const int BrowserViewLayout::kToolbarTabStripVerticalOverlap = 3; | |
| 103 | 105 |
| 104 //////////////////////////////////////////////////////////////////////////////// | 106 //////////////////////////////////////////////////////////////////////////////// |
| 105 // BrowserViewLayout, public: | 107 // BrowserViewLayout, public: |
| 106 | 108 |
| 107 BrowserViewLayout::BrowserViewLayout() | 109 BrowserViewLayout::BrowserViewLayout() |
| 108 : contents_split_(NULL), | 110 : contents_split_(NULL), |
| 109 contents_container_(NULL), | 111 contents_container_(NULL), |
| 110 download_shelf_(NULL), | 112 download_shelf_(NULL), |
| 111 browser_view_(NULL), | 113 browser_view_(NULL), |
| 112 find_bar_y_(0), | 114 find_bar_y_(0), |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 324 browser_view_->frame()->GetTabStripInsets(false).top)); | 326 browser_view_->frame()->GetTabStripInsets(false).top)); |
| 325 } | 327 } |
| 326 top = LayoutToolbar(top); | 328 top = LayoutToolbar(top); |
| 327 top = LayoutBookmarkAndInfoBars(top); | 329 top = LayoutBookmarkAndInfoBars(top); |
| 328 | 330 |
| 329 // Top container requires updated toolbar and bookmark bar to compute size. | 331 // Top container requires updated toolbar and bookmark bar to compute size. |
| 330 browser_view_->top_container_->SetSize( | 332 browser_view_->top_container_->SetSize( |
| 331 browser_view_->top_container_->GetPreferredSize()); | 333 browser_view_->top_container_->GetPreferredSize()); |
| 332 | 334 |
| 333 int bottom = LayoutDownloadShelf(browser_view_->height()); | 335 int bottom = LayoutDownloadShelf(browser_view_->height()); |
| 334 int active_top_margin = GetTopMarginForActiveContent(); | 336 LayoutTabContents(top, bottom, old_contents_origin); |
| 335 top -= active_top_margin; | |
| 336 contents_container_->SetActiveTopMargin(active_top_margin); | |
| 337 LayoutTabContents(top, bottom); | |
| 338 | |
| 339 // Now set the contents to display at their previous origin if we just hid the | |
| 340 // bookmark and/or infobars. | |
| 341 if (active_top_margin == 0 && !old_contents_origin.IsOrigin()) { | |
| 342 gfx::Point new_contents_origin(contents->bounds().origin()); | |
| 343 views::View::ConvertPointToTarget(contents->parent(), browser_view_, | |
| 344 &new_contents_origin); | |
| 345 active_top_margin = old_contents_origin.y() - new_contents_origin.y(); | |
| 346 // Special case: While normally the suggestions appear to "cover" any | |
| 347 // bookmark/infobars, if the suggestions are very short, they might not | |
| 348 // fully cover that gap, and leaving the contents at their original height | |
| 349 // would leave an odd-looking blank space. In this case, we allow the | |
| 350 // contents to go ahead and shift upward. | |
| 351 if (active_top_margin > 0 && active_top_margin < overlay_height) | |
| 352 contents_container_->SetActiveTopMargin(active_top_margin); | |
| 353 } | |
| 354 | 337 |
| 355 // This must be done _after_ we lay out the WebContents since this | 338 // This must be done _after_ we lay out the WebContents since this |
| 356 // code calls back into us to find the bounding box the find bar | 339 // code calls back into us to find the bounding box the find bar |
| 357 // must be laid out within, and that code depends on the | 340 // must be laid out within, and that code depends on the |
| 358 // TabContentsContainer's bounds being up to date. | 341 // TabContentsContainer's bounds being up to date. |
| 359 if (browser()->HasFindBarController()) { | 342 if (browser()->HasFindBarController()) { |
| 360 browser()->GetFindBarController()->find_bar()->MoveWindowIfNecessary( | 343 browser()->GetFindBarController()->find_bar()->MoveWindowIfNecessary( |
| 361 gfx::Rect(), true); | 344 gfx::Rect(), true); |
| 362 } | 345 } |
| 363 | 346 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 468 find_bar_y_ = top + browser_view_->y() - 1; | 451 find_bar_y_ = top + browser_view_->y() - 1; |
| 469 return LayoutInfoBar(top); | 452 return LayoutInfoBar(top); |
| 470 } | 453 } |
| 471 | 454 |
| 472 int BrowserViewLayout::LayoutBookmarkBar(int top) { | 455 int BrowserViewLayout::LayoutBookmarkBar(int top) { |
| 473 BookmarkBarView* bookmark_bar = browser_view_->bookmark_bar_view_.get(); | 456 BookmarkBarView* bookmark_bar = browser_view_->bookmark_bar_view_.get(); |
| 474 DCHECK(bookmark_bar); | 457 DCHECK(bookmark_bar); |
| 475 int y = top; | 458 int y = top; |
| 476 if (!browser_view_->IsBookmarkBarVisible()) { | 459 if (!browser_view_->IsBookmarkBarVisible()) { |
| 477 bookmark_bar->SetVisible(false); | 460 bookmark_bar->SetVisible(false); |
| 461 // TODO(jamescook): Don't change the bookmark bar height when it is | |
| 462 // invisible, so we can use its height for layout even in that state. | |
| 478 bookmark_bar->SetBounds(0, y, browser_view_->width(), 0); | 463 bookmark_bar->SetBounds(0, y, browser_view_->width(), 0); |
| 479 return y; | 464 return y; |
| 480 } | 465 } |
| 481 | 466 |
| 482 bookmark_bar->set_infobar_visible(InfobarVisible()); | 467 bookmark_bar->set_infobar_visible(InfobarVisible()); |
| 483 int bookmark_bar_height = bookmark_bar->GetPreferredSize().height(); | 468 int bookmark_bar_height = bookmark_bar->GetPreferredSize().height(); |
| 484 y -= views::NonClientFrameView::kClientEdgeThickness + | 469 y -= views::NonClientFrameView::kClientEdgeThickness + |
| 485 bookmark_bar->GetToolbarOverlap(false); | 470 bookmark_bar->GetToolbarOverlap(false); |
| 486 bookmark_bar->SetVisible(true); | 471 bookmark_bar->SetVisible(true); |
| 487 bookmark_bar->SetBounds(vertical_layout_rect_.x(), y, | 472 bookmark_bar->SetBounds(vertical_layout_rect_.x(), y, |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 503 infobar_container->SetVisible(InfobarVisible()); | 488 infobar_container->SetVisible(InfobarVisible()); |
| 504 int height; | 489 int height; |
| 505 int overlapped_top = top - infobar_container->GetVerticalOverlap(&height); | 490 int overlapped_top = top - infobar_container->GetVerticalOverlap(&height); |
| 506 infobar_container->SetBounds(vertical_layout_rect_.x(), | 491 infobar_container->SetBounds(vertical_layout_rect_.x(), |
| 507 overlapped_top, | 492 overlapped_top, |
| 508 vertical_layout_rect_.width(), | 493 vertical_layout_rect_.width(), |
| 509 height); | 494 height); |
| 510 return overlapped_top + height; | 495 return overlapped_top + height; |
| 511 } | 496 } |
| 512 | 497 |
| 513 void BrowserViewLayout::LayoutTabContents(int top, int bottom) { | 498 void BrowserViewLayout::LayoutTabContents( |
| 514 // The ultimate idea is to calculate bounds and reserved areas for all | 499 int top, |
| 515 // contents views first and then resize them all, so every view | 500 int bottom, |
| 516 // (and its contents) is resized and laid out only once. | 501 const gfx::Point& contents_origin) { |
| 502 // Vertical offsets for the active page and instant overlay. | |
| 503 int active_top_margin = GetTopMarginForActiveContent(); | |
| 504 int overlay_top_margin = 0; | |
| 517 | 505 |
| 518 // The views hierarcy (see browser_view.h for more details): | 506 // |contents_split_| contains web page contents and devtools. |
| 519 // contents_split_ -> [contents_container_ | devtools] | 507 // See browser_view.h for details. |
| 520 | 508 top -= active_top_margin; |
| 521 gfx::Rect contents_bounds; | 509 gfx::Rect contents_split_bounds(vertical_layout_rect_.x(), |
| 522 gfx::Rect devtools_bounds; | 510 top, |
| 523 | |
| 524 gfx::Rect contents_split_bounds(vertical_layout_rect_.x(), top, | |
| 525 vertical_layout_rect_.width(), | 511 vertical_layout_rect_.width(), |
| 526 std::max(0, bottom - top)); | 512 std::max(0, bottom - top)); |
| 527 gfx::Point contents_split_offset( | 513 contents_split_->SetBoundsRect(contents_split_bounds); |
|
James Cook
2013/04/05 02:05:05
The diff is confusing - LayoutTabContents() contai
kuan
2013/04/08 15:56:30
if SetBoundsRect changes bounds of contents_contai
kuan
2013/04/08 16:05:33
in the scenario that fails, Layout is called separ
| |
| 528 contents_split_bounds.x() - contents_split_->bounds().x(), | |
| 529 contents_split_bounds.y() - contents_split_->bounds().y()); | |
| 530 | 514 |
| 531 // Layout resize corner and calculate reserved contents rects here as all | 515 // During an immersive reveal, if instant extended is showing suggestions |
| 532 // contents view bounds are already determined, but not yet set at this point, | 516 // (either in an overlay web view or the active web view) ensure the |
| 533 // so contents will be laid out once at most. | 517 // the web view appears aligned with the bottom of the omnibox. |
| 534 gfx::Rect browser_reserved_rect; | 518 InstantUIState instant_ui_state = GetInstantUIState(); |
| 535 if (!browser_view_->frame_->IsMaximized() && | 519 if (instant_ui_state != kInstantUINone && |
| 536 !browser_view_->frame_->IsFullscreen()) { | 520 browser_view_->immersive_mode_controller()->IsRevealed()) { |
| 537 gfx::Size resize_corner_size = browser_view_->GetResizeCornerSize(); | 521 gfx::Point bottom_edge(0, browser_view_->top_container_->height()); |
| 538 if (!resize_corner_size.IsEmpty()) { | 522 views::View::ConvertPointToTarget(browser_view_->top_container_, |
| 539 gfx::Rect bounds = browser_view_->GetContentsBounds(); | 523 contents_container_, |
| 540 gfx::Point resize_corner_origin( | 524 &bottom_edge); |
| 541 bounds.right() - resize_corner_size.width(), | 525 switch (instant_ui_state) { |
| 542 bounds.bottom() - resize_corner_size.height()); | 526 case kInstantUINone: |
| 543 browser_reserved_rect = | 527 break; |
| 544 gfx::Rect(resize_corner_origin, resize_corner_size); | 528 case kInstantUIOverlay: |
| 529 overlay_top_margin = bottom_edge.y(); | |
| 530 break; | |
| 531 case kInstantUIFullPageResults: | |
| 532 active_top_margin = bottom_edge.y(); | |
| 533 break; | |
| 545 } | 534 } |
| 546 } | 535 } |
| 547 | 536 |
| 548 // Now it's safe to actually resize all contents views in the hierarchy. | 537 // Now set the contents to display at their previous origin if we just hid the |
| 549 contents_split_->SetBoundsRect(contents_split_bounds); | 538 // bookmark and/or infobars for instant extended. We can't just compute the |
| 539 // proper position at this point because we don't know the height of all the | |
| 540 // infobars and their arrows. | |
| 541 if (active_top_margin == 0 && !contents_origin.IsOrigin()) { | |
| 542 views::WebView* contents_view = browser_view_->contents_container_; | |
| 543 gfx::Point new_contents_origin(contents_view->bounds().origin()); | |
| 544 views::View::ConvertPointToTarget(contents_view->parent(), | |
| 545 browser_view_, | |
| 546 &new_contents_origin); | |
| 547 int contents_offset = contents_origin.y() - new_contents_origin.y(); | |
| 548 // Special case: While normally the suggestions appear to "cover" any | |
| 549 // bookmark/infobars, if the suggestions are very short, they might not | |
| 550 // fully cover that gap, and leaving the contents at their original height | |
| 551 // would leave an odd-looking blank space. In this case, we allow the | |
| 552 // contents to go ahead and shift upward. | |
| 553 if (contents_offset > 0 && | |
| 554 contents_offset < contents_container_->overlay_height()) | |
| 555 active_top_margin = contents_offset; | |
| 556 } | |
| 557 | |
| 558 // Apply our adjustments to the active page and instant overlay position | |
| 559 // to account for detached bookmark bars, instant extended and immersive mode. | |
| 560 contents_container_->SetWebViewsTopMargins(active_top_margin, | |
| 561 overlay_top_margin); | |
| 550 } | 562 } |
| 551 | 563 |
| 552 int BrowserViewLayout::GetTopMarginForActiveContent() { | 564 int BrowserViewLayout::GetTopMarginForActiveContent() { |
| 553 BookmarkBarView* bookmark_bar = browser_view_->bookmark_bar_view_.get(); | 565 BookmarkBarView* bookmark_bar = browser_view_->bookmark_bar_view_.get(); |
| 554 if (!bookmark_bar || | 566 if (!bookmark_bar || |
| 555 !browser_view_->IsBookmarkBarVisible() || | 567 !browser_view_->IsBookmarkBarVisible() || |
| 556 !bookmark_bar->IsDetached()) { | 568 !bookmark_bar->IsDetached()) { |
| 557 return 0; | 569 return 0; |
| 558 } | 570 } |
| 559 | 571 |
| 572 // Handle dev tools. | |
| 560 if (contents_split_->child_at(1) && contents_split_->child_at(1)->visible()) | 573 if (contents_split_->child_at(1) && contents_split_->child_at(1)->visible()) |
| 561 return 0; | 574 return 0; |
| 562 | 575 |
| 563 // Adjust for separator. | 576 // Offset for the detached bookmark bar. |
| 564 return bookmark_bar->height() - | 577 return bookmark_bar->height() - |
| 565 views::NonClientFrameView::kClientEdgeThickness; | 578 views::NonClientFrameView::kClientEdgeThickness; |
| 566 } | 579 } |
| 567 | 580 |
| 581 BrowserViewLayout::InstantUIState BrowserViewLayout::GetInstantUIState() { | |
|
James Cook
2013/04/05 02:05:05
This is a near-copy of the Mac function currentIns
| |
| 582 if (!browser()->search_model()->mode().is_search_suggestions()) | |
| 583 return kInstantUINone; | |
| 584 | |
| 585 // If the search suggestions are already being displayed in the overlay | |
| 586 // contents then return kInstantUIOverlay. | |
| 587 if (contents_container_->overlay_height() > 0) | |
| 588 return kInstantUIOverlay; | |
| 589 | |
| 590 // Top bars stay visible until the results page notifies Chrome it is ready. | |
| 591 if (browser()->search_model()->top_bars_visible()) | |
| 592 return kInstantUINone; | |
| 593 | |
| 594 return kInstantUIFullPageResults; | |
| 595 } | |
| 596 | |
| 568 int BrowserViewLayout::LayoutDownloadShelf(int bottom) { | 597 int BrowserViewLayout::LayoutDownloadShelf(int bottom) { |
| 569 // Re-layout the shelf either if it is visible or if its close animation | 598 // Re-layout the shelf either if it is visible or if its close animation |
| 570 // is currently running. | 599 // is currently running. |
| 571 if (browser_view_->IsDownloadShelfVisible() || | 600 if (browser_view_->IsDownloadShelfVisible() || |
| 572 (download_shelf_ && download_shelf_->IsClosing())) { | 601 (download_shelf_ && download_shelf_->IsClosing())) { |
| 573 bool visible = browser()->SupportsWindowFeature( | 602 bool visible = browser()->SupportsWindowFeature( |
| 574 Browser::FEATURE_DOWNLOADSHELF); | 603 Browser::FEATURE_DOWNLOADSHELF); |
| 575 DCHECK(download_shelf_); | 604 DCHECK(download_shelf_); |
| 576 int height = visible ? download_shelf_->GetPreferredSize().height() : 0; | 605 int height = visible ? download_shelf_->GetPreferredSize().height() : 0; |
| 577 download_shelf_->SetVisible(visible); | 606 download_shelf_->SetVisible(visible); |
| 578 download_shelf_->SetBounds(vertical_layout_rect_.x(), bottom - height, | 607 download_shelf_->SetBounds(vertical_layout_rect_.x(), bottom - height, |
| 579 vertical_layout_rect_.width(), height); | 608 vertical_layout_rect_.width(), height); |
| 580 download_shelf_->Layout(); | 609 download_shelf_->Layout(); |
| 581 bottom -= height; | 610 bottom -= height; |
| 582 } | 611 } |
| 583 return bottom; | 612 return bottom; |
| 584 } | 613 } |
| 585 | 614 |
| 586 bool BrowserViewLayout::InfobarVisible() const { | 615 bool BrowserViewLayout::InfobarVisible() const { |
| 587 views::View* infobar_container = browser_view_->infobar_container_; | 616 views::View* infobar_container = browser_view_->infobar_container_; |
| 588 // NOTE: Can't check if the size IsEmpty() since it's always 0-width. | 617 // NOTE: Can't check if the size IsEmpty() since it's always 0-width. |
| 589 return browser()->SupportsWindowFeature(Browser::FEATURE_INFOBAR) && | 618 return browser()->SupportsWindowFeature(Browser::FEATURE_INFOBAR) && |
| 590 (infobar_container->GetPreferredSize().height() != 0); | 619 (infobar_container->GetPreferredSize().height() != 0); |
| 591 } | 620 } |
| OLD | NEW |