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