• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be found
3 // in the LICENSE file.
4 
5 #ifndef CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
6 #define CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
7 #pragma once
8 
9 #include "include/views/cef_view.h"
10 #include "include/views/cef_view_delegate.h"
11 
12 #include "libcef/browser/thread_util.h"
13 #include "libcef/browser/views/view_util.h"
14 
15 #include "base/logging.h"
16 #include "ui/views/background.h"
17 #include "ui/views/view.h"
18 
19 // Helpers for template boiler-plate.
20 #define CEF_VIEW_VIEW_T \
21   template <class ViewsViewClass, class CefViewDelegateClass>
22 #define CEF_VIEW_VIEW_A ViewsViewClass, CefViewDelegateClass
23 #define CEF_VIEW_VIEW_D CefViewView<CEF_VIEW_VIEW_A>
24 
25 // Base template for implementing views::View-derived classes. The views::View-
26 // derived type passed to this template must provide a no-argument constructor
27 // (for example, see LabelButtonEx from basic_label_button_view.h). See comments
28 // in view_impl.h for a usage overview.
29 CEF_VIEW_VIEW_T class CefViewView : public ViewsViewClass {
30  public:
31   typedef ViewsViewClass ParentClass;
32 
33   // Should be created from CreateRootView() in a CefViewImpl-derived class.
34   // Do not call complex views::View-derived methods from a CefViewView-derived
35   // constructor as they may attempt to call back into CefViewImpl before
36   // registration has been performed. |cef_delegate| may be nullptr.
37   template <typename... Args>
CefViewView(CefViewDelegateClass * cef_delegate,Args...args)38   explicit CefViewView(CefViewDelegateClass* cef_delegate, Args... args)
39       : ParentClass(args...), cef_delegate_(cef_delegate) {}
40 
41   // Should be called from InitializeRootView() in the CefViewImpl-derived
42   // class that created this object. This method will be called after
43   // CefViewImpl registration has completed so it is safe to call complex
44   // views::View-derived methods here.
Initialize()45   virtual void Initialize() {
46     // Use our defaults instead of the Views framework defaults.
47     ParentClass::SetBackground(
48         views::CreateSolidBackground(view_util::kDefaultBackgroundColor));
49   }
50 
51   // Returns the CefViewDelegate-derived delegate associated with this view.
52   // May return nullptr.
cef_delegate()53   CefViewDelegateClass* cef_delegate() const { return cef_delegate_; }
54 
55   // Returns the CefView associated with this view. May return nullptr during
56   // CefViewImpl initialization. If callbacks to the CefViewImpl-derived class
57   // are required define an interface that the CefViewImpl-derived class can
58   // implement and pass as an unowned instance to this object's constructor (see
59   // for example CefWindowView).
GetCefView()60   CefRefPtr<CefView> GetCefView() const {
61     CefRefPtr<CefView> view = view_util::GetFor(this, false);
62     DCHECK(view);
63     return view;
64   }
65 
66   // views::View methods:
67   gfx::Size CalculatePreferredSize() const override;
68   gfx::Size GetMinimumSize() const override;
69   gfx::Size GetMaximumSize() const override;
70   int GetHeightForWidth(int w) const override;
71   void Layout() override;
72   void ViewHierarchyChanged(
73       const views::ViewHierarchyChangedDetails& details) override;
74   void AddedToWidget() override;
75   void RemovedFromWidget() override;
76   void OnFocus() override;
77   void OnBlur() override;
78 
79   // Return true if this View is expected to have a minimum size (for example,
80   // a button where the minimum size is based on the label).
HasMinimumSize()81   virtual bool HasMinimumSize() const { return false; }
82 
83  private:
84   void NotifyChildViewChanged(
85       const views::ViewHierarchyChangedDetails& details);
86   void NotifyParentViewChanged(
87       const views::ViewHierarchyChangedDetails& details);
88 
89   // Not owned by this object.
90   CefViewDelegateClass* const cef_delegate_;
91 };
92 
CalculatePreferredSize()93 CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::CalculatePreferredSize() const {
94   gfx::Size result;
95   if (cef_delegate()) {
96     CefSize cef_size = cef_delegate()->GetPreferredSize(GetCefView());
97     if (!cef_size.IsEmpty())
98       result = gfx::Size(cef_size.width, cef_size.height);
99   }
100   if (result.IsEmpty())
101     result = ParentClass::CalculatePreferredSize();
102   if (result.IsEmpty()) {
103     // Some layouts like BoxLayout expect the preferred size to be non-empty.
104     // The user may have set the size explicitly. Therefore return the current
105     // size as the preferred size.
106     result = ParentClass::size();
107   }
108   return result;
109 }
110 
GetMinimumSize()111 CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::GetMinimumSize() const {
112   gfx::Size result;
113   if (cef_delegate()) {
114     CefSize cef_size = cef_delegate()->GetMinimumSize(GetCefView());
115     if (!cef_size.IsEmpty())
116       result = gfx::Size(cef_size.width, cef_size.height);
117   }
118   // We don't want to call ParentClass::GetMinimumSize() in all cases because
119   // the default views::View implementation will call GetPreferredSize(). That
120   // may result in size() being returned which keeps the View from shrinking.
121   if (result.IsEmpty() && HasMinimumSize())
122     result = ParentClass::GetMinimumSize();
123   return result;
124 }
125 
GetMaximumSize()126 CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::GetMaximumSize() const {
127   gfx::Size result;
128   if (cef_delegate()) {
129     CefSize cef_size = cef_delegate()->GetMaximumSize(GetCefView());
130     if (!cef_size.IsEmpty())
131       result = gfx::Size(cef_size.width, cef_size.height);
132   }
133   if (result.IsEmpty())
134     result = ParentClass::GetMaximumSize();
135   return result;
136 }
137 
GetHeightForWidth(int w)138 CEF_VIEW_VIEW_T int CEF_VIEW_VIEW_D::GetHeightForWidth(int w) const {
139   int result = 0;
140   if (cef_delegate())
141     result = cef_delegate()->GetHeightForWidth(GetCefView(), w);
142   if (result == 0)
143     result = ParentClass::GetHeightForWidth(w);
144   if (result == 0) {
145     // Some layouts like FillLayout will ignore the preferred size if this view
146     // has no children. We want to use the preferred size if not otherwise
147     // specified.
148     result = ParentClass::GetPreferredSize().height();
149   }
150   return result;
151 }
152 
Layout()153 CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::Layout() {
154   ParentClass::Layout();
155 
156   // If Layout() did not provide a size then use the preferred size.
157   if (ParentClass::size().IsEmpty())
158     ParentClass::SizeToPreferredSize();
159 }
160 
ViewHierarchyChanged(const views::ViewHierarchyChangedDetails & details)161 CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::ViewHierarchyChanged(
162     const views::ViewHierarchyChangedDetails& details) {
163   NotifyChildViewChanged(details);
164   NotifyParentViewChanged(details);
165   ParentClass::ViewHierarchyChanged(details);
166 }
167 
AddedToWidget()168 CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::AddedToWidget() {
169   ParentClass::AddedToWidget();
170   if (cef_delegate())
171     cef_delegate()->OnWindowChanged(GetCefView(), /*added=*/true);
172 }
173 
RemovedFromWidget()174 CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::RemovedFromWidget() {
175   if (cef_delegate())
176     cef_delegate()->OnWindowChanged(GetCefView(), /*added=*/false);
177   ParentClass::RemovedFromWidget();
178 }
179 
OnFocus()180 CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::OnFocus() {
181   if (cef_delegate())
182     cef_delegate()->OnFocus(GetCefView());
183   ParentClass::OnFocus();
184 }
185 
OnBlur()186 CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::OnBlur() {
187   if (cef_delegate())
188     cef_delegate()->OnBlur(GetCefView());
189   ParentClass::OnBlur();
190 }
191 
NotifyChildViewChanged(const views::ViewHierarchyChangedDetails & details)192 CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyChildViewChanged(
193     const views::ViewHierarchyChangedDetails& details) {
194   if (!cef_delegate())
195     return;
196 
197   // Only interested with the parent is |this| object and the notification is
198   // about an immediate child (notifications are also sent for grandchildren).
199   if (details.parent != this || details.child->parent() != this)
200     return;
201 
202   // Only notify for children that have a known CEF root view. For example,
203   // don't notify when ScrollView adds child scroll bars.
204   CefRefPtr<CefView> child = view_util::GetFor(details.child, false);
205   if (child)
206     cef_delegate()->OnChildViewChanged(GetCefView(), details.is_add, child);
207 }
208 
NotifyParentViewChanged(const views::ViewHierarchyChangedDetails & details)209 CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyParentViewChanged(
210     const views::ViewHierarchyChangedDetails& details) {
211   if (!cef_delegate())
212     return;
213 
214   // Only interested when the child is |this| object and notification is about
215   // the immediate parent (notifications are sent for all parents).
216   if (details.child != this || details.parent != ParentClass::parent())
217     return;
218 
219   // The immediate parent might be an intermediate view so find the closest
220   // known CEF root view.
221   CefRefPtr<CefView> parent = view_util::GetFor(details.parent, true);
222   DCHECK(parent);
223   cef_delegate()->OnParentViewChanged(GetCefView(), details.is_add, parent);
224 }
225 
226 #endif  // CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
227