flood_fill_ink_drop_ripple.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // Copyright 2016 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 "ui/views/animation/flood_fill_ink_drop_ripple.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/logging.h"
  10. #include "third_party/skia/include/core/SkColor.h"
  11. #include "ui/compositor/layer.h"
  12. #include "ui/compositor/layer_animation_sequence.h"
  13. #include "ui/compositor/scoped_layer_animation_settings.h"
  14. #include "ui/gfx/animation/animation.h"
  15. #include "ui/gfx/geometry/point_conversions.h"
  16. #include "ui/gfx/geometry/vector2d_f.h"
  17. #include "ui/views/animation/animation_builder.h"
  18. #include "ui/views/animation/ink_drop_util.h"
  19. #include "ui/views/style/platform_style.h"
  20. namespace {
  21. // The minimum radius to use when scaling the painted layers. Smaller values
  22. // were causing visual anomalies.
  23. constexpr float kMinRadius = 1.f;
  24. // All the sub animations that are used to animate each of the InkDropStates.
  25. // These are used to get time durations with
  26. // GetAnimationDuration(InkDropSubAnimations). Note that in general a sub
  27. // animation defines the duration for either a transformation animation or an
  28. // opacity animation but there are some exceptions where an entire InkDropState
  29. // animation consists of only 1 sub animation and it defines the duration for
  30. // both the transformation and opacity animations.
  31. enum InkDropSubAnimations {
  32. // HIDDEN sub animations.
  33. // The HIDDEN sub animation that is fading out to a hidden opacity.
  34. HIDDEN_FADE_OUT,
  35. // The HIDDEN sub animation that transform the circle to a small one.
  36. HIDDEN_TRANSFORM,
  37. // ACTION_PENDING sub animations.
  38. // The ACTION_PENDING sub animation that fades in to the visible opacity.
  39. ACTION_PENDING_FADE_IN,
  40. // The ACTION_PENDING sub animation that transforms the circle to fill the
  41. // bounds.
  42. ACTION_PENDING_TRANSFORM,
  43. // ACTION_TRIGGERED sub animations.
  44. // The ACTION_TRIGGERED sub animation that is fading out to a hidden opacity.
  45. ACTION_TRIGGERED_FADE_OUT,
  46. // ALTERNATE_ACTION_PENDING sub animations.
  47. // The ALTERNATE_ACTION_PENDING animation has only one sub animation which
  48. // animates
  49. // the circleto fill the bounds at visible opacity.
  50. ALTERNATE_ACTION_PENDING,
  51. // ALTERNATE_ACTION_TRIGGERED sub animations.
  52. // The ALTERNATE_ACTION_TRIGGERED sub animation that is fading out to a hidden
  53. // opacity.
  54. ALTERNATE_ACTION_TRIGGERED_FADE_OUT,
  55. // ACTIVATED sub animations.
  56. // The ACTIVATED sub animation that is fading in to the visible opacity.
  57. ACTIVATED_FADE_IN,
  58. // The ACTIVATED sub animation that transforms the circle to fill the entire
  59. // bounds.
  60. ACTIVATED_TRANSFORM,
  61. // DEACTIVATED sub animations.
  62. // The DEACTIVATED sub animation that is fading out to a hidden opacity.
  63. DEACTIVATED_FADE_OUT,
  64. };
  65. // Duration constants for InkDropStateSubAnimations. See the
  66. // InkDropStateSubAnimations enum documentation for more info.
  67. int kAnimationDurationInMs[] = {
  68. 200, // HIDDEN_FADE_OUT
  69. 300, // HIDDEN_TRANSFORM
  70. 0, // ACTION_PENDING_FADE_IN
  71. 240, // ACTION_PENDING_TRANSFORM
  72. 300, // ACTION_TRIGGERED_FADE_OUT
  73. 200, // ALTERNATE_ACTION_PENDING
  74. 300, // ALTERNATE_ACTION_TRIGGERED_FADE_OUT
  75. 150, // ACTIVATED_FADE_IN
  76. 200, // ACTIVATED_TRANSFORM
  77. 300, // DEACTIVATED_FADE_OUT
  78. };
  79. gfx::Rect CalculateClipBounds(const gfx::Size& host_size,
  80. const gfx::Insets& clip_insets) {
  81. gfx::Rect clip_bounds(host_size);
  82. clip_bounds.Inset(clip_insets);
  83. return clip_bounds;
  84. }
  85. float CalculateCircleLayerRadius(const gfx::Rect& clip_bounds) {
  86. return std::max(clip_bounds.width(), clip_bounds.height()) / 2.f;
  87. }
  88. } // namespace
  89. namespace views {
  90. FloodFillInkDropRipple::FloodFillInkDropRipple(const gfx::Size& host_size,
  91. const gfx::Insets& clip_insets,
  92. const gfx::Point& center_point,
  93. SkColor color,
  94. float visible_opacity)
  95. : clip_insets_(clip_insets),
  96. center_point_(center_point),
  97. visible_opacity_(visible_opacity),
  98. use_hide_transform_duration_for_hide_fade_out_(false),
  99. duration_factor_(1.f),
  100. root_layer_(ui::LAYER_NOT_DRAWN),
  101. circle_layer_delegate_(color,
  102. CalculateCircleLayerRadius(
  103. CalculateClipBounds(host_size, clip_insets))) {
  104. gfx::Rect clip_bounds = CalculateClipBounds(host_size, clip_insets);
  105. root_layer_.SetName("FloodFillInkDropRipple:ROOT_LAYER");
  106. root_layer_.SetMasksToBounds(true);
  107. root_layer_.SetBounds(clip_bounds);
  108. root_callback_subscription_ =
  109. root_layer_.GetAnimator()->AddSequenceScheduledCallback(
  110. base::BindRepeating(
  111. &FloodFillInkDropRipple::OnLayerAnimationSequenceScheduled,
  112. base::Unretained(this)));
  113. const int painted_size_length =
  114. std::max(clip_bounds.width(), clip_bounds.height());
  115. painted_layer_.SetBounds(gfx::Rect(painted_size_length, painted_size_length));
  116. painted_layer_.SetFillsBoundsOpaquely(false);
  117. painted_layer_.set_delegate(&circle_layer_delegate_);
  118. painted_layer_.SetVisible(true);
  119. painted_layer_.SetOpacity(1.0);
  120. painted_layer_.SetMasksToBounds(false);
  121. painted_layer_.SetName("FloodFillInkDropRipple:PAINTED_LAYER");
  122. painted_layer_callback_subscription_ =
  123. painted_layer_.GetAnimator()->AddSequenceScheduledCallback(
  124. base::BindRepeating(
  125. &FloodFillInkDropRipple::OnLayerAnimationSequenceScheduled,
  126. base::Unretained(this)));
  127. root_layer_.Add(&painted_layer_);
  128. SetStateToHidden();
  129. }
  130. FloodFillInkDropRipple::FloodFillInkDropRipple(const gfx::Size& host_size,
  131. const gfx::Point& center_point,
  132. SkColor color,
  133. float visible_opacity)
  134. : FloodFillInkDropRipple(host_size,
  135. gfx::Insets(),
  136. center_point,
  137. color,
  138. visible_opacity) {}
  139. FloodFillInkDropRipple::~FloodFillInkDropRipple() {
  140. // Explicitly aborting all the animations ensures all callbacks are invoked
  141. // while this instance still exists.
  142. AbortAllAnimations();
  143. }
  144. void FloodFillInkDropRipple::SnapToActivated() {
  145. InkDropRipple::SnapToActivated();
  146. SetOpacity(visible_opacity_);
  147. painted_layer_.SetTransform(GetMaxSizeTargetTransform());
  148. }
  149. ui::Layer* FloodFillInkDropRipple::GetRootLayer() {
  150. return &root_layer_;
  151. }
  152. void FloodFillInkDropRipple::AnimateStateChange(
  153. InkDropState old_ink_drop_state,
  154. InkDropState new_ink_drop_state) {
  155. switch (new_ink_drop_state) {
  156. case InkDropState::HIDDEN:
  157. if (!IsVisible()) {
  158. SetStateToHidden();
  159. } else {
  160. AnimationBuilder()
  161. .SetPreemptionStrategy(
  162. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  163. .Once()
  164. .SetDuration(GetAnimationDuration(HIDDEN_FADE_OUT))
  165. .SetOpacity(&root_layer_, kHiddenOpacity, gfx::Tween::EASE_IN_OUT)
  166. .At(base::TimeDelta())
  167. .SetDuration(GetAnimationDuration(HIDDEN_TRANSFORM))
  168. .SetTransform(&painted_layer_, CalculateTransform(kMinRadius),
  169. gfx::Tween::EASE_IN_OUT);
  170. }
  171. break;
  172. case InkDropState::ACTION_PENDING: {
  173. DLOG_IF(WARNING, InkDropState::HIDDEN != old_ink_drop_state)
  174. << "Invalid InkDropState transition. old_ink_drop_state="
  175. << ToString(old_ink_drop_state)
  176. << " new_ink_drop_state=" << ToString(new_ink_drop_state);
  177. AnimationBuilder()
  178. .SetPreemptionStrategy(
  179. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  180. .Once()
  181. .SetDuration(GetAnimationDuration(ACTION_PENDING_FADE_IN))
  182. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN)
  183. .At(base::TimeDelta())
  184. .SetDuration(GetAnimationDuration(ACTION_PENDING_TRANSFORM))
  185. .SetTransform(&painted_layer_, GetMaxSizeTargetTransform(),
  186. gfx::Tween::FAST_OUT_SLOW_IN);
  187. break;
  188. }
  189. case InkDropState::ACTION_TRIGGERED: {
  190. DLOG_IF(WARNING, old_ink_drop_state != InkDropState::HIDDEN &&
  191. old_ink_drop_state != InkDropState::ACTION_PENDING)
  192. << "Invalid InkDropState transition. old_ink_drop_state="
  193. << ToString(old_ink_drop_state)
  194. << " new_ink_drop_state=" << ToString(new_ink_drop_state);
  195. if (old_ink_drop_state == InkDropState::HIDDEN) {
  196. AnimateStateChange(old_ink_drop_state, InkDropState::ACTION_PENDING);
  197. }
  198. AnimationBuilder()
  199. .SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION)
  200. .Once()
  201. .SetDuration(GetAnimationDuration(ACTION_TRIGGERED_FADE_OUT))
  202. .SetOpacity(&root_layer_, kHiddenOpacity, gfx::Tween::EASE_IN_OUT);
  203. break;
  204. }
  205. case InkDropState::ALTERNATE_ACTION_PENDING: {
  206. DLOG_IF(WARNING, InkDropState::ACTION_PENDING != old_ink_drop_state)
  207. << "Invalid InkDropState transition. old_ink_drop_state="
  208. << ToString(old_ink_drop_state)
  209. << " new_ink_drop_state=" << ToString(new_ink_drop_state);
  210. AnimationBuilder()
  211. .SetPreemptionStrategy(
  212. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  213. .Once()
  214. .SetDuration(GetAnimationDuration(ALTERNATE_ACTION_PENDING))
  215. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN)
  216. .SetTransform(&painted_layer_, GetMaxSizeTargetTransform(),
  217. gfx::Tween::EASE_IN_OUT);
  218. break;
  219. }
  220. case InkDropState::ALTERNATE_ACTION_TRIGGERED:
  221. DLOG_IF(WARNING,
  222. InkDropState::ALTERNATE_ACTION_PENDING != old_ink_drop_state)
  223. << "Invalid InkDropState transition. old_ink_drop_state="
  224. << ToString(old_ink_drop_state)
  225. << " new_ink_drop_state=" << ToString(new_ink_drop_state);
  226. AnimationBuilder()
  227. .SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION)
  228. .Once()
  229. .SetDuration(
  230. GetAnimationDuration(ALTERNATE_ACTION_TRIGGERED_FADE_OUT))
  231. .SetOpacity(&root_layer_, kHiddenOpacity, gfx::Tween::EASE_IN_OUT);
  232. break;
  233. case InkDropState::ACTIVATED: {
  234. if (old_ink_drop_state != InkDropState::ACTION_PENDING) {
  235. AnimationBuilder()
  236. .SetPreemptionStrategy(
  237. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  238. .Once()
  239. .SetDuration(GetAnimationDuration(ACTIVATED_FADE_IN))
  240. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN)
  241. .At(base::TimeDelta())
  242. .SetDuration(GetAnimationDuration(ACTIVATED_TRANSFORM))
  243. .SetTransform(&painted_layer_, GetMaxSizeTargetTransform(),
  244. gfx::Tween::EASE_IN_OUT);
  245. }
  246. break;
  247. }
  248. case InkDropState::DEACTIVATED:
  249. AnimationBuilder()
  250. .SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION)
  251. .Once()
  252. .SetDuration(GetAnimationDuration(DEACTIVATED_FADE_OUT))
  253. .SetOpacity(&root_layer_, kHiddenOpacity, gfx::Tween::EASE_IN_OUT);
  254. break;
  255. }
  256. }
  257. void FloodFillInkDropRipple::SetStateToHidden() {
  258. painted_layer_.SetTransform(CalculateTransform(kMinRadius));
  259. root_layer_.SetOpacity(kHiddenOpacity);
  260. root_layer_.SetVisible(false);
  261. }
  262. void FloodFillInkDropRipple::AbortAllAnimations() {
  263. root_layer_.GetAnimator()->AbortAllAnimations();
  264. painted_layer_.GetAnimator()->AbortAllAnimations();
  265. }
  266. void FloodFillInkDropRipple::SetOpacity(float opacity) {
  267. root_layer_.SetOpacity(opacity);
  268. }
  269. gfx::Transform FloodFillInkDropRipple::CalculateTransform(
  270. float target_radius) const {
  271. const float target_scale = target_radius / circle_layer_delegate_.radius();
  272. gfx::Transform transform = gfx::Transform();
  273. transform.Translate(center_point_.x() - root_layer_.bounds().x(),
  274. center_point_.y() - root_layer_.bounds().y());
  275. transform.Scale(target_scale, target_scale);
  276. const gfx::Vector2dF drawn_center_offset =
  277. circle_layer_delegate_.GetCenteringOffset();
  278. transform.Translate(-drawn_center_offset.x(), -drawn_center_offset.y());
  279. // Add subpixel correction to the transform.
  280. transform.ConcatTransform(GetTransformSubpixelCorrection(
  281. transform, painted_layer_.device_scale_factor()));
  282. return transform;
  283. }
  284. gfx::Transform FloodFillInkDropRipple::GetMaxSizeTargetTransform() const {
  285. return CalculateTransform(MaxDistanceToCorners(center_point_));
  286. }
  287. float FloodFillInkDropRipple::MaxDistanceToCorners(
  288. const gfx::Point& point) const {
  289. const gfx::Rect bounds = root_layer_.bounds();
  290. const float distance_to_top_left = (bounds.origin() - point).Length();
  291. const float distance_to_top_right = (bounds.top_right() - point).Length();
  292. const float distance_to_bottom_left = (bounds.bottom_left() - point).Length();
  293. const float distance_to_bottom_right =
  294. (bounds.bottom_right() - point).Length();
  295. float largest_distance =
  296. std::max(distance_to_top_left, distance_to_top_right);
  297. largest_distance = std::max(largest_distance, distance_to_bottom_left);
  298. largest_distance = std::max(largest_distance, distance_to_bottom_right);
  299. return largest_distance;
  300. }
  301. // Returns the InkDropState sub animation duration for the given |state|.
  302. base::TimeDelta FloodFillInkDropRipple::GetAnimationDuration(int state) {
  303. if (!PlatformStyle::kUseRipples ||
  304. !gfx::Animation::ShouldRenderRichAnimation()) {
  305. return base::TimeDelta();
  306. }
  307. int state_override = state;
  308. // Override the requested state if needed.
  309. if (use_hide_transform_duration_for_hide_fade_out_ &&
  310. state == HIDDEN_FADE_OUT) {
  311. state_override = HIDDEN_TRANSFORM;
  312. }
  313. return base::Milliseconds(kAnimationDurationInMs[state_override] *
  314. duration_factor_);
  315. }
  316. void FloodFillInkDropRipple::OnLayerAnimationSequenceScheduled(
  317. ui::LayerAnimationSequence* sequence) {
  318. sequence->AddObserver(GetLayerAnimationObserver());
  319. }
  320. } // namespace views