File: tab_strip_scroll_session.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (184 lines) | stat: -rw-r--r-- 7,122 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/tabs/dragging/tab_strip_scroll_session.h"

#include <algorithm>

#include "base/check.h"
#include "chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/controls/scroll_view.h"

namespace {
// Duration after which the repeating timer event is called
const base::TimeDelta kScrollTimerDelay = base::Milliseconds(10);
// This is used to calculate the offset but is  also helpful
// for different minimum sizes of tabs.
const int kNumberOfTabsScrolledPerSecond = 4;
}  // namespace

TabStripScrollSession::TabStripScrollSession(
    TabDragWithScrollManager& tab_drag_with_scroll_manager)
    : tab_drag_with_scroll_manager_(tab_drag_with_scroll_manager) {}

TabStripScrollSession::~TabStripScrollSession() = default;

TabStripScrollSessionWithTimer::TabStripScrollSessionWithTimer(
    TabDragWithScrollManager& tab_drag_with_scroll_manager,
    ScrollSessionTimerType timer_type)
    : TabStripScrollSession(tab_drag_with_scroll_manager),
      scroll_timer_(std::make_unique<base::RepeatingTimer>()),
      timer_type_(timer_type) {}

TabStripScrollSessionWithTimer::~TabStripScrollSessionWithTimer() = default;

void TabStripScrollSessionWithTimer::MaybeStart() {
  if (!tab_drag_with_scroll_manager_->GetAttachedContext() || IsRunning()) {
    return;
  }

  const TabStripScrollSession::TabScrollDirection scroll_direction =
      GetTabScrollDirection();

  if (scroll_direction !=
      TabStripScrollSession::TabScrollDirection::kNoScroll) {
    Start(scroll_direction);
  }
}

void TabStripScrollSessionWithTimer::Start(TabScrollDirection direction) {
  scroll_timer_->Start(
      FROM_HERE, kScrollTimerDelay,
      base::BindRepeating(&TabStripScrollSessionWithTimer::TabScrollCallback,
                          base::Unretained(this)));
  scroll_direction_ = direction;
}

void TabStripScrollSessionWithTimer::TabScrollCallback() {
  DCHECK(scroll_direction_ !=
         TabStripScrollSession::TabScrollDirection::kNoScroll);
  if (GetTabScrollDirection() != scroll_direction_) {
    scroll_timer_->Stop();
    return;
  }

  const int tab_scroll_offset = CalculateSpeed();
  views::ScrollView* const scroll_view =
      tab_drag_with_scroll_manager_->GetScrollView();
  scroll_view->ScrollByOffset(gfx::PointF(tab_scroll_offset, 0));

  tab_drag_with_scroll_manager_->MoveAttached(
      tab_drag_with_scroll_manager_->GetLastPointInScreen());
}

bool TabStripScrollSessionWithTimer::IsRunning() {
  return scroll_timer_->IsRunning();
}

int TabStripScrollSessionWithTimer::CalculateSpeed() {
  // TODO(crbug.com/40875170): Use the expected offset at a given time to
  // calculate the current offset. This can help with making up
  // for rounding off the calculation to int in the next call.
  // Also use the time elapsed to calculate the expected offset.
  DCHECK(scroll_direction_ !=
         TabStripScrollSession::TabScrollDirection::kNoScroll);
  const int tab_scroll_offset =
      (scroll_direction_ == TabScrollDirection::kScrollTowardsTrailingTabs)
          ? ceil(CalculateBaseScrollOffset())
          : floor(-CalculateBaseScrollOffset());

  switch (timer_type_) {
    case TabStripScrollSessionWithTimer::ScrollSessionTimerType::kConstantTimer:
      return tab_scroll_offset;
    case TabStripScrollSessionWithTimer::ScrollSessionTimerType::kVariableTimer:
      if (scroll_direction_ == TabScrollDirection::kScrollTowardsTrailingTabs) {
        return ceil(std::clamp(GetRatioInScrollableRegion() * tab_scroll_offset,
                               0.0, CalculateBaseScrollOffset() * 3));
      } else {
        return floor(
            std::clamp(GetRatioInScrollableRegion() * tab_scroll_offset,
                       CalculateBaseScrollOffset() * -3, 0.0));
      }
    default:
      NOTREACHED();
  }
}

double TabStripScrollSessionWithTimer::CalculateBaseScrollOffset() {
  return kNumberOfTabsScrolledPerSecond *
         TabStyle::Get()->GetMinimumInactiveWidth() *
         (kScrollTimerDelay / base::Milliseconds(1000));
}

double TabStripScrollSessionWithTimer::GetRatioInScrollableRegion() {
  const gfx::Rect dragged_tabs_rect_drag_context_coord =
      tab_drag_with_scroll_manager_->GetEnclosingRectForDraggedTabs();
  const views::ScrollView* const scroll_view =
      tab_drag_with_scroll_manager_->GetScrollView();
  const gfx::Rect visible_rect_drag_context_coord =
      gfx::ToEnclosingRect(views::View::ConvertRectToTarget(
          scroll_view->contents(),
          tab_drag_with_scroll_manager_->GetAttachedContext(),
          gfx::RectF(scroll_view->GetVisibleRect())));

  double ratio = 0;
  double scrollable_start = 0;

  switch (scroll_direction_) {
    case TabStripScrollSession::TabScrollDirection::kScrollTowardsTrailingTabs:
      scrollable_start =
          visible_rect_drag_context_coord.right() - GetScrollableOffset();
      ratio =
          (dragged_tabs_rect_drag_context_coord.right() - scrollable_start) /
          GetScrollableOffset();
      return ratio;
    case TabStripScrollSession::TabScrollDirection::kScrollTowardsLeadingTabs:
      scrollable_start =
          visible_rect_drag_context_coord.origin().x() + GetScrollableOffset();
      ratio = (scrollable_start -
               dragged_tabs_rect_drag_context_coord.origin().x()) /
              GetScrollableOffset();
      return ratio;
    default:
      return ratio;
  }
}

TabStripScrollSession::TabScrollDirection
TabStripScrollSessionWithTimer::GetTabScrollDirection() {
  const views::ScrollView* const scroll_view =
      tab_drag_with_scroll_manager_->GetScrollView();

  const gfx::Rect dragged_tabs_rect_drag_context_coord =
      tab_drag_with_scroll_manager_->GetEnclosingRectForDraggedTabs();
  const gfx::Rect visible_rect_drag_context_coord =
      gfx::ToEnclosingRect(views::View::ConvertRectToTarget(
          scroll_view->contents(),
          tab_drag_with_scroll_manager_->GetAttachedContext(),
          gfx::RectF(scroll_view->GetVisibleRect())));

  const bool maybe_scroll_towards_trailing_tabs =
      dragged_tabs_rect_drag_context_coord.right() >=
      (visible_rect_drag_context_coord.right() - GetScrollableOffset());

  const bool maybe_scroll_towards_leading_tabs =
      dragged_tabs_rect_drag_context_coord.origin().x() <=
      (visible_rect_drag_context_coord.origin().x() + GetScrollableOffset());

  // TODO(crbug.com/40875138): Add case for both maybe scroll left and right.
  // This would happen when many tabs are selected.
  if (maybe_scroll_towards_trailing_tabs) {
    return TabStripScrollSession::TabScrollDirection::
        kScrollTowardsTrailingTabs;
  } else if (maybe_scroll_towards_leading_tabs) {
    return TabStripScrollSession::TabScrollDirection::kScrollTowardsLeadingTabs;
  } else {
    return TabStripScrollSession::TabScrollDirection::kNoScroll;
  }
}

int TabStripScrollSession::GetScrollableOffset() const {
  return TabStyle::Get()->GetMinimumInactiveWidth() / 5;
}