scrollbar_animation_controller.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "cc/input/scrollbar_animation_controller.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include "base/bind.h"
  8. #include "base/cxx17_backports.h"
  9. #include "base/memory/ptr_util.h"
  10. #include "base/time/time.h"
  11. #include "cc/trees/layer_tree_impl.h"
  12. namespace cc {
  13. std::unique_ptr<ScrollbarAnimationController>
  14. ScrollbarAnimationController::CreateScrollbarAnimationControllerAndroid(
  15. ElementId scroll_element_id,
  16. ScrollbarAnimationControllerClient* client,
  17. base::TimeDelta fade_delay,
  18. base::TimeDelta fade_duration,
  19. float initial_opacity) {
  20. return base::WrapUnique(new ScrollbarAnimationController(
  21. scroll_element_id, client, fade_delay, fade_duration, initial_opacity));
  22. }
  23. std::unique_ptr<ScrollbarAnimationController>
  24. ScrollbarAnimationController::CreateScrollbarAnimationControllerAuraOverlay(
  25. ElementId scroll_element_id,
  26. ScrollbarAnimationControllerClient* client,
  27. base::TimeDelta fade_delay,
  28. base::TimeDelta fade_duration,
  29. base::TimeDelta thinning_duration,
  30. float initial_opacity) {
  31. return base::WrapUnique(new ScrollbarAnimationController(
  32. scroll_element_id, client, fade_delay, fade_duration, thinning_duration,
  33. initial_opacity));
  34. }
  35. ScrollbarAnimationController::ScrollbarAnimationController(
  36. ElementId scroll_element_id,
  37. ScrollbarAnimationControllerClient* client,
  38. base::TimeDelta fade_delay,
  39. base::TimeDelta fade_duration,
  40. float initial_opacity)
  41. : client_(client),
  42. fade_delay_(fade_delay),
  43. fade_duration_(fade_duration),
  44. need_trigger_scrollbar_fade_in_(false),
  45. is_animating_(false),
  46. animation_change_(AnimationChange::NONE),
  47. scroll_element_id_(scroll_element_id),
  48. opacity_(initial_opacity),
  49. show_scrollbars_on_scroll_gesture_(false),
  50. need_thinning_animation_(false),
  51. need_fade_animation_(true),
  52. is_mouse_down_(false),
  53. tickmarks_showing_(false) {}
  54. ScrollbarAnimationController::ScrollbarAnimationController(
  55. ElementId scroll_element_id,
  56. ScrollbarAnimationControllerClient* client,
  57. base::TimeDelta fade_delay,
  58. base::TimeDelta fade_duration,
  59. base::TimeDelta thinning_duration,
  60. float initial_opacity)
  61. : client_(client),
  62. fade_delay_(fade_delay),
  63. fade_duration_(fade_duration),
  64. need_trigger_scrollbar_fade_in_(false),
  65. is_animating_(false),
  66. animation_change_(AnimationChange::NONE),
  67. scroll_element_id_(scroll_element_id),
  68. opacity_(initial_opacity),
  69. show_scrollbars_on_scroll_gesture_(true),
  70. need_thinning_animation_(true),
  71. need_fade_animation_(!client->IsFluentScrollbar()),
  72. is_mouse_down_(false),
  73. tickmarks_showing_(false) {
  74. vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create(
  75. scroll_element_id, ScrollbarOrientation::VERTICAL, client,
  76. thinning_duration);
  77. horizontal_controller_ = SingleScrollbarAnimationControllerThinning::Create(
  78. scroll_element_id, ScrollbarOrientation::HORIZONTAL, client,
  79. thinning_duration);
  80. }
  81. ScrollbarAnimationController::~ScrollbarAnimationController() = default;
  82. ScrollbarSet ScrollbarAnimationController::Scrollbars() const {
  83. return client_->ScrollbarsFor(scroll_element_id_);
  84. }
  85. SingleScrollbarAnimationControllerThinning&
  86. ScrollbarAnimationController::GetScrollbarAnimationController(
  87. ScrollbarOrientation orientation) const {
  88. DCHECK(need_thinning_animation_);
  89. if (orientation == ScrollbarOrientation::VERTICAL)
  90. return *(vertical_controller_.get());
  91. else
  92. return *(horizontal_controller_.get());
  93. }
  94. void ScrollbarAnimationController::StartAnimation() {
  95. DCHECK(animation_change_ != AnimationChange::NONE);
  96. delayed_scrollbar_animation_.Cancel();
  97. need_trigger_scrollbar_fade_in_ = false;
  98. is_animating_ = true;
  99. last_awaken_time_ = base::TimeTicks();
  100. client_->SetNeedsAnimateForScrollbarAnimation();
  101. }
  102. void ScrollbarAnimationController::StopAnimation() {
  103. delayed_scrollbar_animation_.Cancel();
  104. need_trigger_scrollbar_fade_in_ = false;
  105. is_animating_ = false;
  106. animation_change_ = AnimationChange::NONE;
  107. }
  108. void ScrollbarAnimationController::PostDelayedAnimation(
  109. AnimationChange animation_change) {
  110. // In contrast to Aura overlay scrollbars, Fluent overlay scrollbars
  111. // should not fade out completely. After the initial paint, they remain on the
  112. // screen in the minimal (thin) mode by default and can expand/transition to
  113. // the full (thick) mode. The minimal <-> full mode thinning animation is
  114. // controlled by SingleScrollbarAnimationControllerThinning.
  115. if (!need_fade_animation_)
  116. return;
  117. animation_change_ = animation_change;
  118. delayed_scrollbar_animation_.Cancel();
  119. delayed_scrollbar_animation_.Reset(
  120. base::BindOnce(&ScrollbarAnimationController::StartAnimation,
  121. weak_factory_.GetWeakPtr()));
  122. client_->PostDelayedScrollbarAnimationTask(
  123. delayed_scrollbar_animation_.callback(), fade_delay_);
  124. }
  125. bool ScrollbarAnimationController::Animate(base::TimeTicks now) {
  126. bool animated = false;
  127. for (ScrollbarLayerImplBase* scrollbar : Scrollbars()) {
  128. if (!scrollbar->CanScrollOrientation())
  129. scrollbar->SetOverlayScrollbarLayerOpacityAnimated(0);
  130. }
  131. if (is_animating_) {
  132. DCHECK(animation_change_ != AnimationChange::NONE);
  133. if (last_awaken_time_.is_null())
  134. last_awaken_time_ = now;
  135. float progress = AnimationProgressAtTime(now);
  136. RunAnimationFrame(progress);
  137. if (is_animating_)
  138. client_->SetNeedsAnimateForScrollbarAnimation();
  139. animated = true;
  140. }
  141. if (need_thinning_animation_) {
  142. animated |= vertical_controller_->Animate(now);
  143. animated |= horizontal_controller_->Animate(now);
  144. }
  145. return animated;
  146. }
  147. float ScrollbarAnimationController::AnimationProgressAtTime(
  148. base::TimeTicks now) {
  149. const base::TimeDelta delta = now - last_awaken_time_;
  150. return base::clamp(static_cast<float>(delta / fade_duration_), 0.0f, 1.0f);
  151. }
  152. void ScrollbarAnimationController::RunAnimationFrame(float progress) {
  153. float opacity;
  154. DCHECK(animation_change_ != AnimationChange::NONE);
  155. if (animation_change_ == AnimationChange::FADE_IN) {
  156. opacity = std::max(progress, opacity_);
  157. } else {
  158. opacity = std::min(1.f - progress, opacity_);
  159. }
  160. ApplyOpacityToScrollbars(opacity);
  161. if (progress == 1.f)
  162. StopAnimation();
  163. }
  164. void ScrollbarAnimationController::DidScrollUpdate() {
  165. UpdateScrollbarState();
  166. }
  167. void ScrollbarAnimationController::UpdateScrollbarState() {
  168. if (need_thinning_animation_ && Captured())
  169. return;
  170. StopAnimation();
  171. Show();
  172. // We don't fade out scrollbar if they need thinning animation (Aura
  173. // Overlay) and mouse is near or tickmarks show.
  174. if (need_thinning_animation_) {
  175. if (!MouseIsNearAnyScrollbar() && !tickmarks_showing_)
  176. PostDelayedAnimation(AnimationChange::FADE_OUT);
  177. } else {
  178. PostDelayedAnimation(AnimationChange::FADE_OUT);
  179. }
  180. if (need_thinning_animation_) {
  181. vertical_controller_->UpdateThumbThicknessScale();
  182. horizontal_controller_->UpdateThumbThicknessScale();
  183. }
  184. }
  185. void ScrollbarAnimationController::WillUpdateScroll() {
  186. if (show_scrollbars_on_scroll_gesture_)
  187. UpdateScrollbarState();
  188. }
  189. void ScrollbarAnimationController::DidRequestShow() {
  190. UpdateScrollbarState();
  191. }
  192. void ScrollbarAnimationController::UpdateTickmarksVisibility(bool show) {
  193. if (!need_thinning_animation_)
  194. return;
  195. if (tickmarks_showing_ == show)
  196. return;
  197. tickmarks_showing_ = show;
  198. UpdateScrollbarState();
  199. }
  200. void ScrollbarAnimationController::DidMouseDown() {
  201. if (!need_thinning_animation_)
  202. return;
  203. is_mouse_down_ = true;
  204. if (ScrollbarsHidden()) {
  205. if (need_trigger_scrollbar_fade_in_) {
  206. delayed_scrollbar_animation_.Cancel();
  207. need_trigger_scrollbar_fade_in_ = false;
  208. }
  209. return;
  210. }
  211. vertical_controller_->DidMouseDown();
  212. horizontal_controller_->DidMouseDown();
  213. }
  214. void ScrollbarAnimationController::DidMouseUp() {
  215. if (!need_thinning_animation_)
  216. return;
  217. is_mouse_down_ = false;
  218. if (!Captured()) {
  219. if (MouseIsNearAnyScrollbar() && ScrollbarsHidden()) {
  220. PostDelayedAnimation(AnimationChange::FADE_IN);
  221. need_trigger_scrollbar_fade_in_ = true;
  222. }
  223. return;
  224. }
  225. vertical_controller_->DidMouseUp();
  226. horizontal_controller_->DidMouseUp();
  227. if (!MouseIsNearAnyScrollbar() && !ScrollbarsHidden() && !tickmarks_showing_)
  228. PostDelayedAnimation(AnimationChange::FADE_OUT);
  229. }
  230. void ScrollbarAnimationController::DidMouseLeave() {
  231. if (!need_thinning_animation_)
  232. return;
  233. vertical_controller_->DidMouseLeave();
  234. horizontal_controller_->DidMouseLeave();
  235. delayed_scrollbar_animation_.Cancel();
  236. need_trigger_scrollbar_fade_in_ = false;
  237. if (ScrollbarsHidden() || Captured() || tickmarks_showing_)
  238. return;
  239. PostDelayedAnimation(AnimationChange::FADE_OUT);
  240. }
  241. void ScrollbarAnimationController::DidMouseMove(
  242. const gfx::PointF& device_viewport_point) {
  243. if (!need_thinning_animation_)
  244. return;
  245. bool need_trigger_scrollbar_fade_in_before = need_trigger_scrollbar_fade_in_;
  246. vertical_controller_->DidMouseMove(device_viewport_point);
  247. horizontal_controller_->DidMouseMove(device_viewport_point);
  248. if (Captured() || tickmarks_showing_) {
  249. DCHECK(!ScrollbarsHidden());
  250. return;
  251. }
  252. if (ScrollbarsHidden()) {
  253. // Do not fade in scrollbar when user interacting with the content below
  254. // scrollbar.
  255. if (is_mouse_down_)
  256. return;
  257. need_trigger_scrollbar_fade_in_ = MouseIsNearAnyScrollbar();
  258. if (need_trigger_scrollbar_fade_in_before !=
  259. need_trigger_scrollbar_fade_in_) {
  260. if (need_trigger_scrollbar_fade_in_) {
  261. PostDelayedAnimation(AnimationChange::FADE_IN);
  262. } else {
  263. delayed_scrollbar_animation_.Cancel();
  264. }
  265. }
  266. } else {
  267. if (MouseIsNearAnyScrollbar()) {
  268. Show();
  269. StopAnimation();
  270. } else if (!is_animating_) {
  271. PostDelayedAnimation(AnimationChange::FADE_OUT);
  272. }
  273. }
  274. }
  275. bool ScrollbarAnimationController::MouseIsOverScrollbarThumb(
  276. ScrollbarOrientation orientation) const {
  277. DCHECK(need_thinning_animation_);
  278. return GetScrollbarAnimationController(orientation)
  279. .mouse_is_over_scrollbar_thumb();
  280. }
  281. bool ScrollbarAnimationController::MouseIsNearScrollbarThumb(
  282. ScrollbarOrientation orientation) const {
  283. DCHECK(need_thinning_animation_);
  284. return GetScrollbarAnimationController(orientation)
  285. .mouse_is_near_scrollbar_thumb();
  286. }
  287. bool ScrollbarAnimationController::MouseIsNearScrollbar(
  288. ScrollbarOrientation orientation) const {
  289. DCHECK(need_thinning_animation_);
  290. return GetScrollbarAnimationController(orientation)
  291. .mouse_is_near_scrollbar_track();
  292. }
  293. bool ScrollbarAnimationController::MouseIsNearAnyScrollbar() const {
  294. DCHECK(need_thinning_animation_);
  295. return vertical_controller_->mouse_is_near_scrollbar_track() ||
  296. horizontal_controller_->mouse_is_near_scrollbar_track();
  297. }
  298. bool ScrollbarAnimationController::ScrollbarsHidden() const {
  299. return opacity_ == 0.0f;
  300. }
  301. bool ScrollbarAnimationController::Captured() const {
  302. DCHECK(need_thinning_animation_);
  303. return GetScrollbarAnimationController(ScrollbarOrientation::VERTICAL)
  304. .captured() ||
  305. GetScrollbarAnimationController(ScrollbarOrientation::HORIZONTAL)
  306. .captured();
  307. }
  308. void ScrollbarAnimationController::Show() {
  309. delayed_scrollbar_animation_.Cancel();
  310. ApplyOpacityToScrollbars(1.0f);
  311. }
  312. void ScrollbarAnimationController::ApplyOpacityToScrollbars(float opacity) {
  313. for (ScrollbarLayerImplBase* scrollbar : Scrollbars()) {
  314. DCHECK(scrollbar->is_overlay_scrollbar());
  315. float effective_opacity = scrollbar->CanScrollOrientation() ? opacity : 0;
  316. scrollbar->SetOverlayScrollbarLayerOpacityAnimated(effective_opacity);
  317. }
  318. bool previously_visible_ = opacity_ > 0.0f;
  319. bool currently_visible = opacity > 0.0f;
  320. if (opacity_ != opacity)
  321. client_->SetNeedsRedrawForScrollbarAnimation();
  322. opacity_ = opacity;
  323. if (previously_visible_ != currently_visible) {
  324. client_->DidChangeScrollbarVisibility();
  325. visibility_changed_ = true;
  326. }
  327. }
  328. } // namespace cc