// Copyright (c) 2013 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/aura/window_targeter.h" #include "ui/aura/scoped_window_targeter.h" #include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" #include "ui/events/test/test_event_handler.h" namespace aura { // Always returns the same window. class StaticWindowTargeter : public ui::EventTargeter { public: explicit StaticWindowTargeter(aura::Window* window) : window_(window) {} virtual ~StaticWindowTargeter() {} private: // ui::EventTargeter: virtual ui::EventTarget* FindTargetForLocatedEvent( ui::EventTarget* root, ui::LocatedEvent* event) OVERRIDE { return window_; } Window* window_; DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter); }; class WindowTargeterTest : public test::AuraTestBase { public: WindowTargeterTest() {} virtual ~WindowTargeterTest() {} Window* root_window() { return AuraTestBase::root_window(); } }; gfx::RectF GetEffectiveVisibleBoundsInRootWindow(Window* window) { gfx::RectF bounds = gfx::Rect(window->bounds().size()); Window* root = window->GetRootWindow(); CHECK(window->layer()); CHECK(root->layer()); gfx::Transform transform; if (!window->layer()->GetTargetTransformRelativeTo(root->layer(), &transform)) return gfx::RectF(); transform.TransformRect(&bounds); return bounds; } TEST_F(WindowTargeterTest, Basic) { test::TestWindowDelegate delegate; scoped_ptr window(CreateNormalWindow(1, root_window(), &delegate)); Window* one = CreateNormalWindow(2, window.get(), &delegate); Window* two = CreateNormalWindow(3, window.get(), &delegate); window->SetBounds(gfx::Rect(0, 0, 100, 100)); one->SetBounds(gfx::Rect(0, 0, 500, 100)); two->SetBounds(gfx::Rect(501, 0, 500, 1000)); root_window()->Show(); ui::test::TestEventHandler handler; one->AddPreTargetHandler(&handler); ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(20, 20), gfx::Point(20, 20), ui::EF_NONE, ui::EF_NONE); DispatchEventUsingWindowDispatcher(&press); EXPECT_EQ(1, handler.num_mouse_events()); handler.Reset(); DispatchEventUsingWindowDispatcher(&press); EXPECT_EQ(1, handler.num_mouse_events()); one->RemovePreTargetHandler(&handler); } TEST_F(WindowTargeterTest, ScopedWindowTargeter) { test::TestWindowDelegate delegate; scoped_ptr window(CreateNormalWindow(1, root_window(), &delegate)); Window* child = CreateNormalWindow(2, window.get(), &delegate); window->SetBounds(gfx::Rect(30, 30, 100, 100)); child->SetBounds(gfx::Rect(20, 20, 50, 50)); root_window()->Show(); ui::EventTarget* root = root_window(); ui::EventTargeter* targeter = root->GetEventTargeter(); gfx::Point event_location(60, 60); { ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, ui::EF_NONE, ui::EF_NONE); EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse)); } // Install a targeter on |window| so that the events never reach the child. scoped_ptr scoped_targeter( new ScopedWindowTargeter(window.get(), scoped_ptr( new StaticWindowTargeter(window.get())))); { ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, ui::EF_NONE, ui::EF_NONE); EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse)); } scoped_targeter.reset(); { ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, ui::EF_NONE, ui::EF_NONE); EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse)); } } // Test that ScopedWindowTargeter does not crash if the window for which it // replaces the targeter gets destroyed before it does. TEST_F(WindowTargeterTest, ScopedWindowTargeterWindowDestroyed) { test::TestWindowDelegate delegate; scoped_ptr window(CreateNormalWindow(1, root_window(), &delegate)); scoped_ptr scoped_targeter( new ScopedWindowTargeter(window.get(), scoped_ptr( new StaticWindowTargeter(window.get())))); window.reset(); scoped_targeter.reset(); // We did not crash! } TEST_F(WindowTargeterTest, TargetTransformedWindow) { root_window()->Show(); test::TestWindowDelegate delegate; scoped_ptr window(CreateNormalWindow(2, root_window(), &delegate)); const gfx::Rect window_bounds(100, 20, 400, 80); window->SetBounds(window_bounds); ui::EventTarget* root_target = root_window(); ui::EventTargeter* targeter = root_target->GetEventTargeter(); gfx::Point event_location(490, 50); { ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, ui::EF_NONE, ui::EF_NONE); EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse)); } // Scale |window| by 50%. This should move it away from underneath // |event_location|, so an event in that location will not be targeted to it. gfx::Transform transform; transform.Scale(0.5, 0.5); window->SetTransform(transform); EXPECT_EQ(gfx::RectF(100, 20, 200, 40).ToString(), GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString()); { ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, ui::EF_NONE, ui::EF_NONE); EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_target, &mouse)); } transform = gfx::Transform(); transform.Translate(200, 10); transform.Scale(0.5, 0.5); window->SetTransform(transform); EXPECT_EQ(gfx::RectF(300, 30, 200, 40).ToString(), GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString()); { ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, ui::EF_NONE, ui::EF_NONE); EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse)); } } } // namespace aura