• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Embedded Framework 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 "libcef/browser/native/browser_platform_delegate_native_linux.h"
6 
7 #include "libcef/browser/browser_host_base.h"
8 #include "libcef/browser/context.h"
9 #include "libcef/browser/native/menu_runner_linux.h"
10 #include "libcef/browser/native/window_delegate_view.h"
11 #include "libcef/browser/thread_util.h"
12 
13 #include "base/no_destructor.h"
14 #include "content/browser/renderer_host/render_widget_host_impl.h"
15 #include "content/public/browser/native_web_keyboard_event.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
18 #include "ui/events/keycodes/dom/dom_key.h"
19 #include "ui/events/keycodes/dom/keycode_converter.h"
20 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
21 #include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
22 #include "ui/events/keycodes/keysym_to_unicode.h"
23 #include "ui/gfx/font_render_params.h"
24 #include "ui/views/widget/widget.h"
25 
26 #if BUILDFLAG(OZONE_PLATFORM_X11)
27 #include "libcef/browser/native/window_x11.h"
28 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
29 #endif
30 
CefBrowserPlatformDelegateNativeLinux(const CefWindowInfo & window_info,SkColor background_color)31 CefBrowserPlatformDelegateNativeLinux::CefBrowserPlatformDelegateNativeLinux(
32     const CefWindowInfo& window_info,
33     SkColor background_color)
34     : CefBrowserPlatformDelegateNativeAura(window_info, background_color),
35       host_window_created_(false),
36       window_widget_(nullptr) {}
37 
BrowserDestroyed(CefBrowserHostBase * browser)38 void CefBrowserPlatformDelegateNativeLinux::BrowserDestroyed(
39     CefBrowserHostBase* browser) {
40   CefBrowserPlatformDelegateNative::BrowserDestroyed(browser);
41 
42   if (host_window_created_) {
43     // Release the reference added in CreateHostWindow().
44     browser->Release();
45   }
46 }
47 
CreateHostWindow()48 bool CefBrowserPlatformDelegateNativeLinux::CreateHostWindow() {
49   DCHECK(!window_widget_);
50 
51   if (window_info_.bounds.width == 0)
52     window_info_.bounds.width = 800;
53   if (window_info_.bounds.height == 0)
54     window_info_.bounds.height = 600;
55 
56   gfx::Rect rect(window_info_.bounds.x, window_info_.bounds.y,
57                  window_info_.bounds.width, window_info_.bounds.height);
58 
59 #if BUILDFLAG(OZONE_PLATFORM_X11)
60   DCHECK(!window_x11_);
61 
62   x11::Window parent_window = x11::Window::None;
63   if (window_info_.parent_window != kNullWindowHandle) {
64     parent_window = static_cast<x11::Window>(window_info_.parent_window);
65   }
66 
67   // Create a new window object. It will delete itself when the associated X11
68   // window is destroyed.
69   window_x11_ =
70       new CefWindowX11(browser_, parent_window, rect,
71                        CefString(&window_info_.window_name).ToString());
72   DCHECK_NE(window_x11_->xwindow(), x11::Window::None);
73   window_info_.window =
74       static_cast<cef_window_handle_t>(window_x11_->xwindow());
75 
76   host_window_created_ = true;
77 
78   // Add a reference that will be released in BrowserDestroyed().
79   browser_->AddRef();
80 
81   CefWindowDelegateView* delegate_view = new CefWindowDelegateView(
82       GetBackgroundColor(), window_x11_->TopLevelAlwaysOnTop(),
83       GetBoundsChangedCallback());
84   delegate_view->Init(static_cast<gfx::AcceleratedWidget>(window_info_.window),
85                       web_contents_, gfx::Rect(gfx::Point(), rect.size()));
86 
87   window_widget_ = delegate_view->GetWidget();
88   window_widget_->Show();
89 
90   window_x11_->Show();
91 #endif  // BUILDFLAG(OZONE_PLATFORM_X11)
92 
93   // As an additional requirement on Linux, we must set the colors for the
94   // render widgets in webkit.
95   auto prefs = web_contents_->GetMutableRendererPrefs();
96   prefs->focus_ring_color = SkColorSetARGB(255, 229, 151, 0);
97 
98   prefs->active_selection_bg_color = SkColorSetRGB(30, 144, 255);
99   prefs->active_selection_fg_color = SK_ColorWHITE;
100   prefs->inactive_selection_bg_color = SkColorSetRGB(200, 200, 200);
101   prefs->inactive_selection_fg_color = SkColorSetRGB(50, 50, 50);
102 
103   // Set font-related attributes.
104   static const gfx::FontRenderParams params(
105       gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr));
106   prefs->should_antialias_text = params.antialiasing;
107   prefs->use_subpixel_positioning = params.subpixel_positioning;
108   prefs->hinting = params.hinting;
109   prefs->use_autohinter = params.autohinter;
110   prefs->use_bitmaps = params.use_bitmaps;
111   prefs->subpixel_rendering = params.subpixel_rendering;
112 
113   web_contents_->SyncRendererPrefs();
114 
115   return true;
116 }
117 
CloseHostWindow()118 void CefBrowserPlatformDelegateNativeLinux::CloseHostWindow() {
119 #if BUILDFLAG(OZONE_PLATFORM_X11)
120   if (window_x11_)
121     window_x11_->Close();
122 #endif
123 }
124 
GetHostWindowHandle() const125 CefWindowHandle CefBrowserPlatformDelegateNativeLinux::GetHostWindowHandle()
126     const {
127   if (windowless_handler_)
128     return windowless_handler_->GetParentWindowHandle();
129   return window_info_.window;
130 }
131 
GetWindowWidget() const132 views::Widget* CefBrowserPlatformDelegateNativeLinux::GetWindowWidget() const {
133   return window_widget_;
134 }
135 
SetFocus(bool setFocus)136 void CefBrowserPlatformDelegateNativeLinux::SetFocus(bool setFocus) {
137   if (!setFocus)
138     return;
139 
140   if (web_contents_) {
141     // Give logical focus to the RenderWidgetHostViewAura in the views
142     // hierarchy. This does not change the native keyboard focus.
143     web_contents_->Focus();
144   }
145 
146 #if BUILDFLAG(OZONE_PLATFORM_X11)
147   if (window_x11_) {
148     // Give native focus to the DesktopNativeWidgetAura for the root window.
149     // Needs to be done via the ::Window so that keyboard focus is assigned
150     // correctly.
151     window_x11_->Focus();
152   }
153 #endif  // BUILDFLAG(OZONE_PLATFORM_X11)
154 }
155 
NotifyMoveOrResizeStarted()156 void CefBrowserPlatformDelegateNativeLinux::NotifyMoveOrResizeStarted() {
157   // Call the parent method to dismiss any existing popups.
158   CefBrowserPlatformDelegateNative::NotifyMoveOrResizeStarted();
159 
160   if (!web_contents_)
161     return;
162 
163 #if BUILDFLAG(OZONE_PLATFORM_X11)
164   if (!window_x11_)
165     return;
166 
167   views::DesktopWindowTreeHostLinux* tree_host = window_x11_->GetHost();
168   if (!tree_host)
169     return;
170 
171   // Explicitly set the screen bounds so that WindowTreeHost::*Screen()
172   // methods return the correct results.
173   const gfx::Rect& bounds = window_x11_->GetBoundsInScreen();
174   tree_host->set_screen_bounds(bounds);
175 
176   // Send updated screen rectangle information to the renderer process so that
177   // popups are displayed in the correct location.
178   content::RenderWidgetHostImpl::From(
179       web_contents_->GetRenderViewHost()->GetWidget())
180       ->SendScreenRects();
181 #endif  // BUILDFLAG(OZONE_PLATFORM_X11)
182 }
183 
SizeTo(int width,int height)184 void CefBrowserPlatformDelegateNativeLinux::SizeTo(int width, int height) {
185 #if BUILDFLAG(OZONE_PLATFORM_X11)
186   if (window_x11_) {
187     window_x11_->SetBounds(
188         gfx::Rect(window_x11_->bounds().origin(), gfx::Size(width, height)));
189   }
190 #endif  // BUILDFLAG(OZONE_PLATFORM_X11)
191 }
192 
GetScreenPoint(const gfx::Point & view) const193 gfx::Point CefBrowserPlatformDelegateNativeLinux::GetScreenPoint(
194     const gfx::Point& view) const {
195   if (windowless_handler_)
196     return windowless_handler_->GetParentScreenPoint(view);
197 
198 #if BUILDFLAG(OZONE_PLATFORM_X11)
199   if (!window_x11_)
200     return view;
201 
202   // We can't use aura::Window::GetBoundsInScreen on Linux because it will
203   // return bounds from DesktopWindowTreeHostLinux which in our case is relative
204   // to the parent window instead of the root window (screen).
205   const gfx::Rect& bounds_in_screen = window_x11_->GetBoundsInScreen();
206   return gfx::Point(bounds_in_screen.x() + view.x(),
207                     bounds_in_screen.y() + view.y());
208 #else  // !BUILDFLAG(OZONE_PLATFORM_X11)
209   return gfx::Point();
210 #endif
211 }
212 
ViewText(const std::string & text)213 void CefBrowserPlatformDelegateNativeLinux::ViewText(const std::string& text) {
214   char buff[] = "/tmp/CEFSourceXXXXXX";
215   int fd = mkstemp(buff);
216 
217   if (fd == -1)
218     return;
219 
220   FILE* srcOutput = fdopen(fd, "w+");
221   if (!srcOutput)
222     return;
223 
224   if (fputs(text.c_str(), srcOutput) < 0) {
225     fclose(srcOutput);
226     return;
227   }
228 
229   fclose(srcOutput);
230 
231   std::string newName(buff);
232   newName.append(".txt");
233   if (rename(buff, newName.c_str()) != 0)
234     return;
235 
236   std::string openCommand("xdg-open ");
237   openCommand += newName;
238 
239   int result = system(openCommand.c_str());
240   ALLOW_UNUSED_LOCAL(result);
241 }
242 
HandleKeyboardEvent(const content::NativeWebKeyboardEvent & event)243 bool CefBrowserPlatformDelegateNativeLinux::HandleKeyboardEvent(
244     const content::NativeWebKeyboardEvent& event) {
245   // TODO(cef): Is something required here to handle shortcut keys?
246   return false;
247 }
248 
249 // static
HandleExternalProtocol(const GURL & url)250 void CefBrowserPlatformDelegate::HandleExternalProtocol(const GURL& url) {}
251 
GetEventHandle(const content::NativeWebKeyboardEvent & event) const252 CefEventHandle CefBrowserPlatformDelegateNativeLinux::GetEventHandle(
253     const content::NativeWebKeyboardEvent& event) const {
254   // TODO(cef): We need to return an XEvent* from this method, but
255   // |event.os_event->native_event()| now returns a ui::Event* instead.
256   // See https://crbug.com/965991.
257   return nullptr;
258 }
259 
260 std::unique_ptr<CefMenuRunner>
CreateMenuRunner()261 CefBrowserPlatformDelegateNativeLinux::CreateMenuRunner() {
262   return base::WrapUnique(new CefMenuRunnerLinux);
263 }
264 
GetDialogPosition(const gfx::Size & size)265 gfx::Point CefBrowserPlatformDelegateNativeLinux::GetDialogPosition(
266     const gfx::Size& size) {
267   const gfx::Size& max_size = GetMaximumDialogSize();
268   return gfx::Point((max_size.width() - size.width()) / 2,
269                     (max_size.height() - size.height()) / 2);
270 }
271 
GetMaximumDialogSize()272 gfx::Size CefBrowserPlatformDelegateNativeLinux::GetMaximumDialogSize() {
273   return GetWindowWidget()->GetWindowBoundsInScreen().size();
274 }
275 
TranslateUiKeyEvent(const CefKeyEvent & key_event) const276 ui::KeyEvent CefBrowserPlatformDelegateNativeLinux::TranslateUiKeyEvent(
277     const CefKeyEvent& key_event) const {
278   int flags = TranslateUiEventModifiers(key_event.modifiers);
279   ui::KeyboardCode key_code =
280       static_cast<ui::KeyboardCode>(key_event.windows_key_code);
281   ui::DomCode dom_code =
282       ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.native_key_code);
283   int keysym = ui::XKeysymForWindowsKeyCode(
284       key_code, !!(key_event.modifiers & EVENTFLAG_SHIFT_DOWN));
285   char16_t character = ui::GetUnicodeCharacterFromXKeySym(keysym);
286   base::TimeTicks time_stamp = GetEventTimeStamp();
287 
288   if (key_event.type == KEYEVENT_CHAR) {
289     return ui::KeyEvent(character, key_code, dom_code, flags, time_stamp);
290   }
291 
292   ui::EventType type = ui::ET_UNKNOWN;
293   switch (key_event.type) {
294     case KEYEVENT_RAWKEYDOWN:
295     case KEYEVENT_KEYDOWN:
296       type = ui::ET_KEY_PRESSED;
297       break;
298     case KEYEVENT_KEYUP:
299       type = ui::ET_KEY_RELEASED;
300       break;
301     default:
302       NOTREACHED();
303   }
304 
305   ui::DomKey dom_key = ui::XKeySymToDomKey(keysym, character);
306   return ui::KeyEvent(type, key_code, dom_code, flags, dom_key, time_stamp);
307 }
308 
309 content::NativeWebKeyboardEvent
TranslateWebKeyEvent(const CefKeyEvent & key_event) const310 CefBrowserPlatformDelegateNativeLinux::TranslateWebKeyEvent(
311     const CefKeyEvent& key_event) const {
312   ui::KeyEvent ui_event = TranslateUiKeyEvent(key_event);
313   if (key_event.type == KEYEVENT_CHAR) {
314     return content::NativeWebKeyboardEvent(ui_event, key_event.character);
315   }
316   return content::NativeWebKeyboardEvent(ui_event);
317 }
318