• 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 #include "libcef/browser/views/view_util.h"
6 
7 #include <utility>
8 
9 #include "libcef/browser/views/view_adapter.h"
10 
11 #include "ui/display/display.h"
12 #include "ui/display/screen.h"
13 #include "ui/gfx/geometry/point.h"
14 #include "ui/gfx/geometry/point_conversions.h"
15 #include "ui/views/widget/widget.h"
16 #include "ui/views/widget/widget_delegate.h"
17 #include "ui/views/window/non_client_view.h"
18 
19 #if BUILDFLAG(IS_WIN)
20 #include "ui/display/win/screen_win.h"
21 #endif
22 
23 #if defined(USE_AURA)
24 #include "ui/aura/window.h"
25 #include "ui/views/view_constants_aura.h"
26 #endif
27 
28 namespace view_util {
29 
30 namespace {
31 
32 // Manages the association between views::View and CefView instances.
33 class UserData : public base::SupportsUserData::Data {
34  public:
35   // Create the initial association between the views::View and the CefView. The
36   // CefView owns the views::View at this stage.
Register(CefRefPtr<CefView> cef_view)37   static void Register(CefRefPtr<CefView> cef_view) {
38     DCHECK(cef_view->IsValid());
39     DCHECK(!cef_view->IsAttached());
40 
41     views::View* view = CefViewAdapter::GetFor(cef_view)->Get();
42     DCHECK(view);
43 
44     // The CefView should not already be registered.
45     DCHECK(!view->GetUserData(UserDataKey()));
46 
47     view->SetUserData(UserDataKey(), base::WrapUnique(new UserData(cef_view)));
48   }
49 
GetFor(const views::View * view)50   static CefRefPtr<CefView> GetFor(const views::View* view) {
51     DCHECK(view);
52     UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
53     if (data)
54       return data->view_ref_;
55     return nullptr;
56   }
57 
58   // Transfer ownership of the views::View to the caller. The views::View will
59   // gain a ref-counted reference to the CefView and the CefView will keep an
60   // unowned reference to the views::View. Destruction of the views::View will
61   // release the ref-counted reference to the CefView.
PassOwnership(CefRefPtr<CefView> cef_view)62   static std::unique_ptr<views::View> PassOwnership(CefRefPtr<CefView> cef_view)
63       WARN_UNUSED_RESULT {
64     DCHECK(cef_view->IsValid());
65     DCHECK(!cef_view->IsAttached());
66 
67     std::unique_ptr<views::View> view =
68         CefViewAdapter::GetFor(cef_view)->PassOwnership();
69     DCHECK(view);
70 
71     UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
72     DCHECK(data);
73     data->TakeReference();
74 
75     return view;
76   }
77 
78   // The CefView resumes ownership of the views::View. The views::View no longer
79   // keeps a ref-counted reference to the CefView.
ResumeOwnership(CefRefPtr<CefView> cef_view)80   static void ResumeOwnership(CefRefPtr<CefView> cef_view) {
81     DCHECK(cef_view->IsValid());
82     DCHECK(cef_view->IsAttached());
83 
84     CefViewAdapter* adapter = CefViewAdapter::GetFor(cef_view);
85     adapter->ResumeOwnership();
86 
87     views::View* view = adapter->Get();
88     DCHECK(view);
89 
90     UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
91     DCHECK(data);
92     data->ReleaseReference();
93   }
94 
95  private:
96   friend std::default_delete<UserData>;
97 
UserData(CefRefPtr<CefView> cef_view)98   explicit UserData(CefRefPtr<CefView> cef_view) : view_ref_(cef_view.get()) {
99     DCHECK(view_ref_);
100   }
101 
~UserData()102   ~UserData() override {
103     if (view_) {
104       // The CefView does not own the views::View. Remove the CefView's
105       // reference to the views::View.
106       CefViewAdapter::GetFor(view_)->Detach();
107     }
108   }
109 
TakeReference()110   void TakeReference() { view_ = view_ref_; }
111 
ReleaseReference()112   void ReleaseReference() { view_ = nullptr; }
113 
UserDataKey()114   static void* UserDataKey() {
115     // We just need a unique constant. Use the address of a static that
116     // COMDAT folding won't touch in an optimizing linker.
117     static int data_key = 0;
118     return reinterpret_cast<void*>(&data_key);
119   }
120 
121   CefRefPtr<CefView> view_;
122   CefView* view_ref_;
123 };
124 
125 }  // namespace
126 
127 const SkColor kDefaultBackgroundColor = SkColorSetARGB(255, 255, 255, 255);
128 const char kDefaultFontList[] = "Arial, Helvetica, 14px";
129 
Register(CefRefPtr<CefView> view)130 void Register(CefRefPtr<CefView> view) {
131   UserData::Register(view);
132 }
133 
GetFor(const views::View * view,bool find_known_parent)134 CefRefPtr<CefView> GetFor(const views::View* view, bool find_known_parent) {
135   if (!view)
136     return nullptr;
137 
138   if (!find_known_parent)
139     return UserData::GetFor(view);
140 
141   CefRefPtr<CefView> cef_view;
142   const views::View* current_view = view;
143   do {
144     cef_view = UserData::GetFor(current_view);
145     if (cef_view)
146       break;
147     current_view = current_view->parent();
148   } while (current_view);
149 
150   return cef_view;
151 }
152 
GetFor(CefRefPtr<CefView> view)153 views::View* GetFor(CefRefPtr<CefView> view) {
154   return CefViewAdapter::GetFor(view)->Get();
155 }
156 
PassOwnership(CefRefPtr<CefView> view)157 std::unique_ptr<views::View> PassOwnership(CefRefPtr<CefView> view) {
158   return UserData::PassOwnership(view);
159 }
160 
ResumeOwnership(CefRefPtr<CefView> view)161 void ResumeOwnership(CefRefPtr<CefView> view) {
162   UserData::ResumeOwnership(view);
163 }
164 
GetWindowFor(views::Widget * widget)165 CefRefPtr<CefWindow> GetWindowFor(views::Widget* widget) {
166   CefRefPtr<CefWindow> window;
167 
168 #if defined(USE_AURA)
169   // Retrieve the parent Widget for an overlay.
170   if (widget) {
171     // See matching logic in CefOverlayViewHost::Init.
172     auto widget_view =
173         widget->GetNativeView()->GetProperty(views::kHostViewKey);
174     if (widget_view) {
175       widget = widget_view->GetWidget();
176     }
177   }
178 #endif  // defined(USE_AURA)
179 
180   if (widget) {
181     // The views::WidgetDelegate should be a CefWindowView and |content_view|
182     // should be the same CefWindowView. However, just in case the views::Widget
183     // was created by something else let's go about this the safer way.
184     views::View* content_view = widget->widget_delegate()->GetContentsView();
185     CefRefPtr<CefView> cef_view = GetFor(content_view, false);
186     if (cef_view && cef_view->AsPanel())
187       window = cef_view->AsPanel()->AsWindow();
188 
189     // The Window should always exist if we created the views::Widget.
190     DCHECK(window);
191   }
192 
193   return window;
194 }
195 
GetDisplayNearestPoint(const gfx::Point & point,bool input_pixel_coords)196 display::Display GetDisplayNearestPoint(const gfx::Point& point,
197                                         bool input_pixel_coords) {
198   gfx::Point find_point = point;
199 #if BUILDFLAG(IS_WIN)
200   if (input_pixel_coords) {
201     find_point = gfx::ToFlooredPoint(
202         display::win::ScreenWin::ScreenToDIPPoint(gfx::PointF(point)));
203   }
204 #endif
205   return display::Screen::GetScreen()->GetDisplayNearestPoint(find_point);
206 }
207 
GetDisplayMatchingBounds(const gfx::Rect & bounds,bool input_pixel_coords)208 display::Display GetDisplayMatchingBounds(const gfx::Rect& bounds,
209                                           bool input_pixel_coords) {
210   gfx::Rect find_bounds = bounds;
211 #if BUILDFLAG(IS_WIN)
212   if (input_pixel_coords) {
213     find_bounds =
214         display::win::ScreenWin::ScreenToDIPRect(nullptr, find_bounds);
215   }
216 #endif
217   return display::Screen::GetScreen()->GetDisplayMatching(find_bounds);
218 }
219 
ConvertPointFromPixels(gfx::Point * point,int device_scale_factor)220 void ConvertPointFromPixels(gfx::Point* point, int device_scale_factor) {
221   *point = gfx::ToFlooredPoint(
222       gfx::ScalePoint(gfx::PointF(*point), 1.0f / device_scale_factor));
223 }
224 
ConvertPointToPixels(gfx::Point * point,int device_scale_factor)225 void ConvertPointToPixels(gfx::Point* point, int device_scale_factor) {
226   *point = gfx::ToFlooredPoint(
227       gfx::ScalePoint(gfx::PointF(*point), device_scale_factor));
228 }
229 
ConvertPointToScreen(views::View * view,gfx::Point * point,bool output_pixel_coords)230 bool ConvertPointToScreen(views::View* view,
231                           gfx::Point* point,
232                           bool output_pixel_coords) {
233   if (!view->GetWidget())
234     return false;
235 
236   views::View::ConvertPointToScreen(view, point);
237 
238   if (output_pixel_coords) {
239     const display::Display& display = GetDisplayNearestPoint(*point, false);
240     ConvertPointToPixels(point, display.device_scale_factor());
241   }
242 
243   return true;
244 }
245 
ConvertPointFromScreen(views::View * view,gfx::Point * point,bool input_pixel_coords)246 bool ConvertPointFromScreen(views::View* view,
247                             gfx::Point* point,
248                             bool input_pixel_coords) {
249   if (!view->GetWidget())
250     return false;
251 
252   if (input_pixel_coords) {
253     const display::Display& display = GetDisplayNearestPoint(*point, true);
254     ConvertPointFromPixels(point, display.device_scale_factor());
255   }
256 
257   views::View::ConvertPointFromScreen(view, point);
258 
259   return true;
260 }
261 
ConvertPointToWindow(views::View * view,gfx::Point * point)262 bool ConvertPointToWindow(views::View* view, gfx::Point* point) {
263   views::Widget* widget = view->GetWidget();
264   if (!widget)
265     return false;
266 
267   views::View::ConvertPointToWidget(view, point);
268 
269   if (widget->non_client_view()) {
270     views::NonClientFrameView* non_client_frame_view =
271         widget->non_client_view()->frame_view();
272     if (non_client_frame_view) {
273       // When using a custom drawn NonClientFrameView the native Window will not
274       // know the actual client bounds. Adjust the native Window bounds for the
275       // reported client bounds.
276       const gfx::Rect& client_bounds =
277           non_client_frame_view->GetBoundsForClientView();
278       *point -= client_bounds.OffsetFromOrigin();
279     }
280   }
281 
282   return true;
283 }
284 
ConvertPointFromWindow(views::View * view,gfx::Point * point)285 bool ConvertPointFromWindow(views::View* view, gfx::Point* point) {
286   views::Widget* widget = view->GetWidget();
287   if (!widget)
288     return false;
289 
290   if (widget->non_client_view()) {
291     views::NonClientFrameView* non_client_frame_view =
292         widget->non_client_view()->frame_view();
293     if (non_client_frame_view) {
294       // When using a custom drawn NonClientFrameView the native Window will not
295       // know the actual client bounds. Adjust the native Window bounds for the
296       // reported client bounds.
297       const gfx::Rect& client_bounds =
298           non_client_frame_view->GetBoundsForClientView();
299       *point += client_bounds.OffsetFromOrigin();
300     }
301   }
302 
303   views::View::ConvertPointFromWidget(view, point);
304 
305   return true;
306 }
307 
308 }  // namespace view_util
309