blob: 478b6381972e48087efb6cc9b1955804d87e85c9 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/controls/native/native_view_host_aura.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_targeter.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/controls/native/native_view_host_test_base.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/test/views_test_utils.h"
#include "ui/views/view.h"
#include "ui/views/view_constants_aura.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace views {
// Observer watching for window visibility and bounds change events. This is
// used to verify that the child and clipping window operations are done in the
// right order.
class NativeViewHostWindowObserver : public aura::WindowObserver {
public:
enum EventType {
EVENT_NONE,
EVENT_SHOWN,
EVENT_HIDDEN,
EVENT_BOUNDS_CHANGED,
EVENT_DESTROYED,
};
struct EventDetails {
static int id;
EventDetails(EventType event_type,
aura::Window& window,
const gfx::Rect& event_bounds)
: type(event_type), bounds(event_bounds) {
if (window.GetId() == aura::Window::kInitialId) {
window.SetId(++id);
}
window_id = window.GetId();
}
EventType type;
int window_id;
gfx::Rect bounds;
bool operator==(const EventDetails& rhs) const = default;
};
NativeViewHostWindowObserver() = default;
NativeViewHostWindowObserver(const NativeViewHostWindowObserver&) = delete;
NativeViewHostWindowObserver& operator=(const NativeViewHostWindowObserver&) =
delete;
~NativeViewHostWindowObserver() override = default;
const std::vector<EventDetails>& events() const { return events_; }
// aura::WindowObserver overrides
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
EventDetails event(visible ? EVENT_SHOWN : EVENT_HIDDEN, *window,
window->GetBoundsInRootWindow());
// Dedupe events as a single Hide() call can result in several
// notifications.
if (events_.size() == 0u || events_.back() != event) {
events_.push_back(event);
}
}
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override {
EventDetails event(EVENT_BOUNDS_CHANGED, *window,
window->GetBoundsInRootWindow());
events_.push_back(event);
}
void OnWindowDestroyed(aura::Window* window) override {
EventDetails event(EVENT_DESTROYED, *window, gfx::Rect());
events_.push_back(event);
}
private:
std::vector<EventDetails> events_;
gfx::Rect bounds_at_visibility_changed_;
};
int NativeViewHostWindowObserver::EventDetails::id = 1;
class NativeViewHostAuraTest : public test::NativeViewHostTestBase {
public:
NativeViewHostAuraTest() = default;
NativeViewHostAuraTest(const NativeViewHostAuraTest&) = delete;
NativeViewHostAuraTest& operator=(const NativeViewHostAuraTest&) = delete;
NativeViewHostAura* native_host() {
return static_cast<NativeViewHostAura*>(GetNativeWrapper());
}
Widget* child() { return child_.get(); }
aura::Window* clipping_window() {
return native_host()->clipping_window_.get();
}
void CreateHost() {
CreateTopLevel();
CreateTestingHost();
child_ = CreateChildForHost(toplevel()->GetNativeView(),
toplevel()->client_view(), new View, host());
}
// test::NativeViewHostTestBase:
void TearDown() override {
child_.reset();
test::NativeViewHostTestBase::TearDown();
}
private:
std::unique_ptr<Widget> child_;
};
// Verifies NativeViewHostAura stops observing native view on destruction.
TEST_F(NativeViewHostAuraTest, StopObservingNativeViewOnDestruct) {
CreateHost();
aura::Window* child_win = child()->GetNativeView();
NativeViewHostAura* aura_host = native_host();
EXPECT_TRUE(child_win->HasObserver(aura_host));
DestroyHost();
EXPECT_FALSE(child_win->HasObserver(aura_host));
}
// Tests that the kHostViewKey is correctly set and cleared.
TEST_F(NativeViewHostAuraTest, HostViewPropertyKey) {
// Create the NativeViewHost and attach a NativeView.
CreateHost();
aura::Window* child_win = child()->GetNativeView();
EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey));
EXPECT_EQ(host()->GetWidget()->GetNativeView(),
child_win->GetProperty(aura::client::kHostWindowKey));
EXPECT_EQ(host(), clipping_window()->GetProperty(views::kHostViewKey));
host()->Detach();
EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
EXPECT_FALSE(child_win->GetProperty(aura::client::kHostWindowKey));
EXPECT_TRUE(clipping_window()->GetProperty(views::kHostViewKey));
host()->Attach(child_win);
EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey));
EXPECT_EQ(host()->GetWidget()->GetNativeView(),
child_win->GetProperty(aura::client::kHostWindowKey));
EXPECT_EQ(host(), clipping_window()->GetProperty(views::kHostViewKey));
DestroyHost();
EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
EXPECT_FALSE(child_win->GetProperty(aura::client::kHostWindowKey));
}
// Tests that the NativeViewHost reports the cursor set on its native view.
TEST_F(NativeViewHostAuraTest, CursorForNativeView) {
CreateHost();
toplevel()->SetCursor(ui::mojom::CursorType::kHand);
child()->SetCursor(ui::mojom::CursorType::kWait);
ui::MouseEvent move_event(ui::EventType::kMouseMoved, gfx::Point(0, 0),
gfx::Point(0, 0), ui::EventTimeForNow(), 0, 0);
EXPECT_EQ(ui::mojom::CursorType::kWait, host()->GetCursor(move_event).type());
DestroyHost();
}
// Test that destroying the top level widget before destroying the attached
// NativeViewHost works correctly. Specifically the associated NVH should be
// destroyed and there shouldn't be any errors.
TEST_F(NativeViewHostAuraTest, DestroyWidget) {
ResetHostDestroyedCount();
CreateHost();
ReleaseHost();
EXPECT_EQ(0, host_destroyed_count());
DestroyTopLevel();
EXPECT_EQ(1, host_destroyed_count());
}
// Test that the fast resize path places the clipping and content windows were
// they are supposed to be.
TEST_F(NativeViewHostAuraTest, FastResizePath) {
CreateHost();
toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
// Without fast resize, the clipping window should size to the native view
// with the native view positioned at the origin of the clipping window and
// the clipping window positioned where the native view was requested.
host()->set_fast_resize(false);
native_host()->ShowWidget(5, 10, 100, 100, 100, 100);
EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(5, 10, 100, 100).ToString(),
clipping_window()->bounds().ToString());
// With fast resize, the native view should remain the same size but be
// clipped the requested size.
host()->set_fast_resize(true);
native_host()->ShowWidget(10, 25, 50, 50, 50, 50);
EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(10, 25, 50, 50).ToString(),
clipping_window()->bounds().ToString());
// Turning off fast resize should make the native view start resizing again.
host()->set_fast_resize(false);
native_host()->ShowWidget(10, 25, 50, 50, 50, 50);
EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(10, 25, 50, 50).ToString(),
clipping_window()->bounds().ToString());
DestroyHost();
}
// Test that the clipping and content windows' bounds are set to the correct
// values while the native size is not equal to the View size. During fast
// resize, the size and transform of the NativeView should not be modified.
TEST_F(NativeViewHostAuraTest, BoundsWhileScaling) {
CreateHost();
toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
EXPECT_EQ(gfx::Transform(), host()->native_view()->transform());
// Without fast resize, the clipping window should size to the native view
// with the native view positioned at the origin of the clipping window and
// the clipping window positioned where the native view was requested. The
// size of the native view should be 200x200 (so it's content will be
// shown at half-size).
host()->set_fast_resize(false);
native_host()->ShowWidget(5, 10, 100, 100, 200, 200);
EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(5, 10, 100, 100).ToString(),
clipping_window()->bounds().ToString());
gfx::Transform expected_transform;
expected_transform.Scale(0.5, 0.5);
EXPECT_EQ(expected_transform, host()->native_view()->transform());
// With fast resize, the native view should remain the same size but be
// clipped the requested size. Also, its transform should not be changed.
host()->set_fast_resize(true);
native_host()->ShowWidget(10, 25, 50, 50, 200, 200);
EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(10, 25, 50, 50).ToString(),
clipping_window()->bounds().ToString());
EXPECT_EQ(expected_transform, host()->native_view()->transform());
// Turning off fast resize should make the native view start resizing again,
// and its transform modified to show at the new quarter-size.
host()->set_fast_resize(false);
native_host()->ShowWidget(10, 25, 50, 50, 200, 200);
EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(10, 25, 50, 50).ToString(),
clipping_window()->bounds().ToString());
expected_transform = gfx::Transform();
expected_transform.Scale(0.25, 0.25);
EXPECT_EQ(expected_transform, host()->native_view()->transform());
// When the NativeView is detached, its original transform should be restored.
auto* const detached_view = host()->native_view();
host()->Detach();
EXPECT_EQ(gfx::Transform(), detached_view->transform());
// Attach it again so it's torn down with everything else at the end.
host()->Attach(detached_view);
DestroyHost();
}
// Test installing and uninstalling a clip.
TEST_F(NativeViewHostAuraTest, InstallClip) {
CreateHost();
toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
gfx::Rect client_bounds = toplevel()->client_view()->bounds();
// Without a clip, the clipping window should always be positioned at the
// requested coordinates with the native view positioned at the origin of the
// clipping window.
native_host()->ShowWidget(10, 20, 100, 100, 100, 100);
EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(10, 20, 100, 100).ToString(),
clipping_window()->bounds().ToString());
// Clip to the bottom right quarter of the native view.
native_host()->InstallClip(60 - client_bounds.x(), 70 - client_bounds.y(), 50,
50);
native_host()->ShowWidget(10, 20, 100, 100, 100, 100);
EXPECT_EQ(gfx::Rect(-50, -50, 100, 100).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(60, 70, 50, 50).ToString(),
clipping_window()->bounds().ToString());
// Clip to the center of the native view.
native_host()->InstallClip(35 - client_bounds.x(), 45 - client_bounds.y(), 50,
50);
native_host()->ShowWidget(10, 20, 100, 100, 100, 100);
EXPECT_EQ(gfx::Rect(-25, -25, 100, 100).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(35, 45, 50, 50).ToString(),
clipping_window()->bounds().ToString());
// Uninstalling the clip should make the clipping window match the native view
// again.
native_host()->UninstallClip();
native_host()->ShowWidget(10, 20, 100, 100, 100, 100);
EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
host()->native_view()->bounds().ToString());
EXPECT_EQ(gfx::Rect(10, 20, 100, 100).ToString(),
clipping_window()->bounds().ToString());
DestroyHost();
}
// Ensure native view is parented to the root window after detaching. This is
// a regression test for http://crbug.com/389261.
TEST_F(NativeViewHostAuraTest, ParentAfterDetach) {
CreateHost();
// Trigger layout so that the visibility is set to false (because the bounds
// is empty).
test::RunScheduledLayout(host());
aura::Window* child_win = child()->GetNativeView();
aura::Window* root_window = child_win->GetRootWindow();
aura::WindowTreeHost* child_win_tree_host = child_win->GetHost();
NativeViewHostWindowObserver test_observer;
child_win->AddObserver(&test_observer);
host()->Detach();
EXPECT_EQ(root_window, child_win->GetRootWindow());
EXPECT_EQ(child_win_tree_host, child_win->GetHost());
DestroyHost();
DestroyTopLevel();
// The window is detached, so no longer associated with any Widget
// hierarchy. The root window still owns it, but the test harness checks
// for orphaned windows during TearDown().
EXPECT_EQ(0u, test_observer.events().size())
<< (*test_observer.events().begin()).type;
delete child_win;
ASSERT_EQ(1u, test_observer.events().size());
EXPECT_EQ(NativeViewHostWindowObserver::EVENT_DESTROYED,
test_observer.events().back().type);
}
// Ensure the clipping window is hidden before any other operations.
// This is a regression test for http://crbug.com/388699.
TEST_F(NativeViewHostAuraTest, RemoveClippingWindowOrder) {
CreateHost();
toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
native_host()->ShowWidget(10, 20, 100, 100, 100, 100);
NativeViewHostWindowObserver test_observer;
clipping_window()->AddObserver(&test_observer);
aura::Window* child_win = child()->GetNativeView();
child_win->AddObserver(&test_observer);
host()->Detach();
ASSERT_GE(test_observer.events().size(), 1u);
EXPECT_EQ(NativeViewHostWindowObserver::EVENT_HIDDEN,
test_observer.events()[0].type);
EXPECT_EQ(clipping_window()->GetId(), test_observer.events()[0].window_id);
clipping_window()->RemoveObserver(&test_observer);
child()->GetNativeView()->RemoveObserver(&test_observer);
DestroyHost();
delete child_win; // See comments in ParentAfterDetach.
}
// Ensure the native view receives the correct bounds notification when it is
// attached. This is a regression test for https://crbug.com/399420.
TEST_F(NativeViewHostAuraTest, Attach) {
CreateHost();
host()->Detach();
child()->GetNativeView()->SetBounds(gfx::Rect(0, 0, 0, 0));
toplevel()->SetBounds(gfx::Rect(0, 0, 100, 100));
gfx::Rect client_bounds = toplevel()->client_view()->bounds();
host()->SetBoundsRect(client_bounds);
NativeViewHostWindowObserver test_observer;
child()->GetNativeView()->AddObserver(&test_observer);
host()->Attach(child()->GetNativeView());
// Visibiliity is not updated until layout happens.
test::RunScheduledLayout(host());
auto expected_bounds = client_bounds;
ASSERT_EQ(3u, test_observer.events().size());
EXPECT_EQ(NativeViewHostWindowObserver::EVENT_BOUNDS_CHANGED,
test_observer.events()[0].type);
EXPECT_EQ(child()->GetNativeView()->GetId(),
test_observer.events()[0].window_id);
EXPECT_EQ(expected_bounds.ToString(),
test_observer.events()[0].bounds.ToString());
EXPECT_EQ(NativeViewHostWindowObserver::EVENT_SHOWN,
test_observer.events()[1].type);
EXPECT_EQ(child()->GetNativeView()->GetId(),
test_observer.events()[1].window_id);
EXPECT_EQ(expected_bounds.ToString(),
test_observer.events()[1].bounds.ToString());
EXPECT_EQ(NativeViewHostWindowObserver::EVENT_SHOWN,
test_observer.events()[2].type);
EXPECT_EQ(clipping_window()->GetId(), test_observer.events()[2].window_id);
EXPECT_EQ(expected_bounds.ToString(),
test_observer.events()[2].bounds.ToString());
child()->GetNativeView()->RemoveObserver(&test_observer);
DestroyHost();
}
// Ensure the clipping window is hidden with the native view. This is a
// regression test for https://crbug.com/408877.
TEST_F(NativeViewHostAuraTest, SimpleShowAndHide) {
CreateHost();
toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
toplevel()->Show();
host()->SetBounds(10, 10, 80, 80);
EXPECT_TRUE(clipping_window()->IsVisible());
EXPECT_TRUE(child()->IsVisible());
host()->SetVisible(false);
EXPECT_FALSE(clipping_window()->IsVisible());
EXPECT_FALSE(child()->IsVisible());
DestroyHost();
DestroyTopLevel();
}
namespace {
class TestFocusChangeListener : public FocusChangeListener {
public:
explicit TestFocusChangeListener(FocusManager* focus_manager)
: focus_manager_(focus_manager) {
focus_manager_->AddFocusChangeListener(this);
}
TestFocusChangeListener(const TestFocusChangeListener&) = delete;
TestFocusChangeListener& operator=(const TestFocusChangeListener&) = delete;
~TestFocusChangeListener() override {
focus_manager_->RemoveFocusChangeListener(this);
}
int did_change_focus_count() const { return did_change_focus_count_; }
private:
// FocusChangeListener:
void OnWillChangeFocus(View* focused_before, View* focused_now) override {}
void OnDidChangeFocus(View* focused_before, View* focused_now) override {
did_change_focus_count_++;
}
raw_ptr<FocusManager> focus_manager_;
int did_change_focus_count_ = 0;
};
} // namespace
// Verifies the FocusManager is properly updated if focus is in a child widget
// that is parented to a NativeViewHost and the NativeViewHost is destroyed.
TEST_F(NativeViewHostAuraTest, FocusManagerUpdatedDuringDestruction) {
CreateTopLevel();
toplevel()->Show();
std::unique_ptr<aura::Window> window =
std::make_unique<aura::Window>(nullptr);
window->Init(ui::LAYER_NOT_DRAWN);
window->set_owned_by_parent(false);
std::unique_ptr<NativeViewHost> native_view_host =
std::make_unique<NativeViewHost>();
toplevel()->GetContentsView()->AddChildViewRaw(native_view_host.get());
auto widget_delegate_view =
std::make_unique<WidgetDelegateView>(WidgetDelegateView::CreatePassKey());
Widget::InitParams params =
CreateParams(views::Widget::InitParams::CLIENT_OWNS_WIDGET,
Widget::InitParams::TYPE_CONTROL);
// Delegate is "owned" via the view and will be deleted with it.
params.delegate = widget_delegate_view.release();
params.child = true;
params.bounds = gfx::Rect(10, 10, 100, 100);
params.parent = window.get();
std::unique_ptr<Widget> child_widget = std::make_unique<Widget>();
child_widget->Init(std::move(params));
native_view_host->Attach(window.get());
View* view1 = child_widget->GetContentsView()->AddChildView(
std::make_unique<View>()); // Owned by |child_widget|.
view1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
view1->SetBounds(0, 0, 20, 20);
child_widget->Show();
view1->RequestFocus();
EXPECT_EQ(view1, toplevel()->GetFocusManager()->GetFocusedView());
TestFocusChangeListener focus_change_listener(toplevel()->GetFocusManager());
// ~NativeViewHost() unparents |window|.
native_view_host.reset();
EXPECT_EQ(nullptr, toplevel()->GetFocusManager()->GetFocusedView());
EXPECT_EQ(1, focus_change_listener.did_change_focus_count());
child_widget.reset();
EXPECT_EQ(nullptr, toplevel()->GetFocusManager()->GetFocusedView());
}
namespace {
ui::EventTarget* GetTarget(aura::Window* window, const gfx::Point& location) {
gfx::Point root_location = location;
aura::Window::ConvertPointToTarget(window, window->GetRootWindow(),
&root_location);
ui::MouseEvent event(ui::EventType::kMouseMoved, root_location, root_location,
base::TimeTicks::Now(), 0, 0);
return window->GetHost()->dispatcher()->event_targeter()->FindTargetForEvent(
window->GetRootWindow(), &event);
}
} // namespace
TEST_F(NativeViewHostAuraTest, TopInsets) {
CreateHost();
toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
toplevel()->Show();
// The child window is placed relative to the client view. Take that into
// account.
gfx::Vector2d offset = toplevel()->client_view()->bounds().OffsetFromOrigin();
aura::Window* toplevel_window = toplevel()->GetNativeWindow();
aura::Window* child_window = child()->GetNativeWindow();
EXPECT_EQ(child_window,
GetTarget(toplevel_window, gfx::Point(1, 1) + offset));
EXPECT_EQ(child_window,
GetTarget(toplevel_window, gfx::Point(1, 11) + offset));
host()->SetHitTestTopInset(10);
EXPECT_EQ(toplevel_window, GetTarget(toplevel_window, gfx::Point(1, 1)));
EXPECT_EQ(child_window,
GetTarget(toplevel_window, gfx::Point(1, 11) + offset));
host()->SetHitTestTopInset(0);
EXPECT_EQ(child_window,
GetTarget(toplevel_window, gfx::Point(1, 1) + offset));
EXPECT_EQ(child_window,
GetTarget(toplevel_window, gfx::Point(1, 11) + offset));
DestroyHost();
DestroyTopLevel();
}
TEST_F(NativeViewHostAuraTest, WindowHiddenWhenAttached) {
std::unique_ptr<aura::Window> window =
std::make_unique<aura::Window>(nullptr);
window->Init(ui::LAYER_NOT_DRAWN);
window->set_owned_by_parent(false);
window->Show();
EXPECT_TRUE(window->TargetVisibility());
CreateTopLevel();
NativeViewHost* host = toplevel()->GetRootView()->AddChildView(
std::make_unique<NativeViewHost>());
host->SetVisible(false);
host->Attach(window.get());
// Is |host| is not visible, |window| should immediately be hidden.
EXPECT_FALSE(window->TargetVisibility());
}
TEST_F(NativeViewHostAuraTest, ClippedWindowNotResizedOnDetach) {
CreateTopLevel();
toplevel()->SetSize(gfx::Size(100, 100));
toplevel()->Show();
std::unique_ptr<aura::Window> window =
std::make_unique<aura::Window>(nullptr);
window->Init(ui::LAYER_NOT_DRAWN);
window->set_owned_by_parent(false);
window->SetBounds(gfx::Rect(0, 0, 200, 200));
window->Show();
NativeViewHost* host = toplevel()->GetRootView()->AddChildView(
std::make_unique<NativeViewHost>());
host->SetVisible(true);
host->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
host->Attach(window.get());
EXPECT_EQ(gfx::Size(200, 200), window->bounds().size());
host->Detach();
EXPECT_EQ(gfx::Size(200, 200), window->bounds().size());
}
class WidgetDelegateForShouldDescendIntoChildForEventHandling
: public WidgetDelegate {
public:
void set_window(aura::Window* window) { window_ = window; }
bool ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
const gfx::Point& location) override {
return child != window_;
}
private:
raw_ptr<aura::Window> window_ = nullptr;
};
TEST_F(NativeViewHostAuraTest, ShouldDescendIntoChildForEventHandling) {
WidgetDelegateForShouldDescendIntoChildForEventHandling widget_delegate;
CreateTopLevel(&widget_delegate);
toplevel()->SetSize(gfx::Size(200, 200));
toplevel()->Show();
std::unique_ptr<aura::Window> window =
std::make_unique<aura::Window>(nullptr);
window->Init(ui::LAYER_NOT_DRAWN);
window->set_owned_by_parent(false);
window->SetBounds(gfx::Rect(0, 0, 200, 200));
window->Show();
widget_delegate.set_window(window.get());
CreateTestingHost();
toplevel()->GetRootView()->AddChildViewRaw(host());
host()->SetVisible(true);
host()->SetBoundsRect(gfx::Rect(0, 0, 200, 200));
host()->Attach(window.get());
ui::test::EventGenerator event_generator(window->GetRootWindow());
gfx::Point press_location(100, 100);
aura::Window::ConvertPointToTarget(toplevel()->GetNativeView(),
window->GetRootWindow(), &press_location);
event_generator.MoveMouseTo(press_location);
event_generator.PressLeftButton();
// Because the delegate overrides ShouldDescendIntoChildForEventHandling()
// the NativeView does not get the event, but NativeViewHost will.
EXPECT_EQ(1, on_mouse_pressed_called_count());
widget_delegate.set_window(nullptr);
DestroyHost();
DestroyTopLevel();
}
} // namespace views