| Index: ui/views/widget/root_view_unittest.cc
|
| diff --git a/ui/views/widget/root_view_unittest.cc b/ui/views/widget/root_view_unittest.cc
|
| index fcefb7033020c19e0e19b8890838937b54e233f4..373fe2957f44129445701bea506ad534f64c17ff 100644
|
| --- a/ui/views/widget/root_view_unittest.cc
|
| +++ b/ui/views/widget/root_view_unittest.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "ui/views/widget/root_view.h"
|
|
|
| +#include "ui/events/event_utils.h"
|
| #include "ui/views/context_menu_controller.h"
|
| #include "ui/views/test/views_test_base.h"
|
| #include "ui/views/view_targeter.h"
|
| @@ -337,5 +338,67 @@ TEST_F(RootViewTest, ContextMenuFromLongPressOnDisabledView) {
|
| EXPECT_EQ(0, controller.show_context_menu_calls());
|
| }
|
|
|
| +// This view class provides functionality to delete itself in the context of
|
| +// mouse exit event and helps test that we don't crash when we return from
|
| +// the mouse exit handler.
|
| +class DeleteViewOnMouseExit : public View {
|
| + public:
|
| + explicit DeleteViewOnMouseExit(bool* got_mouse_exit)
|
| + : got_mouse_exit_(got_mouse_exit) {
|
| + }
|
| +
|
| + ~DeleteViewOnMouseExit() override {}
|
| +
|
| + void OnMouseExited(const ui::MouseEvent& event) override {
|
| + *got_mouse_exit_ = true;
|
| + delete this;
|
| + }
|
| +
|
| + private:
|
| + // Set to true in OnMouseExited().
|
| + bool* got_mouse_exit_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DeleteViewOnMouseExit);
|
| +};
|
| +
|
| +// Verifies deleting a View in OnMouseExited() doesn't crash.
|
| +TEST_F(RootViewTest, DeleteViewOnMouseExitDispatch) {
|
| + Widget widget;
|
| + Widget::InitParams init_params =
|
| + CreateParams(Widget::InitParams::TYPE_POPUP);
|
| + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
| + widget.Init(init_params);
|
| + widget.SetBounds(gfx::Rect(10, 10, 500, 500));
|
| +
|
| + View* content = new View;
|
| + widget.SetContentsView(content);
|
| +
|
| + bool got_mouse_exit = false;
|
| + View* child = new DeleteViewOnMouseExit(&got_mouse_exit);
|
| + content->AddChildView(child);
|
| + child->SetBounds(10, 10, 500, 500);
|
| +
|
| + internal::RootView* root_view =
|
| + static_cast<internal::RootView*>(widget.GetRootView());
|
| +
|
| + // Generate a mouse move event which ensures that the mouse_moved_handler_
|
| + // member is set in the RootView class.
|
| + ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(15, 15),
|
| + gfx::Point(100, 100), ui::EventTimeForNow(), 0,
|
| + 0);
|
| + root_view->OnMouseMoved(moved_event);
|
| + EXPECT_FALSE(got_mouse_exit);
|
| +
|
| + // Generate a mouse exit event which in turn will delete the child view which
|
| + // was the target of the mouse move event above. This should not crash when
|
| + // the mouse exit handler returns from the child.
|
| + ui::MouseEvent exit_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(),
|
| + ui::EventTimeForNow(), 0, 0);
|
| + root_view->OnMouseExited(exit_event);
|
| +
|
| + EXPECT_TRUE(got_mouse_exit);
|
| + EXPECT_FALSE(content->has_children());
|
| +}
|
| +
|
| } // namespace test
|
| } // namespace views
|
|
|