Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "ui/views/controls/scroll_view.h" | 5 #include "ui/views/controls/scroll_view.h" |
| 6 | 6 |
| 7 #include "base/feature_list.h" | 7 #include "base/feature_list.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "ui/events/event.h" | 10 #include "ui/events/event.h" |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 gfx::ScrollOffset offset = CurrentOffset(); | 236 gfx::ScrollOffset offset = CurrentOffset(); |
| 237 return gfx::Rect(offset.x(), offset.y(), contents_viewport_->width(), | 237 return gfx::Rect(offset.x(), offset.y(), contents_viewport_->width(), |
| 238 contents_viewport_->height()); | 238 contents_viewport_->height()); |
| 239 } | 239 } |
| 240 | 240 |
| 241 void ScrollView::ClipHeightTo(int min_height, int max_height) { | 241 void ScrollView::ClipHeightTo(int min_height, int max_height) { |
| 242 min_height_ = min_height; | 242 min_height_ = min_height; |
| 243 max_height_ = max_height; | 243 max_height_ = max_height; |
| 244 } | 244 } |
| 245 | 245 |
| 246 int ScrollView::GetScrollBarWidth() const { | 246 int ScrollView::GetScrollBarLayoutWidth() const { |
| 247 return vert_sb_ ? vert_sb_->GetLayoutSize() : 0; | 247 return vert_sb_ && !vert_sb_->OverlapsContent() ? vert_sb_->GetThickness() |
| 248 : 0; | |
| 248 } | 249 } |
| 249 | 250 |
| 250 int ScrollView::GetScrollBarHeight() const { | 251 int ScrollView::GetScrollBarLayoutHeight() const { |
| 251 return horiz_sb_ ? horiz_sb_->GetLayoutSize() : 0; | 252 return horiz_sb_ && !horiz_sb_->OverlapsContent() ? horiz_sb_->GetThickness() |
| 253 : 0; | |
| 252 } | 254 } |
| 253 | 255 |
| 254 void ScrollView::SetHorizontalScrollBar(ScrollBar* horiz_sb) { | 256 void ScrollView::SetHorizontalScrollBar(ScrollBar* horiz_sb) { |
| 255 DCHECK(horiz_sb); | 257 DCHECK(horiz_sb); |
| 256 horiz_sb->SetVisible(horiz_sb_->visible()); | 258 horiz_sb->SetVisible(horiz_sb_->visible()); |
| 257 delete horiz_sb_; | 259 delete horiz_sb_; |
| 258 horiz_sb->set_controller(this); | 260 horiz_sb->set_controller(this); |
| 259 horiz_sb_ = horiz_sb; | 261 horiz_sb_ = horiz_sb; |
| 260 } | 262 } |
| 261 | 263 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 295 if (!is_bounded()) | 297 if (!is_bounded()) |
| 296 return View::GetHeightForWidth(width); | 298 return View::GetHeightForWidth(width); |
| 297 | 299 |
| 298 gfx::Insets insets = GetInsets(); | 300 gfx::Insets insets = GetInsets(); |
| 299 width = std::max(0, width - insets.width()); | 301 width = std::max(0, width - insets.width()); |
| 300 int height = contents_->GetHeightForWidth(width) + insets.height(); | 302 int height = contents_->GetHeightForWidth(width) + insets.height(); |
| 301 return std::min(std::max(height, min_height_), max_height_); | 303 return std::min(std::max(height, min_height_), max_height_); |
| 302 } | 304 } |
| 303 | 305 |
| 304 void ScrollView::Layout() { | 306 void ScrollView::Layout() { |
| 307 #if defined(OS_MACOSX) | |
| 308 // On Mac, scrollbars may update their style one at a time, so they may | |
| 309 // temporarily be of different types. Refuse to lay out at this point. | |
| 310 if (horiz_sb_->OverlapsContent() != vert_sb_->OverlapsContent()) | |
|
Evan Stade
2016/12/13 00:51:52
Sadrul, do you mind this change that I had to make
| |
| 311 return; | |
| 312 #endif | |
| 313 DCHECK_EQ(horiz_sb_->OverlapsContent(), vert_sb_->OverlapsContent()); | |
| 314 | |
| 305 if (focus_ring_) | 315 if (focus_ring_) |
| 306 focus_ring_->Layout(); | 316 focus_ring_->Layout(); |
| 307 | 317 |
| 308 gfx::Rect available_rect = GetContentsBounds(); | 318 gfx::Rect available_rect = GetContentsBounds(); |
| 309 if (is_bounded()) { | 319 if (is_bounded()) { |
| 310 int content_width = available_rect.width(); | 320 int content_width = available_rect.width(); |
| 311 int content_height = contents_->GetHeightForWidth(content_width); | 321 int content_height = contents_->GetHeightForWidth(content_width); |
| 312 if (content_height > height()) { | 322 if (content_height > height()) { |
| 313 content_width = std::max(content_width - GetScrollBarWidth(), 0); | 323 content_width = std::max(content_width - GetScrollBarLayoutWidth(), 0); |
| 314 content_height = contents_->GetHeightForWidth(content_width); | 324 content_height = contents_->GetHeightForWidth(content_width); |
| 315 } | 325 } |
| 316 contents_->SetSize(gfx::Size(content_width, content_height)); | 326 contents_->SetSize(gfx::Size(content_width, content_height)); |
| 317 } | 327 } |
| 318 | 328 |
| 319 // Most views will want to auto-fit the available space. Most of them want to | 329 // Most views will want to auto-fit the available space. Most of them want to |
| 320 // use all available width (without overflowing) and only overflow in | 330 // use all available width (without overflowing) and only overflow in |
| 321 // height. Examples are HistoryView, MostVisitedView, DownloadTabView, etc. | 331 // height. Examples are HistoryView, MostVisitedView, DownloadTabView, etc. |
| 322 // Other views want to fit in both ways. An example is PrintView. To make both | 332 // Other views want to fit in both ways. An example is PrintView. To make both |
| 323 // happy, assume a vertical scrollbar but no horizontal scrollbar. To override | 333 // happy, assume a vertical scrollbar but no horizontal scrollbar. To override |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 335 const int header_height = | 345 const int header_height = |
| 336 std::min(viewport_bounds.height(), | 346 std::min(viewport_bounds.height(), |
| 337 header_ ? header_->GetPreferredSize().height() : 0); | 347 header_ ? header_->GetPreferredSize().height() : 0); |
| 338 viewport_bounds.set_height( | 348 viewport_bounds.set_height( |
| 339 std::max(0, viewport_bounds.height() - header_height)); | 349 std::max(0, viewport_bounds.height() - header_height)); |
| 340 viewport_bounds.set_y(viewport_bounds.y() + header_height); | 350 viewport_bounds.set_y(viewport_bounds.y() + header_height); |
| 341 // viewport_size is the total client space available. | 351 // viewport_size is the total client space available. |
| 342 gfx::Size viewport_size = viewport_bounds.size(); | 352 gfx::Size viewport_size = viewport_bounds.size(); |
| 343 // Assumes a vertical scrollbar since most of the current views are designed | 353 // Assumes a vertical scrollbar since most of the current views are designed |
| 344 // for this. | 354 // for this. |
| 345 int horiz_sb_height = GetScrollBarHeight(); | 355 const int horiz_sb_layout_height = GetScrollBarLayoutHeight(); |
| 346 int vert_sb_width = GetScrollBarWidth(); | 356 const int vert_sb_layout_width = GetScrollBarLayoutWidth(); |
| 347 viewport_bounds.set_width(viewport_bounds.width() - vert_sb_width); | 357 viewport_bounds.set_width(viewport_bounds.width() - vert_sb_layout_width); |
| 348 // Update the bounds right now so the inner views can fit in it. | 358 // Update the bounds right now so the inner views can fit in it. |
| 349 contents_viewport_->SetBoundsRect(viewport_bounds); | 359 contents_viewport_->SetBoundsRect(viewport_bounds); |
| 350 | 360 |
| 351 // Give |contents_| a chance to update its bounds if it depends on the | 361 // Give |contents_| a chance to update its bounds if it depends on the |
| 352 // viewport. | 362 // viewport. |
| 353 if (contents_) | 363 if (contents_) |
| 354 contents_->Layout(); | 364 contents_->Layout(); |
| 355 | 365 |
| 356 bool should_layout_contents = false; | 366 bool should_layout_contents = false; |
| 357 bool horiz_sb_required = false; | 367 bool horiz_sb_required = false; |
| 358 bool vert_sb_required = false; | 368 bool vert_sb_required = false; |
| 359 if (contents_) { | 369 if (contents_) { |
| 360 gfx::Size content_size = contents_->size(); | 370 gfx::Size content_size = contents_->size(); |
| 361 ComputeScrollBarsVisibility(viewport_size, | 371 ComputeScrollBarsVisibility(viewport_size, |
| 362 content_size, | 372 content_size, |
| 363 &horiz_sb_required, | 373 &horiz_sb_required, |
| 364 &vert_sb_required); | 374 &vert_sb_required); |
| 365 } | 375 } |
| 366 bool corner_view_required = horiz_sb_required && vert_sb_required; | 376 // Overlay scrollbars don't need a corner view. |
| 377 bool corner_view_required = | |
| 378 horiz_sb_required && vert_sb_required && !vert_sb_->OverlapsContent(); | |
| 367 // Take action. | 379 // Take action. |
| 368 SetControlVisibility(horiz_sb_, horiz_sb_required); | 380 SetControlVisibility(horiz_sb_, horiz_sb_required); |
| 369 SetControlVisibility(vert_sb_, vert_sb_required); | 381 SetControlVisibility(vert_sb_, vert_sb_required); |
| 370 SetControlVisibility(corner_view_, corner_view_required); | 382 SetControlVisibility(corner_view_, corner_view_required); |
| 371 | 383 |
| 372 // Non-default. | 384 // Non-default. |
| 373 if (horiz_sb_required) { | 385 if (horiz_sb_required) { |
| 374 viewport_bounds.set_height( | 386 viewport_bounds.set_height( |
| 375 std::max(0, viewport_bounds.height() - horiz_sb_height)); | 387 std::max(0, viewport_bounds.height() - horiz_sb_layout_height)); |
| 376 should_layout_contents = true; | 388 should_layout_contents = true; |
| 377 } | 389 } |
| 378 // Default. | 390 // Default. |
| 379 if (!vert_sb_required) { | 391 if (!vert_sb_required) { |
| 380 viewport_bounds.set_width(viewport_bounds.width() + vert_sb_width); | 392 viewport_bounds.set_width(viewport_bounds.width() + vert_sb_layout_width); |
| 381 should_layout_contents = true; | 393 should_layout_contents = true; |
| 382 } | 394 } |
| 383 | 395 |
| 384 int height_offset = horiz_sb_required ? | 396 if (horiz_sb_required) { |
| 385 horiz_sb_->GetContentOverlapSize() : 0; | 397 gfx::Rect horiz_sb_bounds(contents_x, viewport_bounds.bottom(), |
| 386 int width_offset = vert_sb_required ? | 398 viewport_bounds.right() - contents_x, |
| 387 vert_sb_->GetContentOverlapSize() : 0; | 399 horiz_sb_layout_height); |
| 400 if (horiz_sb_->OverlapsContent()) { | |
| 401 horiz_sb_bounds.Inset( | |
| 402 gfx::Insets(-horiz_sb_->GetThickness(), 0, 0, | |
| 403 vert_sb_required ? vert_sb_->GetThickness() : 0)); | |
| 404 } | |
| 388 | 405 |
| 389 if (horiz_sb_required) { | 406 horiz_sb_->SetBoundsRect(horiz_sb_bounds); |
| 390 horiz_sb_->SetBounds(contents_x, | |
| 391 viewport_bounds.bottom() - height_offset, | |
| 392 viewport_bounds.right() - contents_x - width_offset, | |
| 393 horiz_sb_height + height_offset); | |
| 394 } | 407 } |
| 395 if (vert_sb_required) { | 408 if (vert_sb_required) { |
| 396 int width_offset = vert_sb_->GetContentOverlapSize(); | 409 gfx::Rect vert_sb_bounds(viewport_bounds.right(), contents_y, |
| 397 vert_sb_->SetBounds(viewport_bounds.right() - width_offset, | 410 vert_sb_layout_width, |
| 398 contents_y, | 411 viewport_bounds.bottom() - contents_y); |
| 399 vert_sb_width + width_offset, | 412 if (vert_sb_->OverlapsContent()) { |
| 400 viewport_bounds.bottom() - contents_y - height_offset); | 413 // In the overlay scrollbar case, the scrollbar only covers the viewport |
| 414 // (and not the header). | |
| 415 vert_sb_bounds.Inset( | |
| 416 gfx::Insets(header_height, -vert_sb_->GetThickness(), | |
| 417 horiz_sb_required ? horiz_sb_->GetThickness() : 0, 0)); | |
| 418 } | |
| 419 | |
| 420 vert_sb_->SetBoundsRect(vert_sb_bounds); | |
| 401 } | 421 } |
| 402 if (corner_view_required) { | 422 if (corner_view_required) { |
| 403 // Show the resize corner. | 423 // Show the resize corner. |
| 404 corner_view_->SetBounds(vert_sb_->bounds().x(), horiz_sb_->bounds().y(), | 424 corner_view_->SetBounds(vert_sb_->bounds().x(), horiz_sb_->bounds().y(), |
| 405 vert_sb_width, horiz_sb_height); | 425 vert_sb_layout_width, horiz_sb_layout_height); |
| 406 } | 426 } |
| 407 | 427 |
| 408 // Update to the real client size with the visible scrollbars. | 428 // Update to the real client size with the visible scrollbars. |
| 409 contents_viewport_->SetBoundsRect(viewport_bounds); | 429 contents_viewport_->SetBoundsRect(viewport_bounds); |
| 410 if (should_layout_contents && contents_) | 430 if (should_layout_contents && contents_) |
| 411 contents_->Layout(); | 431 contents_->Layout(); |
| 412 | 432 |
| 413 // Even when |contents_| needs to scroll, it can still be narrower or wider | 433 // Even when |contents_| needs to scroll, it can still be narrower or wider |
| 414 // the viewport. So ensure the scrolling layer can fill the viewport, so that | 434 // the viewport. So ensure the scrolling layer can fill the viewport, so that |
| 415 // events will correctly hit it, and overscroll looks correct. | 435 // events will correctly hit it, and overscroll looks correct. |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 612 *vert_is_shown = content_size.height() > vp_size.height(); | 632 *vert_is_shown = content_size.height() > vp_size.height(); |
| 613 return; | 633 return; |
| 614 } | 634 } |
| 615 | 635 |
| 616 // Try to fit both ways first, then try vertical bar only, then horizontal | 636 // Try to fit both ways first, then try vertical bar only, then horizontal |
| 617 // bar only, then defaults to both shown. | 637 // bar only, then defaults to both shown. |
| 618 if (content_size.width() <= vp_size.width() && | 638 if (content_size.width() <= vp_size.width() && |
| 619 content_size.height() <= vp_size.height()) { | 639 content_size.height() <= vp_size.height()) { |
| 620 *horiz_is_shown = false; | 640 *horiz_is_shown = false; |
| 621 *vert_is_shown = false; | 641 *vert_is_shown = false; |
| 622 } else if (content_size.width() <= vp_size.width() - GetScrollBarWidth()) { | 642 } else if (content_size.width() <= |
| 643 vp_size.width() - GetScrollBarLayoutWidth()) { | |
| 623 *horiz_is_shown = false; | 644 *horiz_is_shown = false; |
| 624 *vert_is_shown = true; | 645 *vert_is_shown = true; |
| 625 } else if (content_size.height() <= vp_size.height() - GetScrollBarHeight()) { | 646 } else if (content_size.height() <= |
| 647 vp_size.height() - GetScrollBarLayoutHeight()) { | |
| 626 *horiz_is_shown = true; | 648 *horiz_is_shown = true; |
| 627 *vert_is_shown = false; | 649 *vert_is_shown = false; |
| 628 } else { | 650 } else { |
| 629 *horiz_is_shown = true; | 651 *horiz_is_shown = true; |
| 630 *vert_is_shown = true; | 652 *vert_is_shown = true; |
| 631 } | 653 } |
| 632 } | 654 } |
| 633 | 655 |
| 634 // Make sure that a single scrollbar is created and visible as needed | 656 // Make sure that a single scrollbar is created and visible as needed |
| 635 void ScrollView::SetControlVisibility(View* control, bool should_show) { | 657 void ScrollView::SetControlVisibility(View* control, bool should_show) { |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 | 803 |
| 782 VariableRowHeightScrollHelper::RowInfo | 804 VariableRowHeightScrollHelper::RowInfo |
| 783 FixedRowHeightScrollHelper::GetRowInfo(int y) { | 805 FixedRowHeightScrollHelper::GetRowInfo(int y) { |
| 784 if (y < top_margin_) | 806 if (y < top_margin_) |
| 785 return RowInfo(0, top_margin_); | 807 return RowInfo(0, top_margin_); |
| 786 return RowInfo((y - top_margin_) / row_height_ * row_height_ + top_margin_, | 808 return RowInfo((y - top_margin_) / row_height_ * row_height_ + top_margin_, |
| 787 row_height_); | 809 row_height_); |
| 788 } | 810 } |
| 789 | 811 |
| 790 } // namespace views | 812 } // namespace views |
| OLD | NEW |