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 |