ink_drop_host_view_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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/ink_drop_host_view.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/memory/ptr_util.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "build/build_config.h"
  10. #include "testing/gtest/include/gtest/gtest.h"
  11. #include "ui/compositor/layer.h"
  12. #include "ui/events/event.h"
  13. #include "ui/events/event_constants.h"
  14. #include "ui/events/event_handler.h"
  15. #include "ui/events/event_utils.h"
  16. #include "ui/events/types/event_type.h"
  17. #include "ui/gfx/animation/animation.h"
  18. #include "ui/gfx/animation/animation_test_api.h"
  19. #include "ui/gfx/color_palette.h"
  20. #include "ui/gfx/geometry/point.h"
  21. #include "ui/gfx/geometry/size.h"
  22. #include "ui/views/animation/ink_drop.h"
  23. #include "ui/views/animation/ink_drop_impl.h"
  24. #include "ui/views/animation/test/ink_drop_host_view_test_api.h"
  25. #include "ui/views/animation/test/ink_drop_impl_test_api.h"
  26. #include "ui/views/animation/test/test_ink_drop.h"
  27. #include "ui/views/controls/highlight_path_generator.h"
  28. namespace views {
  29. namespace test {
  30. using InkDropMode = InkDropHostTestApi::InkDropMode;
  31. class TestViewWithInkDrop : public View {
  32. public:
  33. TestViewWithInkDrop() {
  34. InkDrop::Install(this, std::make_unique<InkDropHost>(this));
  35. InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating(
  36. [](TestViewWithInkDrop* host) -> std::unique_ptr<InkDrop> {
  37. auto ink_drop = std::make_unique<TestInkDrop>();
  38. host->last_created_inkdrop_ = ink_drop.get();
  39. return ink_drop;
  40. },
  41. this));
  42. InkDrop::Get(this)->SetBaseColor(gfx::kPlaceholderColor);
  43. }
  44. TestViewWithInkDrop(const TestViewWithInkDrop&) = delete;
  45. TestViewWithInkDrop& operator=(const TestViewWithInkDrop&) = delete;
  46. // Expose EventTarget::target_handler() for testing.
  47. ui::EventHandler* GetTargetHandler() { return target_handler(); }
  48. TestInkDrop* last_created_inkdrop() const { return last_created_inkdrop_; }
  49. private:
  50. raw_ptr<TestInkDrop> last_created_inkdrop_ = nullptr;
  51. };
  52. class InkDropHostViewTest : public testing::Test {
  53. public:
  54. InkDropHostViewTest();
  55. InkDropHostViewTest(const InkDropHostViewTest&) = delete;
  56. InkDropHostViewTest& operator=(const InkDropHostViewTest&) = delete;
  57. ~InkDropHostViewTest() override;
  58. protected:
  59. // Test target.
  60. TestViewWithInkDrop host_view_;
  61. // Provides internal access to |host_view_| test target.
  62. InkDropHostTestApi test_api_;
  63. std::unique_ptr<base::AutoReset<gfx::Animation::RichAnimationRenderMode>>
  64. animation_mode_reset_;
  65. void MouseEventTriggersInkDropHelper(InkDropMode ink_drop_mode);
  66. };
  67. InkDropHostViewTest::InkDropHostViewTest()
  68. : test_api_(InkDrop::Get(&host_view_)),
  69. animation_mode_reset_(gfx::AnimationTestApi::SetRichAnimationRenderMode(
  70. gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED)) {}
  71. InkDropHostViewTest::~InkDropHostViewTest() = default;
  72. void InkDropHostViewTest::MouseEventTriggersInkDropHelper(
  73. InkDropMode ink_drop_mode) {
  74. test_api_.SetInkDropMode(ink_drop_mode);
  75. host_view_.SetEnabled(true);
  76. // Call InkDrop::Get(this)->GetInkDrop() to make sure the test
  77. // CreateInkDrop() is created.
  78. test_api_.GetInkDrop();
  79. if (ink_drop_mode != views::InkDropHost::InkDropMode::OFF)
  80. EXPECT_FALSE(host_view_.last_created_inkdrop()->is_hovered());
  81. else
  82. EXPECT_EQ(host_view_.last_created_inkdrop(), nullptr);
  83. ui::MouseEvent mouse_event(ui::ET_MOUSE_ENTERED, gfx::Point(0, 0),
  84. gfx::Point(0, 0), ui::EventTimeForNow(),
  85. ui::EF_IS_SYNTHESIZED, 0);
  86. host_view_.GetTargetHandler()->OnEvent(&mouse_event);
  87. if (ink_drop_mode != views::InkDropHost::InkDropMode::OFF)
  88. EXPECT_TRUE(host_view_.last_created_inkdrop()->is_hovered());
  89. else
  90. EXPECT_EQ(host_view_.last_created_inkdrop(), nullptr);
  91. }
  92. // Verifies the return value of GetInkDropCenterBasedOnLastEvent() for a null
  93. // Event.
  94. TEST_F(InkDropHostViewTest, GetInkDropCenterBasedOnLastEventForNullEvent) {
  95. host_view_.SetSize(gfx::Size(20, 20));
  96. test_api_.AnimateToState(InkDropState::ACTION_PENDING, nullptr);
  97. EXPECT_EQ(gfx::Point(10, 10),
  98. InkDrop::Get(&host_view_)->GetInkDropCenterBasedOnLastEvent());
  99. }
  100. // Verifies the return value of GetInkDropCenterBasedOnLastEvent() for a located
  101. // Event.
  102. TEST_F(InkDropHostViewTest, GetInkDropCenterBasedOnLastEventForLocatedEvent) {
  103. host_view_.SetSize(gfx::Size(20, 20));
  104. ui::MouseEvent located_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 6),
  105. gfx::Point(5, 6), ui::EventTimeForNow(),
  106. ui::EF_LEFT_MOUSE_BUTTON, 0);
  107. test_api_.AnimateToState(InkDropState::ACTION_PENDING, &located_event);
  108. EXPECT_EQ(gfx::Point(5, 6),
  109. InkDrop::Get(&host_view_)->GetInkDropCenterBasedOnLastEvent());
  110. }
  111. TEST_F(InkDropHostViewTest, HasInkDrop) {
  112. EXPECT_FALSE(test_api_.HasInkDrop());
  113. test_api_.GetInkDrop();
  114. EXPECT_TRUE(test_api_.HasInkDrop());
  115. test_api_.SetInkDropMode(views::InkDropHost::InkDropMode::OFF);
  116. EXPECT_FALSE(test_api_.HasInkDrop());
  117. }
  118. // Verifies that mouse events trigger ink drops when ink drop mode is ON.
  119. TEST_F(InkDropHostViewTest, MouseEventsTriggerInkDropsWhenInkDropIsOn) {
  120. MouseEventTriggersInkDropHelper(views::InkDropHost::InkDropMode::ON);
  121. }
  122. // Verifies that mouse events trigger ink drops when ink drop mode is
  123. // ON_NO_GESTURE_HANDLER.
  124. TEST_F(InkDropHostViewTest,
  125. MouseEventsTriggerInkDropsWhenInkDropIsOnNoGestureHandler) {
  126. MouseEventTriggersInkDropHelper(
  127. views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER);
  128. }
  129. // Verifies that mouse events do not trigger ink drops when ink drop mode is
  130. // OFF.
  131. TEST_F(InkDropHostViewTest, MouseEventsDontTriggerInkDropsWhenInkDropIsOff) {
  132. MouseEventTriggersInkDropHelper(views::InkDropHost::InkDropMode::OFF);
  133. }
  134. // Verifies that ink drops are not shown when the host is disabled.
  135. TEST_F(InkDropHostViewTest,
  136. GestureEventsDontTriggerInkDropsWhenHostIsDisabled) {
  137. test_api_.SetInkDropMode(views::InkDropHost::InkDropMode::ON);
  138. host_view_.SetEnabled(false);
  139. ui::GestureEvent gesture_event(
  140. 0.f, 0.f, 0, ui::EventTimeForNow(),
  141. ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
  142. host_view_.GetTargetHandler()->OnEvent(&gesture_event);
  143. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  144. InkDropState::HIDDEN);
  145. }
  146. // Verifies that ink drops are not triggered by gesture events when ink drop
  147. // mode is ON_NO_GESTURE_EVENT or OFF.
  148. TEST_F(InkDropHostViewTest,
  149. GestureEventsDontTriggerInkDropsWhenInkDropModeIsNotOn) {
  150. for (auto ink_drop_mode :
  151. {views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER,
  152. views::InkDropHost::InkDropMode::OFF}) {
  153. test_api_.SetInkDropMode(ink_drop_mode);
  154. ui::GestureEvent gesture_event(
  155. 0.f, 0.f, 0, ui::EventTimeForNow(),
  156. ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
  157. host_view_.GetTargetHandler()->OnEvent(&gesture_event);
  158. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  159. InkDropState::HIDDEN);
  160. }
  161. }
  162. #if BUILDFLAG(IS_WIN)
  163. TEST_F(InkDropHostViewTest, NoInkDropOnTouchOrGestureEvents) {
  164. host_view_.SetSize(gfx::Size(20, 20));
  165. test_api_.SetInkDropMode(
  166. views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER);
  167. // Ensure the target ink drop is in the expected state.
  168. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  169. InkDropState::HIDDEN);
  170. ui::TouchEvent touch_event(
  171. ui::ET_TOUCH_PRESSED, gfx::Point(5, 6), ui::EventTimeForNow(),
  172. ui::PointerDetails(ui::EventPointerType::kTouch, 1));
  173. test_api_.AnimateToState(InkDropState::ACTION_PENDING, &touch_event);
  174. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  175. InkDropState::HIDDEN);
  176. test_api_.AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING,
  177. &touch_event);
  178. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  179. InkDropState::HIDDEN);
  180. ui::GestureEvent gesture_event(5.0f, 6.0f, 0, ui::EventTimeForNow(),
  181. ui::GestureEventDetails(ui::ET_GESTURE_TAP));
  182. test_api_.AnimateToState(InkDropState::ACTION_PENDING, &gesture_event);
  183. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  184. InkDropState::HIDDEN);
  185. test_api_.AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING,
  186. &gesture_event);
  187. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  188. InkDropState::HIDDEN);
  189. }
  190. TEST_F(InkDropHostViewTest, DismissInkDropOnTouchOrGestureEvents) {
  191. // TODO(bruthig): Re-enable! For some reason these tests fail on some win
  192. // trunk builds. See crbug.com/731811.
  193. if (!gfx::Animation::ShouldRenderRichAnimation())
  194. return;
  195. host_view_.SetSize(gfx::Size(20, 20));
  196. test_api_.SetInkDropMode(
  197. views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER);
  198. // Ensure the target ink drop is in the expected state.
  199. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  200. InkDropState::HIDDEN);
  201. ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 6),
  202. gfx::Point(5, 6), ui::EventTimeForNow(),
  203. ui::EF_LEFT_MOUSE_BUTTON, 0);
  204. test_api_.AnimateToState(InkDropState::ACTION_PENDING, &mouse_event);
  205. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  206. InkDropState::ACTION_PENDING);
  207. ui::TouchEvent touch_event(
  208. ui::ET_TOUCH_PRESSED, gfx::Point(5, 6), ui::EventTimeForNow(),
  209. ui::PointerDetails(ui::EventPointerType::kTouch, 1));
  210. test_api_.AnimateToState(InkDropState::ACTION_TRIGGERED, &touch_event);
  211. EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
  212. InkDropState::ACTION_TRIGGERED);
  213. }
  214. #endif
  215. // Verifies that calling OnInkDropHighlightedChanged() triggers a property
  216. // changed notification for the highlighted property.
  217. TEST_F(InkDropHostViewTest, HighlightedChangedFired) {
  218. bool callback_called = false;
  219. auto subscription =
  220. InkDrop::Get(&host_view_)
  221. ->AddHighlightedChangedCallback(base::BindRepeating(
  222. [](bool* called) { *called = true; }, &callback_called));
  223. InkDrop::Get(&host_view_)->OnInkDropHighlightedChanged();
  224. EXPECT_TRUE(callback_called);
  225. }
  226. // A very basic View that hosts an InkDrop.
  227. class BasicTestViewWithInkDrop : public View {
  228. public:
  229. BasicTestViewWithInkDrop() {
  230. InkDrop::Install(this, std::make_unique<InkDropHost>(this));
  231. // Call SetBaseColor to avoid hitting a NOTREACHED() for fetching an
  232. // undefined color.
  233. InkDrop::Get(this)->SetBaseColor(gfx::kPlaceholderColor);
  234. }
  235. BasicTestViewWithInkDrop(const BasicTestViewWithInkDrop&) = delete;
  236. BasicTestViewWithInkDrop& operator=(const BasicTestViewWithInkDrop&) = delete;
  237. ~BasicTestViewWithInkDrop() override = default;
  238. };
  239. // Tests the existence of layer clipping or layer masking when certain path
  240. // generators are applied on an InkDropHostView.
  241. class InkDropHostViewClippingTest : public testing::Test {
  242. public:
  243. InkDropHostViewClippingTest()
  244. : host_view_test_api_(InkDrop::Get(&host_view_)) {
  245. // Set up an InkDropHostView. Clipping is based on the size of the view, so
  246. // make sure the size is non empty.
  247. host_view_test_api_.SetInkDropMode(views::InkDropHost::InkDropMode::ON);
  248. host_view_.SetSize(gfx::Size(20, 20));
  249. // The root layer of the ink drop is created the first time GetInkDrop is
  250. // called and then kept alive until the host view is destroyed.
  251. ink_drop_ =
  252. static_cast<InkDropImpl*>(InkDrop::Get(&host_view_)->GetInkDrop());
  253. ink_drop_test_api_ = std::make_unique<test::InkDropImplTestApi>(ink_drop_);
  254. }
  255. InkDropHostViewClippingTest(const InkDropHostViewClippingTest&) = delete;
  256. InkDropHostViewClippingTest& operator=(const InkDropHostViewClippingTest&) =
  257. delete;
  258. ~InkDropHostViewClippingTest() override = default;
  259. ui::Layer* GetRootLayer() { return ink_drop_test_api_->GetRootLayer(); }
  260. protected:
  261. // Test target.
  262. BasicTestViewWithInkDrop host_view_;
  263. // Provides internal access to |host_view_| test target.
  264. InkDropHostTestApi host_view_test_api_;
  265. raw_ptr<InkDropImpl> ink_drop_ = nullptr;
  266. // Provides internal access to |host_view_|'s ink drop.
  267. std::unique_ptr<test::InkDropImplTestApi> ink_drop_test_api_;
  268. };
  269. // Tests that by default (no highlight path generator applied), the root layer
  270. // will be masked.
  271. TEST_F(InkDropHostViewClippingTest, DefaultInkDropMasksRootLayer) {
  272. ink_drop_->SetHovered(true);
  273. EXPECT_TRUE(GetRootLayer()->layer_mask_layer());
  274. EXPECT_TRUE(GetRootLayer()->clip_rect().IsEmpty());
  275. }
  276. // Tests that when adding a non empty highlight path generator, the root layer
  277. // is clipped instead of masked.
  278. TEST_F(InkDropHostViewClippingTest,
  279. HighlightPathGeneratorClipsRootLayerWithoutMask) {
  280. views::InstallRectHighlightPathGenerator(&host_view_);
  281. ink_drop_->SetHovered(true);
  282. EXPECT_FALSE(GetRootLayer()->layer_mask_layer());
  283. EXPECT_FALSE(GetRootLayer()->clip_rect().IsEmpty());
  284. }
  285. // An empty highlight path generator is used for views who do not want their
  286. // highlight or ripple constrained by their size. Test that the views' ink
  287. // drop root layers have neither a clip or mask.
  288. TEST_F(InkDropHostViewClippingTest,
  289. EmptyHighlightPathGeneratorUsesNeitherMaskNorClipsRootLayer) {
  290. views::InstallEmptyHighlightPathGenerator(&host_view_);
  291. ink_drop_->SetHovered(true);
  292. EXPECT_FALSE(GetRootLayer()->layer_mask_layer());
  293. EXPECT_TRUE(GetRootLayer()->clip_rect().IsEmpty());
  294. }
  295. } // namespace test
  296. } // namespace views