1// Copyright (c) 2013 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 5#include "ui/aura/window_targeter.h" 6 7#include "ui/aura/scoped_window_targeter.h" 8#include "ui/aura/test/aura_test_base.h" 9#include "ui/aura/test/test_window_delegate.h" 10#include "ui/aura/window.h" 11#include "ui/events/test/test_event_handler.h" 12 13namespace aura { 14 15// Always returns the same window. 16class StaticWindowTargeter : public ui::EventTargeter { 17 public: 18 explicit StaticWindowTargeter(aura::Window* window) 19 : window_(window) {} 20 virtual ~StaticWindowTargeter() {} 21 22 private: 23 // ui::EventTargeter: 24 virtual ui::EventTarget* FindTargetForLocatedEvent( 25 ui::EventTarget* root, 26 ui::LocatedEvent* event) OVERRIDE { 27 return window_; 28 } 29 30 Window* window_; 31 32 DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter); 33}; 34 35class WindowTargeterTest : public test::AuraTestBase { 36 public: 37 WindowTargeterTest() {} 38 virtual ~WindowTargeterTest() {} 39 40 Window* root_window() { return AuraTestBase::root_window(); } 41}; 42 43gfx::RectF GetEffectiveVisibleBoundsInRootWindow(Window* window) { 44 gfx::RectF bounds = gfx::Rect(window->bounds().size()); 45 Window* root = window->GetRootWindow(); 46 CHECK(window->layer()); 47 CHECK(root->layer()); 48 gfx::Transform transform; 49 if (!window->layer()->GetTargetTransformRelativeTo(root->layer(), &transform)) 50 return gfx::RectF(); 51 transform.TransformRect(&bounds); 52 return bounds; 53} 54 55TEST_F(WindowTargeterTest, Basic) { 56 test::TestWindowDelegate delegate; 57 scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate)); 58 Window* one = CreateNormalWindow(2, window.get(), &delegate); 59 Window* two = CreateNormalWindow(3, window.get(), &delegate); 60 61 window->SetBounds(gfx::Rect(0, 0, 100, 100)); 62 one->SetBounds(gfx::Rect(0, 0, 500, 100)); 63 two->SetBounds(gfx::Rect(501, 0, 500, 1000)); 64 65 root_window()->Show(); 66 67 ui::test::TestEventHandler handler; 68 one->AddPreTargetHandler(&handler); 69 70 ui::MouseEvent press(ui::ET_MOUSE_PRESSED, 71 gfx::Point(20, 20), 72 gfx::Point(20, 20), 73 ui::EF_NONE, 74 ui::EF_NONE); 75 DispatchEventUsingWindowDispatcher(&press); 76 EXPECT_EQ(1, handler.num_mouse_events()); 77 78 handler.Reset(); 79 DispatchEventUsingWindowDispatcher(&press); 80 EXPECT_EQ(1, handler.num_mouse_events()); 81 82 one->RemovePreTargetHandler(&handler); 83} 84 85TEST_F(WindowTargeterTest, ScopedWindowTargeter) { 86 test::TestWindowDelegate delegate; 87 scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate)); 88 Window* child = CreateNormalWindow(2, window.get(), &delegate); 89 90 window->SetBounds(gfx::Rect(30, 30, 100, 100)); 91 child->SetBounds(gfx::Rect(20, 20, 50, 50)); 92 root_window()->Show(); 93 94 ui::EventTarget* root = root_window(); 95 ui::EventTargeter* targeter = root->GetEventTargeter(); 96 97 gfx::Point event_location(60, 60); 98 { 99 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, 100 ui::EF_NONE, ui::EF_NONE); 101 EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse)); 102 } 103 104 // Install a targeter on |window| so that the events never reach the child. 105 scoped_ptr<ScopedWindowTargeter> scoped_targeter( 106 new ScopedWindowTargeter(window.get(), scoped_ptr<ui::EventTargeter>( 107 new StaticWindowTargeter(window.get())))); 108 { 109 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, 110 ui::EF_NONE, ui::EF_NONE); 111 EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse)); 112 } 113 scoped_targeter.reset(); 114 { 115 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, 116 ui::EF_NONE, ui::EF_NONE); 117 EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse)); 118 } 119} 120 121// Test that ScopedWindowTargeter does not crash if the window for which it 122// replaces the targeter gets destroyed before it does. 123TEST_F(WindowTargeterTest, ScopedWindowTargeterWindowDestroyed) { 124 test::TestWindowDelegate delegate; 125 scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate)); 126 scoped_ptr<ScopedWindowTargeter> scoped_targeter( 127 new ScopedWindowTargeter(window.get(), scoped_ptr<ui::EventTargeter>( 128 new StaticWindowTargeter(window.get())))); 129 130 window.reset(); 131 scoped_targeter.reset(); 132 133 // We did not crash! 134} 135 136TEST_F(WindowTargeterTest, TargetTransformedWindow) { 137 root_window()->Show(); 138 139 test::TestWindowDelegate delegate; 140 scoped_ptr<Window> window(CreateNormalWindow(2, root_window(), &delegate)); 141 142 const gfx::Rect window_bounds(100, 20, 400, 80); 143 window->SetBounds(window_bounds); 144 145 ui::EventTarget* root_target = root_window(); 146 ui::EventTargeter* targeter = root_target->GetEventTargeter(); 147 gfx::Point event_location(490, 50); 148 { 149 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, 150 ui::EF_NONE, ui::EF_NONE); 151 EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse)); 152 } 153 154 // Scale |window| by 50%. This should move it away from underneath 155 // |event_location|, so an event in that location will not be targeted to it. 156 gfx::Transform transform; 157 transform.Scale(0.5, 0.5); 158 window->SetTransform(transform); 159 EXPECT_EQ(gfx::RectF(100, 20, 200, 40).ToString(), 160 GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString()); 161 { 162 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, 163 ui::EF_NONE, ui::EF_NONE); 164 EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_target, &mouse)); 165 } 166 167 transform = gfx::Transform(); 168 transform.Translate(200, 10); 169 transform.Scale(0.5, 0.5); 170 window->SetTransform(transform); 171 EXPECT_EQ(gfx::RectF(300, 30, 200, 40).ToString(), 172 GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString()); 173 { 174 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, 175 ui::EF_NONE, ui::EF_NONE); 176 EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse)); 177 } 178} 179 180} // namespace aura 181