diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-20 16:11:21 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-20 16:11:21 +0000 |
commit | e1850856986a812c7a84fbc34899a6c5af8187f8 (patch) | |
tree | 1954dd261d8b80da778bac1ac2e90aa3a84cb439 | |
parent | f66f1c0b76001e9e988827fab799eeab704c9f16 (diff) | |
download | chromium_src-e1850856986a812c7a84fbc34899a6c5af8187f8.zip chromium_src-e1850856986a812c7a84fbc34899a6c5af8187f8.tar.gz chromium_src-e1850856986a812c7a84fbc34899a6c5af8187f8.tar.bz2 |
events: Fix event-targeting for transformed windows.
Applying the transforms on a Window's bounds does not give the correct transformed
bounds of the window in its parent's coordinate system. For example, a Window with
size 300x200 at position 20,10 and scaled at 50% has bounds (20, 10, 150, 100), and
not (10, 5, 150, 100). So remove this transform from the window-targeting code, and
instead convert the event's location to be in the child Window's coordinate system
when doing hit-testing.
This fixes selecting windows when in overview mode.
BUG=339834
R=sky@chromium.org
Review URL: https://codereview.chromium.org/167323004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@252257 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/wm/overview/window_selector_unittest.cc | 46 | ||||
-rw-r--r-- | ui/aura/window_targeter.cc | 8 | ||||
-rw-r--r-- | ui/aura/window_targeter_unittest.cc | 56 | ||||
-rw-r--r-- | ui/wm/core/easy_resize_window_targeter.cc | 19 |
4 files changed, 116 insertions, 13 deletions
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc index db3c6fb5..c23fedc 100644 --- a/ash/wm/overview/window_selector_unittest.cc +++ b/ash/wm/overview/window_selector_unittest.cc @@ -198,6 +198,20 @@ class WindowSelectorTest : public test::AshTestBase { return bounds; } + gfx::RectF GetTransformedBoundsInRootWindow(aura::Window* window) { + gfx::RectF bounds = gfx::Rect(window->bounds().size()); + aura::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; + } + void ClickWindow(aura::Window* window) { aura::test::EventGenerator event_generator(window->GetRootWindow(), window); gfx::RectF target = GetTransformedBounds(window); @@ -1030,5 +1044,37 @@ TEST_F(WindowSelectorTest, DISABLED_DragDropInProgress) { RunAllPendingInMessageLoop(); } +TEST_F(WindowSelectorTest, HitTestingInOverview) { + gfx::Rect window_bounds(20, 10, 200, 300); + aura::Window* root_window = Shell::GetPrimaryRootWindow(); + scoped_ptr<aura::Window> window1(CreateWindow(window_bounds)); + scoped_ptr<aura::Window> window2(CreateWindow(window_bounds)); + + ToggleOverview(); + gfx::RectF bounds1 = GetTransformedBoundsInRootWindow(window1.get()); + gfx::RectF bounds2 = GetTransformedBoundsInRootWindow(window2.get()); + EXPECT_NE(bounds1.ToString(), bounds2.ToString()); + + ui::EventTarget* root_target = root_window; + ui::EventTargeter* targeter = root_target->GetEventTargeter(); + aura::Window* windows[] = { window1.get(), window2.get() }; + for (size_t w = 0; w < arraysize(windows); ++w) { + gfx::RectF bounds = GetTransformedBoundsInRootWindow(windows[w]); + gfx::Point points[] = { + gfx::Point(bounds.x(), bounds.y()), + gfx::Point(bounds.right() - 1, bounds.y()), + gfx::Point(bounds.x(), bounds.bottom() - 1), + gfx::Point(bounds.right() - 1, bounds.bottom() - 1), + }; + + for (size_t p = 0; p < arraysize(points); ++p) { + ui::MouseEvent event(ui::ET_MOUSE_MOVED, points[p], points[p], + ui::EF_NONE, ui::EF_NONE); + EXPECT_EQ(windows[w], + targeter->FindTargetForEvent(root_target, &event)); + } + } +} + } // namespace internal } // namespace ash diff --git a/ui/aura/window_targeter.cc b/ui/aura/window_targeter.cc index 942d8c7..7db90de 100644 --- a/ui/aura/window_targeter.cc +++ b/ui/aura/window_targeter.cc @@ -37,10 +37,10 @@ bool WindowTargeter::WindowCanAcceptEvent(aura::Window* window, bool WindowTargeter::EventLocationInsideBounds( aura::Window* window, const ui::LocatedEvent& event) const { - gfx::RectF bounds = window->bounds(); - if (window->layer()) - window->layer()->transform().TransformRect(&bounds); - return bounds.Contains(event.location()); + gfx::Point point = event.location(); + if (window->parent()) + aura::Window::ConvertPointToTarget(window->parent(), window, &point); + return gfx::Rect(window->bounds().size()).Contains(point); } ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root, diff --git a/ui/aura/window_targeter_unittest.cc b/ui/aura/window_targeter_unittest.cc index fb84ee4..985426b 100644 --- a/ui/aura/window_targeter_unittest.cc +++ b/ui/aura/window_targeter_unittest.cc @@ -40,6 +40,18 @@ class WindowTargeterTest : public test::AuraTestBase { 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> window(CreateNormalWindow(1, root_window(), &delegate)); @@ -106,4 +118,48 @@ TEST_F(WindowTargeterTest, ScopedWindowTargeter) { } } +TEST_F(WindowTargeterTest, TargetTransformedWindow) { + root_window()->Show(); + + test::TestWindowDelegate delegate; + scoped_ptr<Window> 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 diff --git a/ui/wm/core/easy_resize_window_targeter.cc b/ui/wm/core/easy_resize_window_targeter.cc index 1f0e90a..5b48c81 100644 --- a/ui/wm/core/easy_resize_window_targeter.cc +++ b/ui/wm/core/easy_resize_window_targeter.cc @@ -27,18 +27,19 @@ bool EasyResizeWindowTargeter::EventLocationInsideBounds( aura::Window* window, const ui::LocatedEvent& event) const { if (ShouldUseExtendedBounds(window)) { - gfx::RectF bounds(window->bounds()); - gfx::Transform transform = window->layer()->transform(); - transform.TransformRect(&bounds); - if (event.IsTouchEvent() || event.IsGestureEvent()) { + // Note that |event|'s location is in |window|'s parent's coordinate system, + // so convert it to |window|'s coordinate system first. + gfx::Point point = event.location(); + if (window->parent()) + aura::Window::ConvertPointToTarget(window->parent(), window, &point); + + gfx::Rect bounds(window->bounds().size()); + if (event.IsTouchEvent() || event.IsGestureEvent()) bounds.Inset(touch_extend_); - } else { + else bounds.Inset(mouse_extend_); - } - // Note that |event|'s location is in the |container_|'s coordinate system, - // as is |bounds|. - return bounds.Contains(event.location()); + return bounds.Contains(point); } return WindowTargeter::EventLocationInsideBounds(window, event); } |