square_ink_drop_ripple.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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/square_ink_drop_ripple.h"
  5. #include <algorithm>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/logging.h"
  9. #include "ui/compositor/compositor.h"
  10. #include "ui/compositor/layer.h"
  11. #include "ui/compositor/layer_animation_sequence.h"
  12. #include "ui/compositor/scoped_layer_animation_settings.h"
  13. #include "ui/gfx/animation/animation.h"
  14. #include "ui/gfx/geometry/point3_f.h"
  15. #include "ui/gfx/geometry/point_conversions.h"
  16. #include "ui/gfx/geometry/point_f.h"
  17. #include "ui/gfx/geometry/transform_util.h"
  18. #include "ui/gfx/geometry/vector3d_f.h"
  19. #include "ui/views/animation/animation_builder.h"
  20. #include "ui/views/animation/animation_sequence_block.h"
  21. #include "ui/views/animation/ink_drop_painted_layer_delegates.h"
  22. #include "ui/views/style/platform_style.h"
  23. #include "ui/views/view.h"
  24. namespace views {
  25. namespace {
  26. // The minimum scale factor to use when scaling rectangle layers. Smaller values
  27. // were causing visual anomalies.
  28. constexpr float kMinimumRectScale = 0.0001f;
  29. // The minimum scale factor to use when scaling circle layers. Smaller values
  30. // were causing visual anomalies.
  31. constexpr float kMinimumCircleScale = 0.001f;
  32. // All the sub animations that are used to animate each of the InkDropStates.
  33. // These are used to get time durations with
  34. // GetAnimationDuration(InkDropSubAnimations). Note that in general a sub
  35. // animation defines the duration for either a transformation animation or an
  36. // opacity animation but there are some exceptions where an entire InkDropState
  37. // animation consists of only 1 sub animation and it defines the duration for
  38. // both the transformation and opacity animations.
  39. enum InkDropSubAnimations {
  40. // HIDDEN sub animations.
  41. // The HIDDEN sub animation that is fading out to a hidden opacity.
  42. HIDDEN_FADE_OUT,
  43. // The HIDDEN sub animation that transforms the shape to a |small_size_|
  44. // circle.
  45. HIDDEN_TRANSFORM,
  46. // ACTION_PENDING sub animations.
  47. // The ACTION_PENDING sub animation that fades in to the visible opacity.
  48. ACTION_PENDING_FADE_IN,
  49. // The ACTION_PENDING sub animation that transforms the shape to a
  50. // |large_size_| circle.
  51. ACTION_PENDING_TRANSFORM,
  52. // ACTION_TRIGGERED sub animations.
  53. // The ACTION_TRIGGERED sub animation that is fading out to a hidden opacity.
  54. ACTION_TRIGGERED_FADE_OUT,
  55. // The ACTION_TRIGGERED sub animation that transforms the shape to a
  56. // |large_size_|
  57. // circle.
  58. ACTION_TRIGGERED_TRANSFORM,
  59. // ALTERNATE_ACTION_PENDING sub animations.
  60. // The ALTERNATE_ACTION_PENDING animation has only one sub animation which
  61. // animates
  62. // to a |small_size_| rounded rectangle at visible opacity.
  63. ALTERNATE_ACTION_PENDING,
  64. // ALTERNATE_ACTION_TRIGGERED sub animations.
  65. // The ALTERNATE_ACTION_TRIGGERED sub animation that is fading out to a hidden
  66. // opacity.
  67. ALTERNATE_ACTION_TRIGGERED_FADE_OUT,
  68. // The ALTERNATE_ACTION_TRIGGERED sub animation that transforms the shape to a
  69. // |large_size_|
  70. // rounded rectangle.
  71. ALTERNATE_ACTION_TRIGGERED_TRANSFORM,
  72. // ACTIVATED sub animations.
  73. // The ACTIVATED sub animation that transforms the shape to a |large_size_|
  74. // circle. This is used when the ink drop is in a HIDDEN state prior to
  75. // animating to the ACTIVATED state.
  76. ACTIVATED_CIRCLE_TRANSFORM,
  77. // The ACTIVATED sub animation that transforms the shape to a |small_size_|
  78. // rounded rectangle.
  79. ACTIVATED_RECT_TRANSFORM,
  80. // DEACTIVATED sub animations.
  81. // The DEACTIVATED sub animation that is fading out to a hidden opacity.
  82. DEACTIVATED_FADE_OUT,
  83. // The DEACTIVATED sub animation that transforms the shape to a |large_size_|
  84. // rounded rectangle.
  85. DEACTIVATED_TRANSFORM,
  86. };
  87. // The scale factor used to burst the ACTION_TRIGGERED bubble as it fades out.
  88. constexpr float kQuickActionBurstScale = 1.3f;
  89. // Returns the InkDropState sub animation duration for the given |state|.
  90. base::TimeDelta GetAnimationDuration(InkDropSubAnimations state) {
  91. if (!PlatformStyle::kUseRipples ||
  92. !gfx::Animation::ShouldRenderRichAnimation()) {
  93. return base::TimeDelta();
  94. }
  95. // Duration constants for InkDropStateSubAnimations. See the
  96. // InkDropStateSubAnimations enum documentation for more info.
  97. constexpr base::TimeDelta kAnimationDuration[] = {
  98. base::Milliseconds(150), // HIDDEN_FADE_OUT
  99. base::Milliseconds(200), // HIDDEN_TRANSFORM
  100. base::TimeDelta(), // ACTION_PENDING_FADE_IN
  101. base::Milliseconds(160), // ACTION_PENDING_TRANSFORM
  102. base::Milliseconds(150), // ACTION_TRIGGERED_FADE_OUT
  103. base::Milliseconds(160), // ACTION_TRIGGERED_TRANSFORM
  104. base::Milliseconds(200), // ALTERNATE_ACTION_PENDING
  105. base::Milliseconds(150), // ALTERNAT..._TRIGGERED_FADE_OUT
  106. base::Milliseconds(200), // ALTERNA..._TRIGGERED_TRANSFORM
  107. base::Milliseconds(200), // ACTIVATED_CIRCLE_TRANSFORM
  108. base::Milliseconds(160), // ACTIVATED_RECT_TRANSFORM
  109. base::Milliseconds(150), // DEACTIVATED_FADE_OUT
  110. base::Milliseconds(200), // DEACTIVATED_TRANSFORM
  111. };
  112. return kAnimationDuration[state];
  113. }
  114. } // namespace
  115. SquareInkDropRipple::SquareInkDropRipple(const gfx::Size& large_size,
  116. int large_corner_radius,
  117. const gfx::Size& small_size,
  118. int small_corner_radius,
  119. const gfx::Point& center_point,
  120. SkColor color,
  121. float visible_opacity)
  122. : activated_shape_(ActivatedShape::kRoundedRect),
  123. visible_opacity_(visible_opacity),
  124. large_size_(large_size),
  125. large_corner_radius_(large_corner_radius),
  126. small_size_(small_size),
  127. small_corner_radius_(small_corner_radius),
  128. center_point_(center_point),
  129. circle_layer_delegate_(new CircleLayerDelegate(
  130. color,
  131. std::min(large_size_.width(), large_size_.height()) / 2)),
  132. rect_layer_delegate_(
  133. new RectangleLayerDelegate(color, gfx::SizeF(large_size_))),
  134. root_layer_(ui::LAYER_NOT_DRAWN) {
  135. root_layer_.SetName("SquareInkDropRipple:ROOT_LAYER");
  136. for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i)
  137. AddPaintLayer(static_cast<PaintedShape>(i));
  138. root_layer_.SetMasksToBounds(false);
  139. root_layer_.SetBounds(gfx::Rect(large_size_));
  140. root_callback_subscription_ =
  141. root_layer_.GetAnimator()->AddSequenceScheduledCallback(
  142. base::BindRepeating(
  143. &SquareInkDropRipple::OnLayerAnimationSequenceScheduled,
  144. base::Unretained(this)));
  145. SetStateToHidden();
  146. }
  147. SquareInkDropRipple::~SquareInkDropRipple() {
  148. // Explicitly aborting all the animations ensures all callbacks are invoked
  149. // while this instance still exists.
  150. AbortAllAnimations();
  151. }
  152. void SquareInkDropRipple::SnapToActivated() {
  153. InkDropRipple::SnapToActivated();
  154. SetOpacity(visible_opacity_);
  155. InkDropTransforms transforms;
  156. GetActivatedTargetTransforms(&transforms);
  157. SetTransforms(transforms);
  158. }
  159. ui::Layer* SquareInkDropRipple::GetRootLayer() {
  160. return &root_layer_;
  161. }
  162. float SquareInkDropRipple::GetCurrentOpacity() const {
  163. return root_layer_.opacity();
  164. }
  165. std::string SquareInkDropRipple::ToLayerName(PaintedShape painted_shape) {
  166. switch (painted_shape) {
  167. case TOP_LEFT_CIRCLE:
  168. return "TOP_LEFT_CIRCLE";
  169. case TOP_RIGHT_CIRCLE:
  170. return "TOP_RIGHT_CIRCLE";
  171. case BOTTOM_RIGHT_CIRCLE:
  172. return "BOTTOM_RIGHT_CIRCLE";
  173. case BOTTOM_LEFT_CIRCLE:
  174. return "BOTTOM_LEFT_CIRCLE";
  175. case HORIZONTAL_RECT:
  176. return "HORIZONTAL_RECT";
  177. case VERTICAL_RECT:
  178. return "VERTICAL_RECT";
  179. case PAINTED_SHAPE_COUNT:
  180. NOTREACHED() << "The PAINTED_SHAPE_COUNT value should never be used.";
  181. return "PAINTED_SHAPE_COUNT";
  182. }
  183. return "UNKNOWN";
  184. }
  185. void SquareInkDropRipple::AnimateStateChange(InkDropState old_ink_drop_state,
  186. InkDropState new_ink_drop_state) {
  187. InkDropTransforms transforms;
  188. AnimationBuilder builder;
  189. builder
  190. .SetPreemptionStrategy(
  191. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  192. .Once();
  193. auto animate_to_transforms =
  194. [this](AnimationSequenceBlock& sequence,
  195. const InkDropTransforms& transforms,
  196. gfx::Tween::Type tween) -> AnimationSequenceBlock& {
  197. for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i)
  198. sequence.SetTransform(painted_layers_[i].get(), transforms[i], tween);
  199. return sequence;
  200. };
  201. auto pending_animation =
  202. [this, &animate_to_transforms](
  203. AnimationSequenceBlock& sequence,
  204. const InkDropTransforms& transforms) -> AnimationSequenceBlock& {
  205. auto& new_sequence =
  206. sequence.SetDuration(GetAnimationDuration(ACTION_PENDING_FADE_IN))
  207. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN)
  208. .Then()
  209. .SetDuration(GetAnimationDuration(ACTION_PENDING_TRANSFORM))
  210. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN);
  211. animate_to_transforms(new_sequence, transforms, gfx::Tween::EASE_IN_OUT);
  212. return new_sequence;
  213. };
  214. switch (new_ink_drop_state) {
  215. case InkDropState::HIDDEN:
  216. if (!IsVisible()) {
  217. SetStateToHidden();
  218. break;
  219. } else {
  220. CalculateCircleTransforms(small_size_, &transforms);
  221. auto& sequence =
  222. builder.GetCurrentSequence()
  223. .SetDuration(GetAnimationDuration(HIDDEN_FADE_OUT))
  224. .SetOpacity(&root_layer_, kHiddenOpacity,
  225. gfx::Tween::EASE_IN_OUT)
  226. .At(base::TimeDelta())
  227. .SetDuration(GetAnimationDuration(HIDDEN_TRANSFORM));
  228. animate_to_transforms(sequence, transforms, gfx::Tween::EASE_IN_OUT);
  229. }
  230. break;
  231. case InkDropState::ACTION_PENDING: {
  232. if (old_ink_drop_state == new_ink_drop_state)
  233. return;
  234. DLOG_IF(WARNING, InkDropState::HIDDEN != old_ink_drop_state)
  235. << "Invalid InkDropState transition. old_ink_drop_state="
  236. << ToString(old_ink_drop_state)
  237. << " new_ink_drop_state=" << ToString(new_ink_drop_state);
  238. CalculateCircleTransforms(large_size_, &transforms);
  239. pending_animation(builder.GetCurrentSequence(), transforms);
  240. break;
  241. }
  242. case InkDropState::ACTION_TRIGGERED: {
  243. DLOG_IF(WARNING, old_ink_drop_state != InkDropState::HIDDEN &&
  244. old_ink_drop_state != InkDropState::ACTION_PENDING)
  245. << "Invalid InkDropState transition. old_ink_drop_state="
  246. << ToString(old_ink_drop_state)
  247. << " new_ink_drop_state=" << ToString(new_ink_drop_state);
  248. gfx::Size s = ScaleToRoundedSize(large_size_, kQuickActionBurstScale);
  249. CalculateCircleTransforms(s, &transforms);
  250. if (old_ink_drop_state == InkDropState::HIDDEN) {
  251. pending_animation(builder.GetCurrentSequence(), transforms).Then();
  252. } else {
  253. builder.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION);
  254. }
  255. builder.GetCurrentSequence()
  256. .SetDuration(GetAnimationDuration(ACTION_TRIGGERED_FADE_OUT))
  257. .SetOpacity(&root_layer_, kHiddenOpacity, gfx::Tween::EASE_IN_OUT)
  258. .Offset(base::TimeDelta())
  259. .SetDuration(GetAnimationDuration(ACTION_TRIGGERED_TRANSFORM));
  260. animate_to_transforms(builder.GetCurrentSequence(), transforms,
  261. gfx::Tween::EASE_IN_OUT);
  262. break;
  263. }
  264. case InkDropState::ALTERNATE_ACTION_PENDING: {
  265. DLOG_IF(WARNING, InkDropState::ACTION_PENDING != old_ink_drop_state)
  266. << "Invalid InkDropState transition. old_ink_drop_state="
  267. << ToString(old_ink_drop_state)
  268. << " new_ink_drop_state=" << ToString(new_ink_drop_state);
  269. CalculateRectTransforms(small_size_, small_corner_radius_, &transforms);
  270. animate_to_transforms(
  271. builder.GetCurrentSequence()
  272. .SetDuration(GetAnimationDuration(ALTERNATE_ACTION_PENDING))
  273. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN),
  274. transforms, gfx::Tween::EASE_IN_OUT);
  275. break;
  276. }
  277. case InkDropState::ALTERNATE_ACTION_TRIGGERED: {
  278. DLOG_IF(WARNING,
  279. InkDropState::ALTERNATE_ACTION_PENDING != old_ink_drop_state)
  280. << "Invalid InkDropState transition. old_ink_drop_state="
  281. << ToString(old_ink_drop_state)
  282. << " new_ink_drop_state=" << ToString(new_ink_drop_state);
  283. base::TimeDelta visible_duration =
  284. GetAnimationDuration(ALTERNATE_ACTION_TRIGGERED_TRANSFORM) -
  285. GetAnimationDuration(ALTERNATE_ACTION_TRIGGERED_FADE_OUT);
  286. CalculateRectTransforms(large_size_, large_corner_radius_, &transforms);
  287. builder.GetCurrentSequence()
  288. .SetDuration(visible_duration)
  289. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN_OUT)
  290. .Then()
  291. .SetDuration(
  292. GetAnimationDuration(ALTERNATE_ACTION_TRIGGERED_FADE_OUT))
  293. .SetOpacity(&root_layer_, kHiddenOpacity, gfx::Tween::EASE_IN_OUT)
  294. .At(base::TimeDelta())
  295. .SetDuration(
  296. GetAnimationDuration(ALTERNATE_ACTION_TRIGGERED_TRANSFORM));
  297. animate_to_transforms(builder.GetCurrentSequence(), transforms,
  298. gfx::Tween::EASE_IN_OUT);
  299. break;
  300. }
  301. case InkDropState::ACTIVATED: {
  302. // Animate the opacity so that it cancels any opacity animations already
  303. // in progress.
  304. builder.GetCurrentSequence()
  305. .SetDuration(base::TimeDelta())
  306. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN_OUT)
  307. .Then();
  308. if (old_ink_drop_state == InkDropState::HIDDEN) {
  309. CalculateCircleTransforms(large_size_, &transforms);
  310. animate_to_transforms(
  311. builder.GetCurrentSequence().SetDuration(
  312. GetAnimationDuration(ACTIVATED_CIRCLE_TRANSFORM)),
  313. transforms, gfx::Tween::EASE_IN_OUT)
  314. .Then();
  315. } else if (old_ink_drop_state == InkDropState::ACTION_PENDING) {
  316. builder.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION);
  317. }
  318. GetActivatedTargetTransforms(&transforms);
  319. animate_to_transforms(builder.GetCurrentSequence().SetDuration(
  320. GetAnimationDuration(ACTIVATED_RECT_TRANSFORM)),
  321. transforms, gfx::Tween::EASE_IN_OUT);
  322. break;
  323. }
  324. case InkDropState::DEACTIVATED: {
  325. base::TimeDelta visible_duration =
  326. GetAnimationDuration(DEACTIVATED_TRANSFORM) -
  327. GetAnimationDuration(DEACTIVATED_FADE_OUT);
  328. GetDeactivatedTargetTransforms(&transforms);
  329. builder.GetCurrentSequence()
  330. .SetDuration(visible_duration)
  331. .SetOpacity(&root_layer_, visible_opacity_, gfx::Tween::EASE_IN_OUT)
  332. .Then()
  333. .SetDuration(GetAnimationDuration(DEACTIVATED_FADE_OUT))
  334. .SetOpacity(&root_layer_, kHiddenOpacity, gfx::Tween::EASE_IN_OUT)
  335. .At(base::TimeDelta());
  336. animate_to_transforms(builder.GetCurrentSequence().SetDuration(
  337. GetAnimationDuration(DEACTIVATED_TRANSFORM)),
  338. transforms, gfx::Tween::EASE_IN_OUT);
  339. break;
  340. }
  341. }
  342. }
  343. void SquareInkDropRipple::SetStateToHidden() {
  344. InkDropTransforms transforms;
  345. // Use non-zero size to avoid visual anomalies.
  346. CalculateCircleTransforms(gfx::Size(1, 1), &transforms);
  347. SetTransforms(transforms);
  348. root_layer_.SetOpacity(InkDropRipple::kHiddenOpacity);
  349. root_layer_.SetVisible(false);
  350. }
  351. void SquareInkDropRipple::AbortAllAnimations() {
  352. root_layer_.GetAnimator()->AbortAllAnimations();
  353. for (auto& painted_layer : painted_layers_)
  354. painted_layer->GetAnimator()->AbortAllAnimations();
  355. }
  356. void SquareInkDropRipple::SetTransforms(const InkDropTransforms transforms) {
  357. for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i)
  358. painted_layers_[i]->SetTransform(transforms[i]);
  359. }
  360. void SquareInkDropRipple::SetOpacity(float opacity) {
  361. root_layer_.SetOpacity(opacity);
  362. }
  363. void SquareInkDropRipple::CalculateCircleTransforms(
  364. const gfx::Size& size,
  365. InkDropTransforms* transforms_out) const {
  366. CalculateRectTransforms(size, std::min(size.width(), size.height()) / 2.0f,
  367. transforms_out);
  368. }
  369. void SquareInkDropRipple::CalculateRectTransforms(
  370. const gfx::Size& desired_size,
  371. float corner_radius,
  372. InkDropTransforms* transforms_out) const {
  373. DCHECK_GE(desired_size.width() / 2.0f, corner_radius)
  374. << "The circle's diameter should not be greater than the total width.";
  375. DCHECK_GE(desired_size.height() / 2.0f, corner_radius)
  376. << "The circle's diameter should not be greater than the total height.";
  377. gfx::SizeF size(desired_size);
  378. // This function can be called before the layer's been added to a view,
  379. // either at construction time or in tests.
  380. if (root_layer_.GetCompositor()) {
  381. // Modify |desired_size| so that the ripple aligns to pixel bounds.
  382. const float dsf = root_layer_.GetCompositor()->device_scale_factor();
  383. gfx::RectF ripple_bounds((gfx::PointF(center_point_)), gfx::SizeF());
  384. ripple_bounds.Inset(-gfx::InsetsF::VH(desired_size.height() / 2.0f,
  385. desired_size.width() / 2.0f));
  386. ripple_bounds.Scale(dsf);
  387. ripple_bounds = gfx::RectF(gfx::ToEnclosingRect(ripple_bounds));
  388. ripple_bounds.Scale(1.0f / dsf);
  389. size = ripple_bounds.size();
  390. }
  391. // The shapes are drawn such that their center points are not at the origin.
  392. // Thus we use the CalculateCircleTransform() and CalculateRectTransform()
  393. // methods to calculate the complex Transforms.
  394. const float circle_scale = std::max(
  395. kMinimumCircleScale,
  396. corner_radius / static_cast<float>(circle_layer_delegate_->radius()));
  397. const float circle_target_x_offset = size.width() / 2.0f - corner_radius;
  398. const float circle_target_y_offset = size.height() / 2.0f - corner_radius;
  399. (*transforms_out)[TOP_LEFT_CIRCLE] = CalculateCircleTransform(
  400. circle_scale, -circle_target_x_offset, -circle_target_y_offset);
  401. (*transforms_out)[TOP_RIGHT_CIRCLE] = CalculateCircleTransform(
  402. circle_scale, circle_target_x_offset, -circle_target_y_offset);
  403. (*transforms_out)[BOTTOM_RIGHT_CIRCLE] = CalculateCircleTransform(
  404. circle_scale, circle_target_x_offset, circle_target_y_offset);
  405. (*transforms_out)[BOTTOM_LEFT_CIRCLE] = CalculateCircleTransform(
  406. circle_scale, -circle_target_x_offset, circle_target_y_offset);
  407. const float rect_delegate_width = rect_layer_delegate_->size().width();
  408. const float rect_delegate_height = rect_layer_delegate_->size().height();
  409. (*transforms_out)[HORIZONTAL_RECT] = CalculateRectTransform(
  410. std::max(kMinimumRectScale, size.width() / rect_delegate_width),
  411. std::max(kMinimumRectScale,
  412. (size.height() - 2.0f * corner_radius) / rect_delegate_height));
  413. (*transforms_out)[VERTICAL_RECT] = CalculateRectTransform(
  414. std::max(kMinimumRectScale,
  415. (size.width() - 2.0f * corner_radius) / rect_delegate_width),
  416. std::max(kMinimumRectScale, size.height() / rect_delegate_height));
  417. }
  418. gfx::Transform SquareInkDropRipple::CalculateCircleTransform(
  419. float scale,
  420. float target_center_x,
  421. float target_center_y) const {
  422. gfx::Transform transform;
  423. // Offset for the center point of the ripple.
  424. transform.Translate(center_point_.x(), center_point_.y());
  425. // Move circle to target.
  426. transform.Translate(target_center_x, target_center_y);
  427. transform.Scale(scale, scale);
  428. // Align center point of the painted circle.
  429. const gfx::Vector2dF circle_center_offset =
  430. circle_layer_delegate_->GetCenteringOffset();
  431. transform.Translate(-circle_center_offset.x(), -circle_center_offset.y());
  432. return transform;
  433. }
  434. gfx::Transform SquareInkDropRipple::CalculateRectTransform(
  435. float x_scale,
  436. float y_scale) const {
  437. gfx::Transform transform;
  438. transform.Translate(center_point_.x(), center_point_.y());
  439. transform.Scale(x_scale, y_scale);
  440. const gfx::Vector2dF rect_center_offset =
  441. rect_layer_delegate_->GetCenteringOffset();
  442. transform.Translate(-rect_center_offset.x(), -rect_center_offset.y());
  443. return transform;
  444. }
  445. void SquareInkDropRipple::GetCurrentTransforms(
  446. InkDropTransforms* transforms_out) const {
  447. for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i)
  448. (*transforms_out)[i] = painted_layers_[i]->transform();
  449. }
  450. void SquareInkDropRipple::GetActivatedTargetTransforms(
  451. InkDropTransforms* transforms_out) const {
  452. switch (activated_shape_) {
  453. case ActivatedShape::kCircle:
  454. CalculateCircleTransforms(small_size_, transforms_out);
  455. break;
  456. case ActivatedShape::kRoundedRect:
  457. CalculateRectTransforms(small_size_, small_corner_radius_,
  458. transforms_out);
  459. break;
  460. }
  461. }
  462. void SquareInkDropRipple::GetDeactivatedTargetTransforms(
  463. InkDropTransforms* transforms_out) const {
  464. switch (activated_shape_) {
  465. case ActivatedShape::kCircle:
  466. CalculateCircleTransforms(large_size_, transforms_out);
  467. break;
  468. case ActivatedShape::kRoundedRect:
  469. CalculateRectTransforms(large_size_, small_corner_radius_,
  470. transforms_out);
  471. break;
  472. }
  473. }
  474. void SquareInkDropRipple::AddPaintLayer(PaintedShape painted_shape) {
  475. ui::LayerDelegate* delegate = nullptr;
  476. switch (painted_shape) {
  477. case TOP_LEFT_CIRCLE:
  478. case TOP_RIGHT_CIRCLE:
  479. case BOTTOM_RIGHT_CIRCLE:
  480. case BOTTOM_LEFT_CIRCLE:
  481. delegate = circle_layer_delegate_.get();
  482. break;
  483. case HORIZONTAL_RECT:
  484. case VERTICAL_RECT:
  485. delegate = rect_layer_delegate_.get();
  486. break;
  487. case PAINTED_SHAPE_COUNT:
  488. NOTREACHED() << "PAINTED_SHAPE_COUNT is not an actual shape type.";
  489. break;
  490. }
  491. ui::Layer* layer = new ui::Layer();
  492. root_layer_.Add(layer);
  493. layer->SetBounds(gfx::Rect(large_size_));
  494. layer->SetFillsBoundsOpaquely(false);
  495. layer->set_delegate(delegate);
  496. layer->SetVisible(true);
  497. layer->SetOpacity(1.0);
  498. layer->SetMasksToBounds(false);
  499. layer->SetName("PAINTED_SHAPE_COUNT:" + ToLayerName(painted_shape));
  500. callback_subscriptions_[painted_shape] =
  501. layer->GetAnimator()->AddSequenceScheduledCallback(base::BindRepeating(
  502. &SquareInkDropRipple::OnLayerAnimationSequenceScheduled,
  503. base::Unretained(this)));
  504. painted_layers_[painted_shape].reset(layer);
  505. }
  506. void SquareInkDropRipple::OnLayerAnimationSequenceScheduled(
  507. ui::LayerAnimationSequence* sequence) {
  508. sequence->AddObserver(GetLayerAnimationObserver());
  509. }
  510. } // namespace views