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/logging.h" | 8 #include "base/logging.h" |
| 8 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "ui/compositor/overscroll/ui_scroll_input_manager.h" | |
| 9 #include "ui/events/event.h" | 11 #include "ui/events/event.h" |
| 10 #include "ui/gfx/canvas.h" | 12 #include "ui/gfx/canvas.h" |
| 11 #include "ui/native_theme/native_theme.h" | 13 #include "ui/native_theme/native_theme.h" |
| 14 #include "ui/views/background.h" | |
| 12 #include "ui/views/border.h" | 15 #include "ui/views/border.h" |
| 13 #include "ui/views/style/platform_style.h" | 16 #include "ui/views/style/platform_style.h" |
| 14 #include "ui/views/widget/root_view.h" | 17 #include "ui/views/widget/widget.h" |
| 15 | 18 |
| 16 namespace views { | 19 namespace views { |
| 17 | 20 |
| 18 const char ScrollView::kViewClassName[] = "ScrollView"; | 21 const char ScrollView::kViewClassName[] = "ScrollView"; |
| 19 | 22 |
| 20 namespace { | 23 namespace { |
| 21 | 24 |
| 25 const base::Feature kToolkitViewsScrollWithLayers { | |
| 26 "ToolkitViewsScrollWithLayers", | |
| 27 #if defined(OS_MACOSX) | |
| 28 base::FEATURE_ENABLED_BY_DEFAULT | |
| 29 #else | |
| 30 base::FEATURE_DISABLED_BY_DEFAULT | |
| 31 #endif | |
| 32 }; | |
| 33 | |
| 22 // Subclass of ScrollView that resets the border when the theme changes. | 34 // Subclass of ScrollView that resets the border when the theme changes. |
| 23 class ScrollViewWithBorder : public views::ScrollView { | 35 class ScrollViewWithBorder : public views::ScrollView { |
| 24 public: | 36 public: |
| 25 ScrollViewWithBorder() {} | 37 ScrollViewWithBorder() {} |
| 26 | 38 |
| 27 // View overrides; | 39 // View overrides; |
| 28 void OnNativeThemeChanged(const ui::NativeTheme* theme) override { | 40 void OnNativeThemeChanged(const ui::NativeTheme* theme) override { |
| 29 SetBorder(Border::CreateSolidBorder( | 41 SetBorder(Border::CreateSolidBorder( |
| 30 1, | 42 1, |
| 31 theme->GetSystemColor(ui::NativeTheme::kColorId_UnfocusedBorderColor))); | 43 theme->GetSystemColor(ui::NativeTheme::kColorId_UnfocusedBorderColor))); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 57 int CheckScrollBounds(int viewport_size, int content_size, int current_pos) { | 69 int CheckScrollBounds(int viewport_size, int content_size, int current_pos) { |
| 58 int max = std::max(content_size - viewport_size, 0); | 70 int max = std::max(content_size - viewport_size, 0); |
| 59 if (current_pos < 0) | 71 if (current_pos < 0) |
| 60 return 0; | 72 return 0; |
| 61 if (current_pos > max) | 73 if (current_pos > max) |
| 62 return max; | 74 return max; |
| 63 return current_pos; | 75 return current_pos; |
| 64 } | 76 } |
| 65 | 77 |
| 66 // Make sure the content is not scrolled out of bounds | 78 // Make sure the content is not scrolled out of bounds |
| 67 void CheckScrollBounds(View* viewport, View* view) { | 79 void CheckScrollBounds(View* viewport, View* container, View* view) { |
| 68 if (!view) | 80 if (!view) |
| 69 return; | 81 return; |
| 70 | 82 |
| 71 int x = CheckScrollBounds(viewport->width(), view->width(), -view->x()); | 83 gfx::ScrollOffset offset = container |
| 72 int y = CheckScrollBounds(viewport->height(), view->height(), -view->y()); | 84 ? container->layer()->CurrentScrollOffset() |
| 85 : gfx::ScrollOffset(-view->x(), -view->y()); | |
| 73 | 86 |
| 74 // This is no op if bounds are the same | 87 int x = CheckScrollBounds(viewport->width(), view->width(), offset.x()); |
| 75 view->SetBounds(-x, -y, view->width(), view->height()); | 88 int y = CheckScrollBounds(viewport->height(), view->height(), offset.y()); |
| 89 | |
| 90 if (container) { | |
| 91 container->layer()->SetScrollOffset(gfx::ScrollOffset(x, y)); | |
| 92 } else { | |
| 93 // This is no op if bounds are the same | |
| 94 view->SetBounds(-x, -y, view->width(), view->height()); | |
| 95 } | |
| 76 } | 96 } |
| 77 | 97 |
| 78 // Used by ScrollToPosition() to make sure the new position fits within the | 98 // Used by ScrollToPosition() to make sure the new position fits within the |
| 79 // allowed scroll range. | 99 // allowed scroll range. |
| 80 int AdjustPosition(int current_position, | 100 int AdjustPosition(int current_position, |
| 81 int new_position, | 101 int new_position, |
| 82 int content_size, | 102 int content_size, |
| 83 int viewport_size) { | 103 int viewport_size) { |
| 84 if (-current_position == new_position) | 104 if (-current_position == new_position) |
| 85 return new_position; | 105 return new_position; |
| 86 if (new_position < 0) | 106 if (new_position < 0) |
| 87 return 0; | 107 return 0; |
| 88 const int max_position = std::max(0, content_size - viewport_size); | 108 const int max_position = std::max(0, content_size - viewport_size); |
| 89 return (new_position > max_position) ? max_position : new_position; | 109 return (new_position > max_position) ? max_position : new_position; |
| 90 } | 110 } |
| 91 | 111 |
| 112 class ScrollViewContainer : public View { | |
| 113 public: | |
| 114 ScrollViewContainer() {} | |
| 115 | |
| 116 // View: | |
| 117 void ChildPreferredSizeChanged(View* child) override { | |
| 118 PreferredSizeChanged(); | |
| 119 } | |
| 120 | |
| 121 private: | |
| 122 DISALLOW_COPY_AND_ASSIGN(ScrollViewContainer); | |
| 123 }; | |
| 124 | |
| 92 } // namespace | 125 } // namespace |
| 93 | 126 |
| 94 // Viewport contains the contents View of the ScrollView. | 127 // Viewport contains the contents View of the ScrollView. |
| 95 class ScrollView::Viewport : public View { | 128 class ScrollView::Viewport : public View { |
| 96 public: | 129 public: |
| 97 Viewport() {} | 130 Viewport() {} |
| 98 ~Viewport() override {} | 131 ~Viewport() override {} |
| 99 | 132 |
| 100 const char* GetClassName() const override { return "ScrollView::Viewport"; } | 133 const char* GetClassName() const override { return "ScrollView::Viewport"; } |
| 101 | 134 |
| 102 void ScrollRectToVisible(const gfx::Rect& rect) override { | 135 void ScrollRectToVisible(const gfx::Rect& rect) override { |
| 103 if (!has_children() || !parent()) | 136 if (!has_children() || !parent()) |
| 104 return; | 137 return; |
| 105 | 138 |
| 106 View* contents = child_at(0); | 139 View* contents = child_at(0); |
| 107 gfx::Rect scroll_rect(rect); | 140 gfx::Rect scroll_rect(rect); |
| 141 | |
| 142 ScrollView* scroll_view = static_cast<ScrollView*>(parent()); | |
| 143 if (contents == scroll_view->contents_container_) { | |
| 144 // With layer scrolling, there's no need to "undo" the offset done in the | |
| 145 // child's View::ScrollRectToVisible() before it calls this. | |
| 146 DCHECK_EQ(0, contents->x()); | |
| 147 DCHECK_EQ(0, contents->y()); | |
| 148 } | |
| 149 | |
| 108 scroll_rect.Offset(-contents->x(), -contents->y()); | 150 scroll_rect.Offset(-contents->x(), -contents->y()); |
| 109 static_cast<ScrollView*>(parent())->ScrollContentsRegionToBeVisible( | 151 scroll_view->ScrollContentsRegionToBeVisible(scroll_rect); |
| 110 scroll_rect); | |
| 111 } | 152 } |
| 112 | 153 |
| 113 void ChildPreferredSizeChanged(View* child) override { | 154 void ChildPreferredSizeChanged(View* child) override { |
| 114 if (parent()) | 155 if (parent()) |
| 115 parent()->Layout(); | 156 parent()->Layout(); |
| 116 } | 157 } |
| 117 | 158 |
| 118 private: | 159 private: |
| 119 DISALLOW_COPY_AND_ASSIGN(Viewport); | 160 DISALLOW_COPY_AND_ASSIGN(Viewport); |
| 120 }; | 161 }; |
| 121 | 162 |
| 122 ScrollView::ScrollView() | 163 ScrollView::ScrollView() |
| 123 : contents_(NULL), | 164 : contents_(NULL), |
| 165 contents_container_(nullptr), | |
| 124 contents_viewport_(new Viewport()), | 166 contents_viewport_(new Viewport()), |
| 125 header_(NULL), | 167 header_(NULL), |
| 126 header_viewport_(new Viewport()), | 168 header_viewport_(new Viewport()), |
| 127 horiz_sb_(PlatformStyle::CreateScrollBar(true).release()), | 169 horiz_sb_(PlatformStyle::CreateScrollBar(true).release()), |
| 128 vert_sb_(PlatformStyle::CreateScrollBar(false).release()), | 170 vert_sb_(PlatformStyle::CreateScrollBar(false).release()), |
| 129 corner_view_(new ScrollCornerView()), | 171 corner_view_(new ScrollCornerView()), |
| 130 min_height_(-1), | 172 min_height_(-1), |
| 131 max_height_(-1), | 173 max_height_(-1), |
| 132 hide_horizontal_scrollbar_(false) { | 174 hide_horizontal_scrollbar_(false) { |
| 133 set_notify_enter_exit_on_child(true); | 175 set_notify_enter_exit_on_child(true); |
| 134 | 176 |
| 135 AddChildView(contents_viewport_); | 177 AddChildView(contents_viewport_); |
| 136 AddChildView(header_viewport_); | 178 AddChildView(header_viewport_); |
| 137 | 179 |
| 138 // Don't add the scrollbars as children until we discover we need them | 180 // Don't add the scrollbars as children until we discover we need them |
| 139 // (ShowOrHideScrollBar). | 181 // (ShowOrHideScrollBar). |
| 140 horiz_sb_->SetVisible(false); | 182 horiz_sb_->SetVisible(false); |
| 141 horiz_sb_->set_controller(this); | 183 horiz_sb_->set_controller(this); |
| 142 vert_sb_->SetVisible(false); | 184 vert_sb_->SetVisible(false); |
| 143 vert_sb_->set_controller(this); | 185 vert_sb_->set_controller(this); |
| 144 corner_view_->SetVisible(false); | 186 corner_view_->SetVisible(false); |
| 187 | |
| 188 if (!base::FeatureList::IsEnabled(kToolkitViewsScrollWithLayers)) | |
| 189 return; | |
| 190 | |
| 191 contents_container_ = new ScrollViewContainer(); | |
| 192 contents_viewport_->AddChildView(contents_container_); | |
| 193 contents_viewport_->SetPaintToLayer(true); | |
| 194 contents_viewport_->set_background( | |
| 195 Background::CreateSolidBackground(SK_ColorWHITE)); | |
| 196 contents_viewport_->layer()->SetMasksToBounds(true); | |
| 197 | |
| 198 contents_container_->SetPaintToLayer(true); | |
|
sky
2016/08/02 17:29:45
Would it be possible to to turn on paint to layer
tapted
2016/08/03 00:18:58
One issue was that there's no guarantee that |cont
| |
| 199 contents_container_->set_background( | |
| 200 Background::CreateSolidBackground(SK_ColorWHITE)); | |
| 201 contents_container_->layer()->SetScrollable( | |
| 202 contents_viewport_->layer(), true /* can_overscroll */, | |
| 203 base::Bind(&ScrollView::OnLayerScrolled, base::Unretained(this))); | |
| 145 } | 204 } |
| 146 | 205 |
| 147 ScrollView::~ScrollView() { | 206 ScrollView::~ScrollView() { |
| 148 // The scrollbars may not have been added, delete them to ensure they get | 207 // The scrollbars may not have been added, delete them to ensure they get |
| 149 // deleted. | 208 // deleted. |
| 150 delete horiz_sb_; | 209 delete horiz_sb_; |
| 151 delete vert_sb_; | 210 delete vert_sb_; |
| 152 delete corner_view_; | 211 delete corner_view_; |
| 153 } | 212 } |
| 154 | 213 |
| 155 // static | 214 // static |
| 156 ScrollView* ScrollView::CreateScrollViewWithBorder() { | 215 ScrollView* ScrollView::CreateScrollViewWithBorder() { |
| 157 return new ScrollViewWithBorder(); | 216 return new ScrollViewWithBorder(); |
| 158 } | 217 } |
| 159 | 218 |
| 160 void ScrollView::SetContents(View* a_view) { | 219 void ScrollView::SetContents(View* a_view) { |
| 161 SetHeaderOrContents(contents_viewport_, a_view, &contents_); | 220 View* parent = contents_container_ ? contents_container_ : contents_viewport_; |
| 221 SetHeaderOrContents(parent, a_view, &contents_); | |
| 162 } | 222 } |
| 163 | 223 |
| 164 void ScrollView::SetHeader(View* header) { | 224 void ScrollView::SetHeader(View* header) { |
| 165 SetHeaderOrContents(header_viewport_, header, &header_); | 225 SetHeaderOrContents(header_viewport_, header, &header_); |
| 166 } | 226 } |
| 167 | 227 |
| 168 gfx::Rect ScrollView::GetVisibleRect() const { | 228 gfx::Rect ScrollView::GetVisibleRect() const { |
| 169 if (!contents_) | 229 if (!contents_) |
| 170 return gfx::Rect(); | 230 return gfx::Rect(); |
| 171 return gfx::Rect(-contents_->x(), -contents_->y(), | 231 gfx::ScrollOffset offset = CurrentOffset(); |
| 172 contents_viewport_->width(), contents_viewport_->height()); | 232 return gfx::Rect(offset.x(), offset.y(), contents_viewport_->width(), |
| 233 contents_viewport_->height()); | |
| 173 } | 234 } |
| 174 | 235 |
| 175 void ScrollView::ClipHeightTo(int min_height, int max_height) { | 236 void ScrollView::ClipHeightTo(int min_height, int max_height) { |
| 176 min_height_ = min_height; | 237 min_height_ = min_height; |
| 177 max_height_ = max_height; | 238 max_height_ = max_height; |
| 178 } | 239 } |
| 179 | 240 |
| 180 int ScrollView::GetScrollBarWidth() const { | 241 int ScrollView::GetScrollBarWidth() const { |
| 181 return vert_sb_ ? vert_sb_->GetLayoutSize() : 0; | 242 return vert_sb_ ? vert_sb_->GetLayoutSize() : 0; |
| 182 } | 243 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 // viewport_size is the total client space available. | 321 // viewport_size is the total client space available. |
| 261 gfx::Size viewport_size = viewport_bounds.size(); | 322 gfx::Size viewport_size = viewport_bounds.size(); |
| 262 // Assumes a vertical scrollbar since most of the current views are designed | 323 // Assumes a vertical scrollbar since most of the current views are designed |
| 263 // for this. | 324 // for this. |
| 264 int horiz_sb_height = GetScrollBarHeight(); | 325 int horiz_sb_height = GetScrollBarHeight(); |
| 265 int vert_sb_width = GetScrollBarWidth(); | 326 int vert_sb_width = GetScrollBarWidth(); |
| 266 viewport_bounds.set_width(viewport_bounds.width() - vert_sb_width); | 327 viewport_bounds.set_width(viewport_bounds.width() - vert_sb_width); |
| 267 // Update the bounds right now so the inner views can fit in it. | 328 // Update the bounds right now so the inner views can fit in it. |
| 268 contents_viewport_->SetBoundsRect(viewport_bounds); | 329 contents_viewport_->SetBoundsRect(viewport_bounds); |
| 269 | 330 |
| 270 // Give |contents_| a chance to update its bounds if it depends on the | 331 // Give |contents_| a chance to update its bounds if it depends on its parent |
| 271 // viewport. | 332 // bounds. |
| 272 if (contents_) | 333 if (contents_) { |
| 334 // The container bounds may need to be made larger later, but use the | |
| 335 // viewport bounds to layout the contents. | |
| 336 if (contents_container_) | |
| 337 contents_container_->SetBoundsRect(viewport_bounds); | |
| 273 contents_->Layout(); | 338 contents_->Layout(); |
| 339 } | |
| 274 | 340 |
| 275 bool should_layout_contents = false; | 341 bool should_layout_contents = false; |
| 276 bool horiz_sb_required = false; | 342 bool horiz_sb_required = false; |
| 277 bool vert_sb_required = false; | 343 bool vert_sb_required = false; |
| 278 if (contents_) { | 344 if (contents_) { |
| 279 gfx::Size content_size = contents_->size(); | 345 gfx::Size content_size = contents_->size(); |
| 280 ComputeScrollBarsVisibility(viewport_size, | 346 ComputeScrollBarsVisibility(viewport_size, |
| 281 content_size, | 347 content_size, |
| 282 &horiz_sb_required, | 348 &horiz_sb_required, |
| 283 &vert_sb_required); | 349 &vert_sb_required); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 viewport_bounds.bottom() - contents_y - height_offset); | 385 viewport_bounds.bottom() - contents_y - height_offset); |
| 320 } | 386 } |
| 321 if (corner_view_required) { | 387 if (corner_view_required) { |
| 322 // Show the resize corner. | 388 // Show the resize corner. |
| 323 corner_view_->SetBounds(vert_sb_->bounds().x(), horiz_sb_->bounds().y(), | 389 corner_view_->SetBounds(vert_sb_->bounds().x(), horiz_sb_->bounds().y(), |
| 324 vert_sb_width, horiz_sb_height); | 390 vert_sb_width, horiz_sb_height); |
| 325 } | 391 } |
| 326 | 392 |
| 327 // Update to the real client size with the visible scrollbars. | 393 // Update to the real client size with the visible scrollbars. |
| 328 contents_viewport_->SetBoundsRect(viewport_bounds); | 394 contents_viewport_->SetBoundsRect(viewport_bounds); |
| 329 if (should_layout_contents && contents_) | 395 if (should_layout_contents && contents_) { |
| 396 if (contents_container_) | |
| 397 contents_container_->SetBoundsRect(viewport_bounds); | |
| 330 contents_->Layout(); | 398 contents_->Layout(); |
| 399 } | |
| 400 | |
| 401 // Even when |contents_| needs to scroll, it can still be narrower or wider | |
| 402 // the viewport. So ensure the scrolling layer can fill the viewport, so that | |
| 403 // events will correctly hit it, and overscroll looks correct. | |
| 404 if (contents_container_) { | |
| 405 gfx::Size container_size = contents_ ? contents_->size() : gfx::Size(); | |
| 406 container_size.SetToMax(viewport_bounds.size()); | |
| 407 contents_container_->SetBoundsRect(gfx::Rect(container_size)); | |
| 408 } | |
| 331 | 409 |
| 332 header_viewport_->SetBounds(contents_x, contents_y, | 410 header_viewport_->SetBounds(contents_x, contents_y, |
| 333 viewport_bounds.width(), header_height); | 411 viewport_bounds.width(), header_height); |
| 334 if (header_) | 412 if (header_) |
| 335 header_->Layout(); | 413 header_->Layout(); |
| 336 | 414 |
| 337 CheckScrollBounds(header_viewport_, header_); | 415 CheckScrollBounds(header_viewport_, nullptr, header_); |
| 338 CheckScrollBounds(contents_viewport_, contents_); | 416 CheckScrollBounds(contents_viewport_, contents_container_, contents_); |
| 417 | |
| 339 SchedulePaint(); | 418 SchedulePaint(); |
| 340 UpdateScrollBarPositions(); | 419 UpdateScrollBarPositions(); |
| 341 } | 420 } |
| 342 | 421 |
| 343 bool ScrollView::OnKeyPressed(const ui::KeyEvent& event) { | 422 bool ScrollView::OnKeyPressed(const ui::KeyEvent& event) { |
| 344 bool processed = false; | 423 bool processed = false; |
| 345 | 424 |
| 346 // Give vertical scrollbar priority | 425 // Give vertical scrollbar priority |
| 347 if (vert_sb_->visible()) | 426 if (vert_sb_->visible()) |
| 348 processed = vert_sb_->OnKeyPressed(event); | 427 processed = vert_sb_->OnKeyPressed(event); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 372 vert_sb_->OnMouseEnteredScrollView(event); | 451 vert_sb_->OnMouseEnteredScrollView(event); |
| 373 } | 452 } |
| 374 | 453 |
| 375 void ScrollView::OnMouseExited(const ui::MouseEvent& event) { | 454 void ScrollView::OnMouseExited(const ui::MouseEvent& event) { |
| 376 if (horiz_sb_) | 455 if (horiz_sb_) |
| 377 horiz_sb_->OnMouseExitedScrollView(event); | 456 horiz_sb_->OnMouseExitedScrollView(event); |
| 378 if (vert_sb_) | 457 if (vert_sb_) |
| 379 vert_sb_->OnMouseExitedScrollView(event); | 458 vert_sb_->OnMouseExitedScrollView(event); |
| 380 } | 459 } |
| 381 | 460 |
| 461 void ScrollView::OnScrollEvent(ui::ScrollEvent* event) { | |
| 462 #if defined(OS_MACOSX) | |
| 463 ui::UIScrollInputManager* compositor_scroller = | |
| 464 GetWidget()->GetCompositor()->scroll_input_manager(); | |
| 465 if (compositor_scroller) | |
| 466 compositor_scroller->OnScrollEvent(*event); | |
| 467 #endif | |
| 468 } | |
| 469 | |
| 382 void ScrollView::OnGestureEvent(ui::GestureEvent* event) { | 470 void ScrollView::OnGestureEvent(ui::GestureEvent* event) { |
| 383 // If the event happened on one of the scrollbars, then those events are | 471 // If the event happened on one of the scrollbars, then those events are |
| 384 // sent directly to the scrollbars. Otherwise, only scroll events are sent to | 472 // sent directly to the scrollbars. Otherwise, only scroll events are sent to |
| 385 // the scrollbars. | 473 // the scrollbars. |
| 386 bool scroll_event = event->type() == ui::ET_GESTURE_SCROLL_UPDATE || | 474 bool scroll_event = event->type() == ui::ET_GESTURE_SCROLL_UPDATE || |
| 387 event->type() == ui::ET_GESTURE_SCROLL_BEGIN || | 475 event->type() == ui::ET_GESTURE_SCROLL_BEGIN || |
| 388 event->type() == ui::ET_GESTURE_SCROLL_END || | 476 event->type() == ui::ET_GESTURE_SCROLL_END || |
| 389 event->type() == ui::ET_SCROLL_FLING_START; | 477 event->type() == ui::ET_SCROLL_FLING_START; |
| 390 | 478 |
| 391 if (vert_sb_->visible()) { | 479 if (vert_sb_->visible()) { |
| 392 if (vert_sb_->bounds().Contains(event->location()) || scroll_event) | 480 if (vert_sb_->bounds().Contains(event->location()) || scroll_event) |
| 393 vert_sb_->OnGestureEvent(event); | 481 vert_sb_->OnGestureEvent(event); |
| 394 } | 482 } |
| 395 if (!event->handled() && horiz_sb_->visible()) { | 483 if (!event->handled() && horiz_sb_->visible()) { |
| 396 if (horiz_sb_->bounds().Contains(event->location()) || scroll_event) | 484 if (horiz_sb_->bounds().Contains(event->location()) || scroll_event) |
| 397 horiz_sb_->OnGestureEvent(event); | 485 horiz_sb_->OnGestureEvent(event); |
| 398 } | 486 } |
| 399 } | 487 } |
| 400 | 488 |
| 401 const char* ScrollView::GetClassName() const { | 489 const char* ScrollView::GetClassName() const { |
| 402 return kViewClassName; | 490 return kViewClassName; |
| 403 } | 491 } |
| 404 | 492 |
| 493 ScrollView* ScrollView::EnclosingScrollView() { | |
| 494 return this; | |
| 495 } | |
| 496 | |
| 405 void ScrollView::ScrollToPosition(ScrollBar* source, int position) { | 497 void ScrollView::ScrollToPosition(ScrollBar* source, int position) { |
| 406 if (!contents_) | 498 if (!contents_) |
| 407 return; | 499 return; |
| 408 | 500 |
| 501 gfx::ScrollOffset offset = CurrentOffset(); | |
| 409 if (source == horiz_sb_ && horiz_sb_->visible()) { | 502 if (source == horiz_sb_ && horiz_sb_->visible()) { |
| 410 position = AdjustPosition(contents_->x(), position, contents_->width(), | 503 position = AdjustPosition(offset.x(), position, contents_->width(), |
| 411 contents_viewport_->width()); | 504 contents_viewport_->width()); |
| 412 if (-contents_->x() == position) | 505 if (offset.x() == position) |
| 413 return; | 506 return; |
| 414 contents_->SetX(-position); | 507 offset.set_x(position); |
| 415 if (header_) { | |
| 416 header_->SetX(-position); | |
| 417 header_->SchedulePaintInRect(header_->GetVisibleBounds()); | |
| 418 } | |
| 419 } else if (source == vert_sb_ && vert_sb_->visible()) { | 508 } else if (source == vert_sb_ && vert_sb_->visible()) { |
| 420 position = AdjustPosition(contents_->y(), position, contents_->height(), | 509 position = AdjustPosition(offset.y(), position, contents_->height(), |
| 421 contents_viewport_->height()); | 510 contents_viewport_->height()); |
| 422 if (-contents_->y() == position) | 511 if (offset.y() == position) |
| 423 return; | 512 return; |
| 424 contents_->SetY(-position); | 513 offset.set_y(position); |
| 425 } | 514 } |
| 426 contents_->SchedulePaintInRect(contents_->GetVisibleBounds()); | 515 ScrollToOffset(offset); |
| 516 | |
| 517 if (!contents_container_) | |
| 518 contents_->SchedulePaintInRect(contents_->GetVisibleBounds()); | |
| 427 } | 519 } |
| 428 | 520 |
| 429 int ScrollView::GetScrollIncrement(ScrollBar* source, bool is_page, | 521 int ScrollView::GetScrollIncrement(ScrollBar* source, bool is_page, |
| 430 bool is_positive) { | 522 bool is_positive) { |
| 431 bool is_horizontal = source->IsHorizontal(); | 523 bool is_horizontal = source->IsHorizontal(); |
| 432 int amount = 0; | 524 int amount = 0; |
| 433 if (contents_) { | 525 if (contents_) { |
| 434 if (is_page) { | 526 if (is_page) { |
| 435 amount = contents_->GetPageScrollIncrement( | 527 amount = contents_->GetPageScrollIncrement( |
| 436 this, is_horizontal, is_positive); | 528 this, is_horizontal, is_positive); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 497 // corner. This is done by setting the offset to -X or -Y. For down | 589 // corner. This is done by setting the offset to -X or -Y. For down |
| 498 // or right shifts we need to make sure it appears in the | 590 // or right shifts we need to make sure it appears in the |
| 499 // lower/right corner. This is calculated by taking max_x or max_y | 591 // lower/right corner. This is calculated by taking max_x or max_y |
| 500 // and scaling it back by the size of the viewport. | 592 // and scaling it back by the size of the viewport. |
| 501 const int new_x = | 593 const int new_x = |
| 502 (vis_rect.x() > x) ? x : std::max(0, max_x - contents_viewport_->width()); | 594 (vis_rect.x() > x) ? x : std::max(0, max_x - contents_viewport_->width()); |
| 503 const int new_y = | 595 const int new_y = |
| 504 (vis_rect.y() > y) ? y : std::max(0, max_y - | 596 (vis_rect.y() > y) ? y : std::max(0, max_y - |
| 505 contents_viewport_->height()); | 597 contents_viewport_->height()); |
| 506 | 598 |
| 507 contents_->SetX(-new_x); | 599 ScrollToOffset(gfx::ScrollOffset(new_x, new_y)); |
| 508 if (header_) | |
| 509 header_->SetX(-new_x); | |
| 510 contents_->SetY(-new_y); | |
| 511 UpdateScrollBarPositions(); | 600 UpdateScrollBarPositions(); |
| 512 } | 601 } |
| 513 | 602 |
| 514 void ScrollView::ComputeScrollBarsVisibility(const gfx::Size& vp_size, | 603 void ScrollView::ComputeScrollBarsVisibility(const gfx::Size& vp_size, |
| 515 const gfx::Size& content_size, | 604 const gfx::Size& content_size, |
| 516 bool* horiz_is_shown, | 605 bool* horiz_is_shown, |
| 517 bool* vert_is_shown) const { | 606 bool* vert_is_shown) const { |
| 518 // Try to fit both ways first, then try vertical bar only, then horizontal | 607 // Try to fit both ways first, then try vertical bar only, then horizontal |
| 519 // bar only, then defaults to both shown. | 608 // bar only, then defaults to both shown. |
| 520 if (content_size.width() <= vp_size.width() && | 609 if (content_size.width() <= vp_size.width() && |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 548 } else { | 637 } else { |
| 549 RemoveChildView(control); | 638 RemoveChildView(control); |
| 550 control->SetVisible(false); | 639 control->SetVisible(false); |
| 551 } | 640 } |
| 552 } | 641 } |
| 553 | 642 |
| 554 void ScrollView::UpdateScrollBarPositions() { | 643 void ScrollView::UpdateScrollBarPositions() { |
| 555 if (!contents_) | 644 if (!contents_) |
| 556 return; | 645 return; |
| 557 | 646 |
| 647 const gfx::ScrollOffset offset = CurrentOffset(); | |
| 558 if (horiz_sb_->visible()) { | 648 if (horiz_sb_->visible()) { |
| 559 int vw = contents_viewport_->width(); | 649 int vw = contents_viewport_->width(); |
| 560 int cw = contents_->width(); | 650 int cw = contents_->width(); |
| 561 int origin = contents_->x(); | 651 horiz_sb_->Update(vw, cw, offset.x()); |
| 562 horiz_sb_->Update(vw, cw, -origin); | |
| 563 } | 652 } |
| 564 if (vert_sb_->visible()) { | 653 if (vert_sb_->visible()) { |
| 565 int vh = contents_viewport_->height(); | 654 int vh = contents_viewport_->height(); |
| 566 int ch = contents_->height(); | 655 int ch = contents_->height(); |
| 567 int origin = contents_->y(); | 656 vert_sb_->Update(vh, ch, offset.y()); |
| 568 vert_sb_->Update(vh, ch, -origin); | |
| 569 } | 657 } |
| 570 } | 658 } |
| 571 | 659 |
| 660 gfx::ScrollOffset ScrollView::CurrentOffset() const { | |
| 661 if (contents_container_) | |
| 662 return contents_container_->layer()->CurrentScrollOffset(); | |
| 663 return gfx::ScrollOffset(-contents_->x(), -contents_->y()); | |
| 664 } | |
| 665 | |
| 666 void ScrollView::ScrollToOffset(const gfx::ScrollOffset& offset) { | |
| 667 if (contents_container_) { | |
| 668 contents_container_->layer()->SetScrollOffset(offset); | |
| 669 | |
| 670 // TODO(tapted): Remove this call to OnLayerScrolled(). It's unnecessary, | |
| 671 // but will only be invoked (asynchronously) when a Compositor is present | |
| 672 // and commits a frame, which isn't true in some tests. | |
| 673 OnLayerScrolled(); | |
| 674 } else { | |
| 675 contents_->SetPosition(gfx::Point(-offset.x(), -offset.y())); | |
| 676 ScrollHeader(); | |
| 677 } | |
| 678 } | |
| 679 | |
| 680 void ScrollView::OnLayerScrolled() { | |
| 681 UpdateScrollBarPositions(); | |
| 682 ScrollHeader(); | |
| 683 } | |
| 684 | |
| 685 void ScrollView::ScrollHeader() { | |
| 686 if (!header_) | |
| 687 return; | |
| 688 | |
| 689 int x_offset = CurrentOffset().x(); | |
| 690 if (header_->x() != -x_offset) { | |
| 691 header_->SetX(-x_offset); | |
| 692 header_->SchedulePaintInRect(header_->GetVisibleBounds()); | |
| 693 } | |
| 694 } | |
| 695 | |
| 572 // VariableRowHeightScrollHelper ---------------------------------------------- | 696 // VariableRowHeightScrollHelper ---------------------------------------------- |
| 573 | 697 |
| 574 VariableRowHeightScrollHelper::VariableRowHeightScrollHelper( | 698 VariableRowHeightScrollHelper::VariableRowHeightScrollHelper( |
| 575 Controller* controller) : controller_(controller) { | 699 Controller* controller) : controller_(controller) { |
| 576 } | 700 } |
| 577 | 701 |
| 578 VariableRowHeightScrollHelper::~VariableRowHeightScrollHelper() { | 702 VariableRowHeightScrollHelper::~VariableRowHeightScrollHelper() { |
| 579 } | 703 } |
| 580 | 704 |
| 581 int VariableRowHeightScrollHelper::GetPageScrollIncrement( | 705 int VariableRowHeightScrollHelper::GetPageScrollIncrement( |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 636 | 760 |
| 637 VariableRowHeightScrollHelper::RowInfo | 761 VariableRowHeightScrollHelper::RowInfo |
| 638 FixedRowHeightScrollHelper::GetRowInfo(int y) { | 762 FixedRowHeightScrollHelper::GetRowInfo(int y) { |
| 639 if (y < top_margin_) | 763 if (y < top_margin_) |
| 640 return RowInfo(0, top_margin_); | 764 return RowInfo(0, top_margin_); |
| 641 return RowInfo((y - top_margin_) / row_height_ * row_height_ + top_margin_, | 765 return RowInfo((y - top_margin_) / row_height_ * row_height_ + top_margin_, |
| 642 row_height_); | 766 row_height_); |
| 643 } | 767 } |
| 644 | 768 |
| 645 } // namespace views | 769 } // namespace views |
| OLD | NEW |