123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- // Copyright 2016 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/views/animation/ink_drop_host_view.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/raw_ptr.h"
- #include "build/build_config.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "ui/compositor/layer.h"
- #include "ui/events/event.h"
- #include "ui/events/event_constants.h"
- #include "ui/events/event_handler.h"
- #include "ui/events/event_utils.h"
- #include "ui/events/types/event_type.h"
- #include "ui/gfx/animation/animation.h"
- #include "ui/gfx/animation/animation_test_api.h"
- #include "ui/gfx/color_palette.h"
- #include "ui/gfx/geometry/point.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/views/animation/ink_drop.h"
- #include "ui/views/animation/ink_drop_impl.h"
- #include "ui/views/animation/test/ink_drop_host_view_test_api.h"
- #include "ui/views/animation/test/ink_drop_impl_test_api.h"
- #include "ui/views/animation/test/test_ink_drop.h"
- #include "ui/views/controls/highlight_path_generator.h"
- namespace views {
- namespace test {
- using InkDropMode = InkDropHostTestApi::InkDropMode;
- class TestViewWithInkDrop : public View {
- public:
- TestViewWithInkDrop() {
- InkDrop::Install(this, std::make_unique<InkDropHost>(this));
- InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating(
- [](TestViewWithInkDrop* host) -> std::unique_ptr<InkDrop> {
- auto ink_drop = std::make_unique<TestInkDrop>();
- host->last_created_inkdrop_ = ink_drop.get();
- return ink_drop;
- },
- this));
- InkDrop::Get(this)->SetBaseColor(gfx::kPlaceholderColor);
- }
- TestViewWithInkDrop(const TestViewWithInkDrop&) = delete;
- TestViewWithInkDrop& operator=(const TestViewWithInkDrop&) = delete;
- // Expose EventTarget::target_handler() for testing.
- ui::EventHandler* GetTargetHandler() { return target_handler(); }
- TestInkDrop* last_created_inkdrop() const { return last_created_inkdrop_; }
- private:
- raw_ptr<TestInkDrop> last_created_inkdrop_ = nullptr;
- };
- class InkDropHostViewTest : public testing::Test {
- public:
- InkDropHostViewTest();
- InkDropHostViewTest(const InkDropHostViewTest&) = delete;
- InkDropHostViewTest& operator=(const InkDropHostViewTest&) = delete;
- ~InkDropHostViewTest() override;
- protected:
- // Test target.
- TestViewWithInkDrop host_view_;
- // Provides internal access to |host_view_| test target.
- InkDropHostTestApi test_api_;
- std::unique_ptr<base::AutoReset<gfx::Animation::RichAnimationRenderMode>>
- animation_mode_reset_;
- void MouseEventTriggersInkDropHelper(InkDropMode ink_drop_mode);
- };
- InkDropHostViewTest::InkDropHostViewTest()
- : test_api_(InkDrop::Get(&host_view_)),
- animation_mode_reset_(gfx::AnimationTestApi::SetRichAnimationRenderMode(
- gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED)) {}
- InkDropHostViewTest::~InkDropHostViewTest() = default;
- void InkDropHostViewTest::MouseEventTriggersInkDropHelper(
- InkDropMode ink_drop_mode) {
- test_api_.SetInkDropMode(ink_drop_mode);
- host_view_.SetEnabled(true);
- // Call InkDrop::Get(this)->GetInkDrop() to make sure the test
- // CreateInkDrop() is created.
- test_api_.GetInkDrop();
- if (ink_drop_mode != views::InkDropHost::InkDropMode::OFF)
- EXPECT_FALSE(host_view_.last_created_inkdrop()->is_hovered());
- else
- EXPECT_EQ(host_view_.last_created_inkdrop(), nullptr);
- ui::MouseEvent mouse_event(ui::ET_MOUSE_ENTERED, gfx::Point(0, 0),
- gfx::Point(0, 0), ui::EventTimeForNow(),
- ui::EF_IS_SYNTHESIZED, 0);
- host_view_.GetTargetHandler()->OnEvent(&mouse_event);
- if (ink_drop_mode != views::InkDropHost::InkDropMode::OFF)
- EXPECT_TRUE(host_view_.last_created_inkdrop()->is_hovered());
- else
- EXPECT_EQ(host_view_.last_created_inkdrop(), nullptr);
- }
- // Verifies the return value of GetInkDropCenterBasedOnLastEvent() for a null
- // Event.
- TEST_F(InkDropHostViewTest, GetInkDropCenterBasedOnLastEventForNullEvent) {
- host_view_.SetSize(gfx::Size(20, 20));
- test_api_.AnimateToState(InkDropState::ACTION_PENDING, nullptr);
- EXPECT_EQ(gfx::Point(10, 10),
- InkDrop::Get(&host_view_)->GetInkDropCenterBasedOnLastEvent());
- }
- // Verifies the return value of GetInkDropCenterBasedOnLastEvent() for a located
- // Event.
- TEST_F(InkDropHostViewTest, GetInkDropCenterBasedOnLastEventForLocatedEvent) {
- host_view_.SetSize(gfx::Size(20, 20));
- ui::MouseEvent located_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 6),
- gfx::Point(5, 6), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- test_api_.AnimateToState(InkDropState::ACTION_PENDING, &located_event);
- EXPECT_EQ(gfx::Point(5, 6),
- InkDrop::Get(&host_view_)->GetInkDropCenterBasedOnLastEvent());
- }
- TEST_F(InkDropHostViewTest, HasInkDrop) {
- EXPECT_FALSE(test_api_.HasInkDrop());
- test_api_.GetInkDrop();
- EXPECT_TRUE(test_api_.HasInkDrop());
- test_api_.SetInkDropMode(views::InkDropHost::InkDropMode::OFF);
- EXPECT_FALSE(test_api_.HasInkDrop());
- }
- // Verifies that mouse events trigger ink drops when ink drop mode is ON.
- TEST_F(InkDropHostViewTest, MouseEventsTriggerInkDropsWhenInkDropIsOn) {
- MouseEventTriggersInkDropHelper(views::InkDropHost::InkDropMode::ON);
- }
- // Verifies that mouse events trigger ink drops when ink drop mode is
- // ON_NO_GESTURE_HANDLER.
- TEST_F(InkDropHostViewTest,
- MouseEventsTriggerInkDropsWhenInkDropIsOnNoGestureHandler) {
- MouseEventTriggersInkDropHelper(
- views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER);
- }
- // Verifies that mouse events do not trigger ink drops when ink drop mode is
- // OFF.
- TEST_F(InkDropHostViewTest, MouseEventsDontTriggerInkDropsWhenInkDropIsOff) {
- MouseEventTriggersInkDropHelper(views::InkDropHost::InkDropMode::OFF);
- }
- // Verifies that ink drops are not shown when the host is disabled.
- TEST_F(InkDropHostViewTest,
- GestureEventsDontTriggerInkDropsWhenHostIsDisabled) {
- test_api_.SetInkDropMode(views::InkDropHost::InkDropMode::ON);
- host_view_.SetEnabled(false);
- ui::GestureEvent gesture_event(
- 0.f, 0.f, 0, ui::EventTimeForNow(),
- ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
- host_view_.GetTargetHandler()->OnEvent(&gesture_event);
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::HIDDEN);
- }
- // Verifies that ink drops are not triggered by gesture events when ink drop
- // mode is ON_NO_GESTURE_EVENT or OFF.
- TEST_F(InkDropHostViewTest,
- GestureEventsDontTriggerInkDropsWhenInkDropModeIsNotOn) {
- for (auto ink_drop_mode :
- {views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER,
- views::InkDropHost::InkDropMode::OFF}) {
- test_api_.SetInkDropMode(ink_drop_mode);
- ui::GestureEvent gesture_event(
- 0.f, 0.f, 0, ui::EventTimeForNow(),
- ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
- host_view_.GetTargetHandler()->OnEvent(&gesture_event);
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::HIDDEN);
- }
- }
- #if BUILDFLAG(IS_WIN)
- TEST_F(InkDropHostViewTest, NoInkDropOnTouchOrGestureEvents) {
- host_view_.SetSize(gfx::Size(20, 20));
- test_api_.SetInkDropMode(
- views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER);
- // Ensure the target ink drop is in the expected state.
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::HIDDEN);
- ui::TouchEvent touch_event(
- ui::ET_TOUCH_PRESSED, gfx::Point(5, 6), ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::kTouch, 1));
- test_api_.AnimateToState(InkDropState::ACTION_PENDING, &touch_event);
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::HIDDEN);
- test_api_.AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING,
- &touch_event);
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::HIDDEN);
- ui::GestureEvent gesture_event(5.0f, 6.0f, 0, ui::EventTimeForNow(),
- ui::GestureEventDetails(ui::ET_GESTURE_TAP));
- test_api_.AnimateToState(InkDropState::ACTION_PENDING, &gesture_event);
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::HIDDEN);
- test_api_.AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING,
- &gesture_event);
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::HIDDEN);
- }
- TEST_F(InkDropHostViewTest, DismissInkDropOnTouchOrGestureEvents) {
- // TODO(bruthig): Re-enable! For some reason these tests fail on some win
- // trunk builds. See crbug.com/731811.
- if (!gfx::Animation::ShouldRenderRichAnimation())
- return;
- host_view_.SetSize(gfx::Size(20, 20));
- test_api_.SetInkDropMode(
- views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER);
- // Ensure the target ink drop is in the expected state.
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::HIDDEN);
- ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 6),
- gfx::Point(5, 6), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- test_api_.AnimateToState(InkDropState::ACTION_PENDING, &mouse_event);
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::ACTION_PENDING);
- ui::TouchEvent touch_event(
- ui::ET_TOUCH_PRESSED, gfx::Point(5, 6), ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::kTouch, 1));
- test_api_.AnimateToState(InkDropState::ACTION_TRIGGERED, &touch_event);
- EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
- InkDropState::ACTION_TRIGGERED);
- }
- #endif
- // Verifies that calling OnInkDropHighlightedChanged() triggers a property
- // changed notification for the highlighted property.
- TEST_F(InkDropHostViewTest, HighlightedChangedFired) {
- bool callback_called = false;
- auto subscription =
- InkDrop::Get(&host_view_)
- ->AddHighlightedChangedCallback(base::BindRepeating(
- [](bool* called) { *called = true; }, &callback_called));
- InkDrop::Get(&host_view_)->OnInkDropHighlightedChanged();
- EXPECT_TRUE(callback_called);
- }
- // A very basic View that hosts an InkDrop.
- class BasicTestViewWithInkDrop : public View {
- public:
- BasicTestViewWithInkDrop() {
- InkDrop::Install(this, std::make_unique<InkDropHost>(this));
- // Call SetBaseColor to avoid hitting a NOTREACHED() for fetching an
- // undefined color.
- InkDrop::Get(this)->SetBaseColor(gfx::kPlaceholderColor);
- }
- BasicTestViewWithInkDrop(const BasicTestViewWithInkDrop&) = delete;
- BasicTestViewWithInkDrop& operator=(const BasicTestViewWithInkDrop&) = delete;
- ~BasicTestViewWithInkDrop() override = default;
- };
- // Tests the existence of layer clipping or layer masking when certain path
- // generators are applied on an InkDropHostView.
- class InkDropHostViewClippingTest : public testing::Test {
- public:
- InkDropHostViewClippingTest()
- : host_view_test_api_(InkDrop::Get(&host_view_)) {
- // Set up an InkDropHostView. Clipping is based on the size of the view, so
- // make sure the size is non empty.
- host_view_test_api_.SetInkDropMode(views::InkDropHost::InkDropMode::ON);
- host_view_.SetSize(gfx::Size(20, 20));
- // The root layer of the ink drop is created the first time GetInkDrop is
- // called and then kept alive until the host view is destroyed.
- ink_drop_ =
- static_cast<InkDropImpl*>(InkDrop::Get(&host_view_)->GetInkDrop());
- ink_drop_test_api_ = std::make_unique<test::InkDropImplTestApi>(ink_drop_);
- }
- InkDropHostViewClippingTest(const InkDropHostViewClippingTest&) = delete;
- InkDropHostViewClippingTest& operator=(const InkDropHostViewClippingTest&) =
- delete;
- ~InkDropHostViewClippingTest() override = default;
- ui::Layer* GetRootLayer() { return ink_drop_test_api_->GetRootLayer(); }
- protected:
- // Test target.
- BasicTestViewWithInkDrop host_view_;
- // Provides internal access to |host_view_| test target.
- InkDropHostTestApi host_view_test_api_;
- raw_ptr<InkDropImpl> ink_drop_ = nullptr;
- // Provides internal access to |host_view_|'s ink drop.
- std::unique_ptr<test::InkDropImplTestApi> ink_drop_test_api_;
- };
- // Tests that by default (no highlight path generator applied), the root layer
- // will be masked.
- TEST_F(InkDropHostViewClippingTest, DefaultInkDropMasksRootLayer) {
- ink_drop_->SetHovered(true);
- EXPECT_TRUE(GetRootLayer()->layer_mask_layer());
- EXPECT_TRUE(GetRootLayer()->clip_rect().IsEmpty());
- }
- // Tests that when adding a non empty highlight path generator, the root layer
- // is clipped instead of masked.
- TEST_F(InkDropHostViewClippingTest,
- HighlightPathGeneratorClipsRootLayerWithoutMask) {
- views::InstallRectHighlightPathGenerator(&host_view_);
- ink_drop_->SetHovered(true);
- EXPECT_FALSE(GetRootLayer()->layer_mask_layer());
- EXPECT_FALSE(GetRootLayer()->clip_rect().IsEmpty());
- }
- // An empty highlight path generator is used for views who do not want their
- // highlight or ripple constrained by their size. Test that the views' ink
- // drop root layers have neither a clip or mask.
- TEST_F(InkDropHostViewClippingTest,
- EmptyHighlightPathGeneratorUsesNeitherMaskNorClipsRootLayer) {
- views::InstallEmptyHighlightPathGenerator(&host_view_);
- ink_drop_->SetHovered(true);
- EXPECT_FALSE(GetRootLayer()->layer_mask_layer());
- EXPECT_TRUE(GetRootLayer()->clip_rect().IsEmpty());
- }
- } // namespace test
- } // namespace views
|