Index: ui/views/controls/menu/menu_controller_unittest.cc |
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc |
index 03ba6716f09adf62931a1791eec67f073d078319..e9074f0704e4194f64d44dbd7f7e0a96a36cac9f 100644 |
--- a/ui/views/controls/menu/menu_controller_unittest.cc |
+++ b/ui/views/controls/menu/menu_controller_unittest.cc |
@@ -9,9 +9,14 @@ |
#include "build/build_config.h" |
#include "ui/aura/scoped_window_targeter.h" |
#include "ui/aura/window.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/null_event_targeter.h" |
#include "ui/events/test/event_generator.h" |
+#include "ui/gfx/geometry/point.h" |
+#include "ui/gfx/geometry/rect.h" |
#include "ui/views/controls/menu/menu_controller_delegate.h" |
#include "ui/views/controls/menu/menu_delegate.h" |
#include "ui/views/controls/menu/menu_item_view.h" |
@@ -386,6 +391,11 @@ class MenuControllerTest : public ViewsTestBase { |
menu_controller_->set_is_combobox(is_combobox); |
} |
+ void SetSelectionOnPointerDown(SubmenuView* source, |
+ const ui::LocatedEvent* event) { |
+ menu_controller_->SetSelectionOnPointerDown(source, event); |
+ } |
+ |
void RunMenu() { |
menu_controller_->message_loop_depth_++; |
menu_controller_->RunMessageLoop(false); |
@@ -825,6 +835,81 @@ TEST_F(MenuControllerTest, DoubleAsynchronousNested) { |
EXPECT_EQ(1, nested_delegate->on_menu_closed_called()); |
} |
+// Tests that an asynchronous menu nested within a synchronous menu does not |
+// crash when trying to repost events that occur outside of the bounds of the |
+// menu. Instead a proper shutdown should occur. |
+TEST_F(MenuControllerTest, AsynchronousRepostEvent) { |
+ MenuController* controller = menu_controller(); |
+ TestMenuControllerDelegate* delegate = menu_controller_delegate(); |
+ scoped_ptr<TestMenuControllerDelegate> nested_delegate( |
+ new TestMenuControllerDelegate()); |
+ |
+ ASSERT_FALSE(IsAsyncRun()); |
+ |
+ controller->AddNestedDelegate(nested_delegate.get()); |
+ controller->SetAsyncRun(true); |
+ |
+ EXPECT_TRUE(IsAsyncRun()); |
+ EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate()); |
+ |
+ MenuItemView* item = menu_item(); |
+ int mouse_event_flags = 0; |
+ MenuItemView* run_result = |
+ controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT, |
+ false, false, &mouse_event_flags); |
+ EXPECT_EQ(run_result, nullptr); |
+ |
+ // Show a sub menu to targert with a pointer selection. However have the event |
+ // occur outside of the bounds of the entire menu. |
+ SubmenuView* sub_menu = item->GetSubmenu(); |
+ sub_menu->ShowAt(owner(), item->bounds(), false); |
+ gfx::Point location(sub_menu->bounds().bottom_right()); |
+ location.Offset(1, 1); |
+ ui::MouseEvent event(ui::ET_MOUSE_PRESSED, location, location, |
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); |
+ |
+ // When attempting to select outside of all menus this should lead to a |
+ // shutdown. This should not crash while attempting to repost the event. |
+ SetSelectionOnPointerDown(sub_menu, &event); |
+ |
+ EXPECT_FALSE(IsAsyncRun()); |
+ EXPECT_EQ(delegate, GetCurrentDelegate()); |
+ EXPECT_EQ(0, delegate->on_menu_closed_called()); |
+ EXPECT_EQ(1, nested_delegate->on_menu_closed_called()); |
+ EXPECT_EQ(nullptr, nested_delegate->on_menu_closed_menu()); |
+ EXPECT_EQ(0, nested_delegate->on_menu_closed_mouse_event_flags()); |
+ EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE, |
+ nested_delegate->on_menu_closed_notify_type()); |
+ EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type()); |
+} |
+ |
+// Tests that an asynchronous menu reposts touch events that occur outside of |
+// the bounds of the menu, and that the menu closes. |
+TEST_F(MenuControllerTest, AsynchronousTouchEventRepostEvent) { |
+ MenuController* controller = menu_controller(); |
+ TestMenuControllerDelegate* delegate = menu_controller_delegate(); |
+ controller->SetAsyncRun(true); |
+ |
+ // Show a sub menu to targert with a touch event. However have the event occur |
+ // outside of the bounds of the entire menu. |
+ MenuItemView* item = menu_item(); |
+ SubmenuView* sub_menu = item->GetSubmenu(); |
+ sub_menu->ShowAt(owner(), item->bounds(), false); |
+ gfx::Point location(sub_menu->bounds().bottom_right()); |
+ location.Offset(1, 1); |
+ ui::TouchEvent event(ui::ET_TOUCH_PRESSED, location, 0, 0, |
+ ui::EventTimeForNow(), 0, 0, 0, 0); |
+ controller->OnTouchEvent(sub_menu, &event); |
+ |
+ EXPECT_FALSE(IsShowing()); |
+ EXPECT_EQ(1, delegate->on_menu_closed_called()); |
+ EXPECT_EQ(nullptr, delegate->on_menu_closed_menu()); |
+ EXPECT_EQ(0, delegate->on_menu_closed_mouse_event_flags()); |
+ EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE, |
+ delegate->on_menu_closed_notify_type()); |
+ EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type()); |
+} |
+ |
// Tests that if you exit all menus when an asynchrnous menu is nested within a |
// synchronous menu, the message loop for the parent menu finishes running. |
TEST_F(MenuControllerTest, AsynchronousNestedExitAll) { |