1 // Copyright 2018 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/views/window/non_client_view.h"
6
7 #include <memory>
8
9 #include "ui/views/test/views_test_base.h"
10 #include "ui/views/widget/widget_delegate.h"
11 #include "ui/views/window/client_view.h"
12 #include "ui/views/window/native_frame_view.h"
13
14 namespace views {
15 namespace test {
16
17 namespace {
18
19 class NonClientFrameTestView : public NativeFrameView {
20 public:
21 using NativeFrameView::NativeFrameView;
layout_count() const22 int layout_count() const { return layout_count_; }
23
24 // NativeFrameView:
Layout()25 void Layout() override {
26 NativeFrameView::Layout();
27 ++layout_count_;
28 }
29
30 private:
31 int layout_count_ = 0;
32 };
33
34 class ClientTestView : public ClientView {
35 public:
36 using ClientView::ClientView;
layout_count() const37 int layout_count() const { return layout_count_; }
38
39 // ClientView:
Layout()40 void Layout() override {
41 ClientView::Layout();
42 ++layout_count_;
43 }
44
45 private:
46 int layout_count_ = 0;
47 };
48
49 class TestWidgetDelegate : public WidgetDelegateView {
50 public:
51 // WidgetDelegateView:
CreateNonClientFrameView(Widget * widget)52 std::unique_ptr<NonClientFrameView> CreateNonClientFrameView(
53 Widget* widget) override {
54 return std::make_unique<NonClientFrameTestView>(widget);
55 }
56
CreateClientView(Widget * widget)57 views::ClientView* CreateClientView(Widget* widget) override {
58 return new ClientTestView(widget, this);
59 }
60 };
61
62 class NonClientViewTest : public ViewsTestBase {
63 public:
CreateParams(Widget::InitParams::Type type)64 Widget::InitParams CreateParams(Widget::InitParams::Type type) override {
65 Widget::InitParams params = ViewsTestBase::CreateParams(type);
66 params.delegate = new TestWidgetDelegate;
67 return params;
68 }
69 };
70
71 } // namespace
72
73 // Ensure Layout() is not called excessively on a ClientView when Widget bounds
74 // are changing.
TEST_F(NonClientViewTest,OnlyLayoutChildViewsOnce)75 TEST_F(NonClientViewTest, OnlyLayoutChildViewsOnce) {
76 std::unique_ptr<views::Widget> widget =
77 CreateTestWidget(Widget::InitParams::TYPE_WINDOW);
78
79 NonClientView* non_client_view = widget->non_client_view();
80 non_client_view->Layout();
81
82 auto* frame_view =
83 static_cast<NonClientFrameTestView*>(non_client_view->frame_view());
84 auto* client_view =
85 static_cast<ClientTestView*>(non_client_view->client_view());
86
87 int initial_frame_view_layouts = frame_view->layout_count();
88 int initial_client_view_layouts = client_view->layout_count();
89
90 // Make sure it does no layout when nothing has changed.
91 non_client_view->Layout();
92 EXPECT_EQ(frame_view->layout_count(), initial_frame_view_layouts);
93 EXPECT_EQ(client_view->layout_count(), initial_client_view_layouts);
94
95 // Ensure changing bounds triggers a (single) layout.
96 widget->SetBounds(gfx::Rect(0, 0, 161, 100));
97 EXPECT_EQ(frame_view->layout_count(), initial_frame_view_layouts + 1);
98 EXPECT_EQ(client_view->layout_count(), initial_client_view_layouts + 1);
99 }
100
101 } // namespace test
102 } // namespace views
103