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