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