• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "tests/cefclient/browser/osr_window_win.h"
6 
7 #include <windowsx.h>
8 #if defined(CEF_USE_ATL)
9 #include <oleacc.h>
10 #endif
11 
12 #include "include/base/cef_build.h"
13 #include "tests/cefclient/browser/main_context.h"
14 #include "tests/cefclient/browser/osr_accessibility_helper.h"
15 #include "tests/cefclient/browser/osr_accessibility_node.h"
16 #include "tests/cefclient/browser/osr_ime_handler_win.h"
17 #include "tests/cefclient/browser/osr_render_handler_win_d3d11.h"
18 #include "tests/cefclient/browser/osr_render_handler_win_gl.h"
19 #include "tests/cefclient/browser/resource.h"
20 #include "tests/shared/browser/geometry_util.h"
21 #include "tests/shared/browser/main_message_loop.h"
22 #include "tests/shared/browser/util_win.h"
23 
24 namespace client {
25 
26 namespace {
27 
28 const wchar_t kWndClass[] = L"Client_OsrWindow";
29 
30 // Helper funtion to check if it is Windows8 or greater.
31 // https://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
IsWindows_8_Or_Newer()32 inline BOOL IsWindows_8_Or_Newer() {
33   OSVERSIONINFOEX osvi = {0};
34   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
35   osvi.dwMajorVersion = 6;
36   osvi.dwMinorVersion = 2;
37   DWORDLONG dwlConditionMask = 0;
38   VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
39   VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
40   return ::VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION,
41                              dwlConditionMask);
42 }
43 
44 // Helper function to detect mouse messages coming from emulation of touch
45 // events. These should be ignored.
IsMouseEventFromTouch(UINT message)46 bool IsMouseEventFromTouch(UINT message) {
47 #define MOUSEEVENTF_FROMTOUCH 0xFF515700
48   return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) &&
49          (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) ==
50              MOUSEEVENTF_FROMTOUCH;
51 }
52 
53 class CreateBrowserHelper {
54  public:
CreateBrowserHelper(HWND hwnd,const RECT & rect,CefRefPtr<CefClient> handler,const std::string & url,const CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> extra_info,CefRefPtr<CefRequestContext> request_context,OsrWindowWin * osr_window_win)55   CreateBrowserHelper(HWND hwnd,
56                       const RECT& rect,
57                       CefRefPtr<CefClient> handler,
58                       const std::string& url,
59                       const CefBrowserSettings& settings,
60                       CefRefPtr<CefDictionaryValue> extra_info,
61                       CefRefPtr<CefRequestContext> request_context,
62                       OsrWindowWin* osr_window_win)
63       : hwnd_(hwnd),
64         rect_(rect),
65         handler_(handler),
66         url_(url),
67         settings_(settings),
68         extra_info_(extra_info),
69         request_context_(request_context),
70         osr_window_win_(osr_window_win) {}
71 
72   HWND hwnd_;
73   RECT rect_;
74   CefRefPtr<CefClient> handler_;
75   std::string url_;
76   CefBrowserSettings settings_;
77   CefRefPtr<CefDictionaryValue> extra_info_;
78   CefRefPtr<CefRequestContext> request_context_;
79   OsrWindowWin* osr_window_win_;
80 };
81 
82 }  // namespace
83 
OsrWindowWin(Delegate * delegate,const OsrRendererSettings & settings)84 OsrWindowWin::OsrWindowWin(Delegate* delegate,
85                            const OsrRendererSettings& settings)
86     : delegate_(delegate),
87       settings_(settings),
88       hwnd_(nullptr),
89       device_scale_factor_(0),
90       hidden_(false),
91       last_mouse_pos_(),
92       current_mouse_pos_(),
93       mouse_rotation_(false),
94       mouse_tracking_(false),
95       last_click_x_(0),
96       last_click_y_(0),
97       last_click_button_(MBT_LEFT),
98       last_click_count_(1),
99       last_click_time_(0),
100       last_mouse_down_on_view_(false) {
101   DCHECK(delegate_);
102   client_rect_ = {0};
103 }
104 
~OsrWindowWin()105 OsrWindowWin::~OsrWindowWin() {
106   CEF_REQUIRE_UI_THREAD();
107   // The native window should have already been destroyed.
108   DCHECK(!hwnd_ && !render_handler_.get());
109 }
110 
CreateBrowserWithHelper(CreateBrowserHelper * helper)111 void CreateBrowserWithHelper(CreateBrowserHelper* helper) {
112   helper->osr_window_win_->CreateBrowser(
113       helper->hwnd_, helper->rect_, helper->handler_, helper->settings_,
114       helper->extra_info_, helper->request_context_, helper->url_);
115   delete helper;
116 }
117 
CreateBrowser(HWND parent_hwnd,const RECT & rect,CefRefPtr<CefClient> handler,const CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> extra_info,CefRefPtr<CefRequestContext> request_context,const std::string & startup_url)118 void OsrWindowWin::CreateBrowser(HWND parent_hwnd,
119                                  const RECT& rect,
120                                  CefRefPtr<CefClient> handler,
121                                  const CefBrowserSettings& settings,
122                                  CefRefPtr<CefDictionaryValue> extra_info,
123                                  CefRefPtr<CefRequestContext> request_context,
124                                  const std::string& startup_url) {
125   if (!CefCurrentlyOn(TID_UI)) {
126     // Execute this method on the UI thread.
127     CreateBrowserHelper* helper =
128         new CreateBrowserHelper(parent_hwnd, rect, handler, startup_url,
129                                 settings, extra_info, request_context, this);
130     CefPostTask(TID_UI, base::BindOnce(CreateBrowserWithHelper, helper));
131     return;
132   }
133 
134   // Create the native window.
135   Create(parent_hwnd, rect);
136 
137   CefWindowInfo window_info;
138   window_info.SetAsWindowless(hwnd_);
139 
140   if (GetWindowLongPtr(parent_hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
141     // Don't activate the browser window on creation.
142     window_info.ex_style |= WS_EX_NOACTIVATE;
143   }
144 
145   window_info.shared_texture_enabled = settings_.shared_texture_enabled;
146   window_info.external_begin_frame_enabled =
147       settings_.external_begin_frame_enabled;
148 
149   // Create the browser asynchronously.
150   CefBrowserHost::CreateBrowser(window_info, handler, startup_url, settings,
151                                 extra_info, request_context);
152 }
153 
ShowPopup(HWND parent_hwnd,int x,int y,size_t width,size_t height)154 void OsrWindowWin::ShowPopup(HWND parent_hwnd,
155                              int x,
156                              int y,
157                              size_t width,
158                              size_t height) {
159   if (!CefCurrentlyOn(TID_UI)) {
160     // Execute this method on the UI thread.
161     CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::ShowPopup, this,
162                                        parent_hwnd, x, y, width, height));
163     return;
164   }
165 
166   DCHECK(browser_.get());
167 
168   // Create the native window.
169   const RECT rect = {x, y, x + static_cast<int>(width),
170                      y + static_cast<int>(height)};
171   Create(parent_hwnd, rect);
172 
173   // Create the render handler.
174   EnsureRenderHandler();
175   render_handler_->SetBrowser(browser_);
176 
177   // Send resize notification so the compositor is assigned the correct
178   // viewport size and begins rendering.
179   browser_->GetHost()->WasResized();
180 
181   Show();
182 }
183 
Show()184 void OsrWindowWin::Show() {
185   if (!CefCurrentlyOn(TID_UI)) {
186     // Execute this method on the UI thread.
187     CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::Show, this));
188     return;
189   }
190 
191   if (!browser_)
192     return;
193 
194   // Show the native window if not currently visible.
195   if (hwnd_ && !::IsWindowVisible(hwnd_))
196     ShowWindow(hwnd_, SW_SHOW);
197 
198   if (hidden_) {
199     // Set the browser as visible.
200     browser_->GetHost()->WasHidden(false);
201     hidden_ = false;
202   }
203 
204   // Give focus to the browser.
205   browser_->GetHost()->SetFocus(true);
206 }
207 
Hide()208 void OsrWindowWin::Hide() {
209   if (!CefCurrentlyOn(TID_UI)) {
210     // Execute this method on the UI thread.
211     CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::Hide, this));
212     return;
213   }
214 
215   if (!browser_)
216     return;
217 
218   // Remove focus from the browser.
219   browser_->GetHost()->SetFocus(false);
220 
221   if (!hidden_) {
222     // Set the browser as hidden.
223     browser_->GetHost()->WasHidden(true);
224     hidden_ = true;
225   }
226 }
227 
SetBounds(int x,int y,size_t width,size_t height)228 void OsrWindowWin::SetBounds(int x, int y, size_t width, size_t height) {
229   if (!CefCurrentlyOn(TID_UI)) {
230     // Execute this method on the UI thread.
231     CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::SetBounds, this, x, y,
232                                        width, height));
233     return;
234   }
235 
236   if (hwnd_) {
237     // Set the browser window bounds.
238     ::SetWindowPos(hwnd_, nullptr, x, y, static_cast<int>(width),
239                    static_cast<int>(height), SWP_NOZORDER);
240   }
241 }
242 
SetFocus()243 void OsrWindowWin::SetFocus() {
244   if (!CefCurrentlyOn(TID_UI)) {
245     // Execute this method on the UI thread.
246     CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::SetFocus, this));
247     return;
248   }
249 
250   if (hwnd_) {
251     // Give focus to the native window.
252     ::SetFocus(hwnd_);
253   }
254 }
255 
SetDeviceScaleFactor(float device_scale_factor)256 void OsrWindowWin::SetDeviceScaleFactor(float device_scale_factor) {
257   if (!CefCurrentlyOn(TID_UI)) {
258     // Execute this method on the UI thread.
259     CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::SetDeviceScaleFactor,
260                                        this, device_scale_factor));
261     return;
262   }
263 
264   if (device_scale_factor == device_scale_factor_)
265     return;
266 
267   device_scale_factor_ = device_scale_factor;
268   if (browser_) {
269     browser_->GetHost()->NotifyScreenInfoChanged();
270     browser_->GetHost()->WasResized();
271   }
272 }
273 
Create(HWND parent_hwnd,const RECT & rect)274 void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
275   CEF_REQUIRE_UI_THREAD();
276   DCHECK(!hwnd_ && !render_handler_.get());
277   DCHECK(parent_hwnd);
278   DCHECK(!::IsRectEmpty(&rect));
279 
280   HINSTANCE hInst = ::GetModuleHandle(nullptr);
281 
282   const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
283   const HBRUSH background_brush = CreateSolidBrush(
284       RGB(CefColorGetR(background_color), CefColorGetG(background_color),
285           CefColorGetB(background_color)));
286 
287   RegisterOsrClass(hInst, background_brush);
288 
289   DWORD ex_style = 0;
290   if (GetWindowLongPtr(parent_hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
291     // Don't activate the browser window on creation.
292     ex_style |= WS_EX_NOACTIVATE;
293   }
294 
295   // Create the native window with a border so it's easier to visually identify
296   // OSR windows.
297   hwnd_ = ::CreateWindowEx(
298       ex_style, kWndClass, 0,
299       WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
300       rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
301       parent_hwnd, 0, hInst, 0);
302   CHECK(hwnd_);
303 
304   client_rect_ = rect;
305 
306   // Associate |this| with the window.
307   SetUserDataPtr(hwnd_, this);
308 
309 #if defined(CEF_USE_ATL)
310   accessibility_root_ = nullptr;
311 
312   // Create/register the drag&drop handler.
313   drop_target_ = DropTargetWin::Create(this, hwnd_);
314   HRESULT register_res = RegisterDragDrop(hwnd_, drop_target_);
315   DCHECK_EQ(register_res, S_OK);
316 #endif
317 
318   ime_handler_.reset(new OsrImeHandlerWin(hwnd_));
319 
320   // Enable Touch Events if requested
321   if (client::MainContext::Get()->TouchEventsEnabled())
322     RegisterTouchWindow(hwnd_, 0);
323 
324   // Notify the window owner.
325   NotifyNativeWindowCreated(hwnd_);
326 }
327 
Destroy()328 void OsrWindowWin::Destroy() {
329   CEF_REQUIRE_UI_THREAD();
330   DCHECK(hwnd_ != nullptr);
331 
332 #if defined(CEF_USE_ATL)
333   // Revoke/delete the drag&drop handler.
334   RevokeDragDrop(hwnd_);
335   drop_target_ = nullptr;
336 #endif
337 
338   render_handler_.reset();
339 
340   // Destroy the native window.
341   ::DestroyWindow(hwnd_);
342   ime_handler_.reset();
343   hwnd_ = nullptr;
344 }
345 
NotifyNativeWindowCreated(HWND hwnd)346 void OsrWindowWin::NotifyNativeWindowCreated(HWND hwnd) {
347   if (!CURRENTLY_ON_MAIN_THREAD()) {
348     // Execute this method on the main thread.
349     MAIN_POST_CLOSURE(
350         base::BindOnce(&OsrWindowWin::NotifyNativeWindowCreated, this, hwnd));
351     return;
352   }
353 
354   delegate_->OnOsrNativeWindowCreated(hwnd);
355 }
356 
357 // static
RegisterOsrClass(HINSTANCE hInstance,HBRUSH background_brush)358 void OsrWindowWin::RegisterOsrClass(HINSTANCE hInstance,
359                                     HBRUSH background_brush) {
360   // Only register the class one time.
361   static bool class_registered = false;
362   if (class_registered)
363     return;
364   class_registered = true;
365 
366   WNDCLASSEX wcex;
367 
368   wcex.cbSize = sizeof(WNDCLASSEX);
369   wcex.style = CS_OWNDC;
370   wcex.lpfnWndProc = OsrWndProc;
371   wcex.cbClsExtra = 0;
372   wcex.cbWndExtra = 0;
373   wcex.hInstance = hInstance;
374   wcex.hIcon = nullptr;
375   wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
376   wcex.hbrBackground = background_brush;
377   wcex.lpszMenuName = nullptr;
378   wcex.lpszClassName = kWndClass;
379   wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
380 
381   RegisterClassEx(&wcex);
382 }
383 
OnIMESetContext(UINT message,WPARAM wParam,LPARAM lParam)384 void OsrWindowWin::OnIMESetContext(UINT message, WPARAM wParam, LPARAM lParam) {
385   // We handle the IME Composition Window ourselves (but let the IME Candidates
386   // Window be handled by IME through DefWindowProc()), so clear the
387   // ISC_SHOWUICOMPOSITIONWINDOW flag:
388   lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
389   ::DefWindowProc(hwnd_, message, wParam, lParam);
390 
391   // Create Caret Window if required
392   if (ime_handler_) {
393     ime_handler_->CreateImeWindow();
394     ime_handler_->MoveImeWindow();
395   }
396 }
397 
OnIMEStartComposition()398 void OsrWindowWin::OnIMEStartComposition() {
399   if (ime_handler_) {
400     ime_handler_->CreateImeWindow();
401     ime_handler_->MoveImeWindow();
402     ime_handler_->ResetComposition();
403   }
404 }
405 
OnIMEComposition(UINT message,WPARAM wParam,LPARAM lParam)406 void OsrWindowWin::OnIMEComposition(UINT message,
407                                     WPARAM wParam,
408                                     LPARAM lParam) {
409   if (browser_ && ime_handler_) {
410     CefString cTextStr;
411     if (ime_handler_->GetResult(lParam, cTextStr)) {
412       // Send the text to the browser. The |replacement_range| and
413       // |relative_cursor_pos| params are not used on Windows, so provide
414       // default invalid values.
415       browser_->GetHost()->ImeCommitText(cTextStr,
416                                          CefRange(UINT32_MAX, UINT32_MAX), 0);
417       ime_handler_->ResetComposition();
418       // Continue reading the composition string - Japanese IMEs send both
419       // GCS_RESULTSTR and GCS_COMPSTR.
420     }
421 
422     std::vector<CefCompositionUnderline> underlines;
423     int composition_start = 0;
424 
425     if (ime_handler_->GetComposition(lParam, cTextStr, underlines,
426                                      composition_start)) {
427       // Send the composition string to the browser. The |replacement_range|
428       // param is not used on Windows, so provide a default invalid value.
429       browser_->GetHost()->ImeSetComposition(
430           cTextStr, underlines, CefRange(UINT32_MAX, UINT32_MAX),
431           CefRange(composition_start,
432                    static_cast<int>(composition_start + cTextStr.length())));
433 
434       // Update the Candidate Window position. The cursor is at the end so
435       // subtract 1. This is safe because IMM32 does not support non-zero-width
436       // in a composition. Also,  negative values are safely ignored in
437       // MoveImeWindow
438       ime_handler_->UpdateCaretPosition(composition_start - 1);
439     } else {
440       OnIMECancelCompositionEvent();
441     }
442   }
443 }
444 
OnIMECancelCompositionEvent()445 void OsrWindowWin::OnIMECancelCompositionEvent() {
446   if (browser_ && ime_handler_) {
447     browser_->GetHost()->ImeCancelComposition();
448     ime_handler_->ResetComposition();
449     ime_handler_->DestroyImeWindow();
450   }
451 }
452 
453 // static
OsrWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)454 LRESULT CALLBACK OsrWindowWin::OsrWndProc(HWND hWnd,
455                                           UINT message,
456                                           WPARAM wParam,
457                                           LPARAM lParam) {
458   CEF_REQUIRE_UI_THREAD();
459 
460   OsrWindowWin* self = GetUserDataPtr<OsrWindowWin*>(hWnd);
461   if (!self)
462     return DefWindowProc(hWnd, message, wParam, lParam);
463 
464   // We want to handle IME events before the OS does any default handling.
465   switch (message) {
466     case WM_IME_SETCONTEXT:
467       self->OnIMESetContext(message, wParam, lParam);
468       return 0;
469     case WM_IME_STARTCOMPOSITION:
470       self->OnIMEStartComposition();
471       return 0;
472     case WM_IME_COMPOSITION:
473       self->OnIMEComposition(message, wParam, lParam);
474       return 0;
475     case WM_IME_ENDCOMPOSITION:
476       self->OnIMECancelCompositionEvent();
477       // Let WTL call::DefWindowProc() and release its resources.
478       break;
479 #if defined(CEF_USE_ATL)
480     case WM_GETOBJECT: {
481       // Only the lower 32 bits of lParam are valid when checking the object id
482       // because it sometimes gets sign-extended incorrectly (but not always).
483       DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(lParam));
484 
485       // Accessibility readers will send an OBJID_CLIENT message.
486       if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
487         if (self->accessibility_root_) {
488           return LresultFromObject(
489               IID_IAccessible, wParam,
490               static_cast<IAccessible*>(self->accessibility_root_));
491         } else {
492           // Notify the renderer to enable accessibility.
493           if (self->browser_ && self->browser_->GetHost())
494             self->browser_->GetHost()->SetAccessibilityState(STATE_ENABLED);
495         }
496       }
497     } break;
498 #endif
499     case WM_LBUTTONDOWN:
500     case WM_RBUTTONDOWN:
501     case WM_MBUTTONDOWN:
502     case WM_LBUTTONUP:
503     case WM_RBUTTONUP:
504     case WM_MBUTTONUP:
505     case WM_MOUSEMOVE:
506     case WM_MOUSELEAVE:
507     case WM_MOUSEWHEEL:
508       self->OnMouseEvent(message, wParam, lParam);
509       break;
510 
511     case WM_SIZE:
512       self->OnSize();
513       break;
514 
515     case WM_SETFOCUS:
516     case WM_KILLFOCUS:
517       self->OnFocus(message == WM_SETFOCUS);
518       break;
519 
520     case WM_CAPTURECHANGED:
521     case WM_CANCELMODE:
522       self->OnCaptureLost();
523       break;
524 
525     case WM_SYSCHAR:
526     case WM_SYSKEYDOWN:
527     case WM_SYSKEYUP:
528     case WM_KEYDOWN:
529     case WM_KEYUP:
530     case WM_CHAR:
531       self->OnKeyEvent(message, wParam, lParam);
532       break;
533 
534     case WM_PAINT:
535       self->OnPaint();
536       return 0;
537 
538     case WM_ERASEBKGND:
539       if (self->OnEraseBkgnd())
540         break;
541       // Don't erase the background.
542       return 0;
543 
544     // If your application does not require Win7 support, please do consider
545     // using WM_POINTER* messages instead of WM_TOUCH. WM_POINTER are more
546     // intutive, complete and simpler to code.
547     // https://msdn.microsoft.com/en-us/library/hh454903(v=vs.85).aspx
548     case WM_TOUCH:
549       if (self->OnTouchEvent(message, wParam, lParam))
550         return 0;
551       break;
552 
553     case WM_NCDESTROY:
554       // Clear the reference to |self|.
555       SetUserDataPtr(hWnd, nullptr);
556       self->hwnd_ = nullptr;
557       break;
558   }
559 
560   return DefWindowProc(hWnd, message, wParam, lParam);
561 }
562 
OnMouseEvent(UINT message,WPARAM wParam,LPARAM lParam)563 void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
564   if (IsMouseEventFromTouch(message))
565     return;
566 
567   CefRefPtr<CefBrowserHost> browser_host;
568   if (browser_)
569     browser_host = browser_->GetHost();
570 
571   LONG currentTime = 0;
572   bool cancelPreviousClick = false;
573 
574   if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN ||
575       message == WM_MBUTTONDOWN || message == WM_MOUSEMOVE ||
576       message == WM_MOUSELEAVE) {
577     currentTime = GetMessageTime();
578     int x = GET_X_LPARAM(lParam);
579     int y = GET_Y_LPARAM(lParam);
580     cancelPreviousClick =
581         (abs(last_click_x_ - x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2)) ||
582         (abs(last_click_y_ - y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2)) ||
583         ((currentTime - last_click_time_) > GetDoubleClickTime());
584     if (cancelPreviousClick &&
585         (message == WM_MOUSEMOVE || message == WM_MOUSELEAVE)) {
586       last_click_count_ = 1;
587       last_click_x_ = 0;
588       last_click_y_ = 0;
589       last_click_time_ = 0;
590     }
591   }
592 
593   switch (message) {
594     case WM_LBUTTONDOWN:
595     case WM_RBUTTONDOWN:
596     case WM_MBUTTONDOWN: {
597       ::SetCapture(hwnd_);
598       ::SetFocus(hwnd_);
599       int x = GET_X_LPARAM(lParam);
600       int y = GET_Y_LPARAM(lParam);
601       if (wParam & MK_SHIFT) {
602         // Start rotation effect.
603         last_mouse_pos_.x = current_mouse_pos_.x = x;
604         last_mouse_pos_.y = current_mouse_pos_.y = y;
605         mouse_rotation_ = true;
606       } else {
607         CefBrowserHost::MouseButtonType btnType =
608             (message == WM_LBUTTONDOWN
609                  ? MBT_LEFT
610                  : (message == WM_RBUTTONDOWN ? MBT_RIGHT : MBT_MIDDLE));
611         if (!cancelPreviousClick && (btnType == last_click_button_)) {
612           ++last_click_count_;
613         } else {
614           last_click_count_ = 1;
615           last_click_x_ = x;
616           last_click_y_ = y;
617         }
618         last_click_time_ = currentTime;
619         last_click_button_ = btnType;
620 
621         if (browser_host) {
622           CefMouseEvent mouse_event;
623           mouse_event.x = x;
624           mouse_event.y = y;
625           last_mouse_down_on_view_ = !IsOverPopupWidget(x, y);
626           ApplyPopupOffset(mouse_event.x, mouse_event.y);
627           DeviceToLogical(mouse_event, device_scale_factor_);
628           mouse_event.modifiers = GetCefMouseModifiers(wParam);
629           browser_host->SendMouseClickEvent(mouse_event, btnType, false,
630                                             last_click_count_);
631         }
632       }
633     } break;
634 
635     case WM_LBUTTONUP:
636     case WM_RBUTTONUP:
637     case WM_MBUTTONUP:
638       if (GetCapture() == hwnd_)
639         ReleaseCapture();
640       if (mouse_rotation_) {
641         // End rotation effect.
642         mouse_rotation_ = false;
643         render_handler_->SetSpin(0, 0);
644       } else {
645         int x = GET_X_LPARAM(lParam);
646         int y = GET_Y_LPARAM(lParam);
647         CefBrowserHost::MouseButtonType btnType =
648             (message == WM_LBUTTONUP
649                  ? MBT_LEFT
650                  : (message == WM_RBUTTONUP ? MBT_RIGHT : MBT_MIDDLE));
651         if (browser_host) {
652           CefMouseEvent mouse_event;
653           mouse_event.x = x;
654           mouse_event.y = y;
655           if (last_mouse_down_on_view_ && IsOverPopupWidget(x, y) &&
656               (GetPopupXOffset() || GetPopupYOffset())) {
657             break;
658           }
659           ApplyPopupOffset(mouse_event.x, mouse_event.y);
660           DeviceToLogical(mouse_event, device_scale_factor_);
661           mouse_event.modifiers = GetCefMouseModifiers(wParam);
662           browser_host->SendMouseClickEvent(mouse_event, btnType, true,
663                                             last_click_count_);
664         }
665       }
666       break;
667 
668     case WM_MOUSEMOVE: {
669       int x = GET_X_LPARAM(lParam);
670       int y = GET_Y_LPARAM(lParam);
671       if (mouse_rotation_) {
672         // Apply rotation effect.
673         current_mouse_pos_.x = x;
674         current_mouse_pos_.y = y;
675         render_handler_->IncrementSpin(
676             current_mouse_pos_.x - last_mouse_pos_.x,
677             current_mouse_pos_.y - last_mouse_pos_.y);
678         last_mouse_pos_.x = current_mouse_pos_.x;
679         last_mouse_pos_.y = current_mouse_pos_.y;
680       } else {
681         if (!mouse_tracking_) {
682           // Start tracking mouse leave. Required for the WM_MOUSELEAVE event to
683           // be generated.
684           TRACKMOUSEEVENT tme;
685           tme.cbSize = sizeof(TRACKMOUSEEVENT);
686           tme.dwFlags = TME_LEAVE;
687           tme.hwndTrack = hwnd_;
688           TrackMouseEvent(&tme);
689           mouse_tracking_ = true;
690         }
691 
692         if (browser_host) {
693           CefMouseEvent mouse_event;
694           mouse_event.x = x;
695           mouse_event.y = y;
696           ApplyPopupOffset(mouse_event.x, mouse_event.y);
697           DeviceToLogical(mouse_event, device_scale_factor_);
698           mouse_event.modifiers = GetCefMouseModifiers(wParam);
699           browser_host->SendMouseMoveEvent(mouse_event, false);
700         }
701       }
702       break;
703     }
704 
705     case WM_MOUSELEAVE: {
706       if (mouse_tracking_) {
707         // Stop tracking mouse leave.
708         TRACKMOUSEEVENT tme;
709         tme.cbSize = sizeof(TRACKMOUSEEVENT);
710         tme.dwFlags = TME_LEAVE & TME_CANCEL;
711         tme.hwndTrack = hwnd_;
712         TrackMouseEvent(&tme);
713         mouse_tracking_ = false;
714       }
715 
716       if (browser_host) {
717         // Determine the cursor position in screen coordinates.
718         POINT p;
719         ::GetCursorPos(&p);
720         ::ScreenToClient(hwnd_, &p);
721 
722         CefMouseEvent mouse_event;
723         mouse_event.x = p.x;
724         mouse_event.y = p.y;
725         DeviceToLogical(mouse_event, device_scale_factor_);
726         mouse_event.modifiers = GetCefMouseModifiers(wParam);
727         browser_host->SendMouseMoveEvent(mouse_event, true);
728       }
729     } break;
730 
731     case WM_MOUSEWHEEL:
732       if (browser_host) {
733         POINT screen_point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
734         HWND scrolled_wnd = ::WindowFromPoint(screen_point);
735         if (scrolled_wnd != hwnd_)
736           break;
737 
738         ScreenToClient(hwnd_, &screen_point);
739         int delta = GET_WHEEL_DELTA_WPARAM(wParam);
740 
741         CefMouseEvent mouse_event;
742         mouse_event.x = screen_point.x;
743         mouse_event.y = screen_point.y;
744         ApplyPopupOffset(mouse_event.x, mouse_event.y);
745         DeviceToLogical(mouse_event, device_scale_factor_);
746         mouse_event.modifiers = GetCefMouseModifiers(wParam);
747         browser_host->SendMouseWheelEvent(mouse_event,
748                                           IsKeyDown(VK_SHIFT) ? delta : 0,
749                                           !IsKeyDown(VK_SHIFT) ? delta : 0);
750       }
751       break;
752   }
753 }
754 
OnSize()755 void OsrWindowWin::OnSize() {
756   // Keep |client_rect_| up to date.
757   ::GetClientRect(hwnd_, &client_rect_);
758 
759   if (browser_)
760     browser_->GetHost()->WasResized();
761 }
762 
OnFocus(bool setFocus)763 void OsrWindowWin::OnFocus(bool setFocus) {
764   if (browser_)
765     browser_->GetHost()->SetFocus(setFocus);
766 }
767 
OnCaptureLost()768 void OsrWindowWin::OnCaptureLost() {
769   if (mouse_rotation_)
770     return;
771 
772   if (browser_)
773     browser_->GetHost()->SendCaptureLostEvent();
774 }
775 
OnKeyEvent(UINT message,WPARAM wParam,LPARAM lParam)776 void OsrWindowWin::OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam) {
777   if (!browser_)
778     return;
779 
780   CefKeyEvent event;
781   event.windows_key_code = wParam;
782   event.native_key_code = lParam;
783   event.is_system_key = message == WM_SYSCHAR || message == WM_SYSKEYDOWN ||
784                         message == WM_SYSKEYUP;
785 
786   if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
787     event.type = KEYEVENT_RAWKEYDOWN;
788   else if (message == WM_KEYUP || message == WM_SYSKEYUP)
789     event.type = KEYEVENT_KEYUP;
790   else
791     event.type = KEYEVENT_CHAR;
792   event.modifiers = GetCefKeyboardModifiers(wParam, lParam);
793 
794   // mimic alt-gr check behaviour from
795   // src/ui/events/win/events_win_utils.cc: GetModifiersFromKeyState
796   if ((event.type == KEYEVENT_CHAR) && IsKeyDown(VK_RMENU)) {
797     // reverse AltGr detection taken from PlatformKeyMap::UsesAltGraph
798     // instead of checking all combination for ctrl-alt, just check current char
799     HKL current_layout = ::GetKeyboardLayout(0);
800 
801     // https://docs.microsoft.com/en-gb/windows/win32/api/winuser/nf-winuser-vkkeyscanexw
802     // ... high-order byte contains the shift state,
803     // which can be a combination of the following flag bits.
804     // 1 Either SHIFT key is pressed.
805     // 2 Either CTRL key is pressed.
806     // 4 Either ALT key is pressed.
807     SHORT scan_res = ::VkKeyScanExW(wParam, current_layout);
808     constexpr auto ctrlAlt = (2 | 4);
809     if (((scan_res >> 8) & ctrlAlt) == ctrlAlt) {  // ctrl-alt pressed
810       event.modifiers &= ~(EVENTFLAG_CONTROL_DOWN | EVENTFLAG_ALT_DOWN);
811       event.modifiers |= EVENTFLAG_ALTGR_DOWN;
812     }
813   }
814 
815   browser_->GetHost()->SendKeyEvent(event);
816 }
817 
OnPaint()818 void OsrWindowWin::OnPaint() {
819   // Paint nothing here. Invalidate will cause OnPaint to be called for the
820   // render handler.
821   PAINTSTRUCT ps;
822   BeginPaint(hwnd_, &ps);
823   EndPaint(hwnd_, &ps);
824 
825   if (browser_)
826     browser_->GetHost()->Invalidate(PET_VIEW);
827 }
828 
OnEraseBkgnd()829 bool OsrWindowWin::OnEraseBkgnd() {
830   // Erase the background when the browser does not exist.
831   return (browser_ == nullptr);
832 }
833 
OnTouchEvent(UINT message,WPARAM wParam,LPARAM lParam)834 bool OsrWindowWin::OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam) {
835   // Handle touch events on Windows.
836   int num_points = LOWORD(wParam);
837   // Chromium only supports upto 16 touch points.
838   if (num_points < 0 || num_points > 16)
839     return false;
840   std::unique_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]);
841   if (GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(lParam), num_points,
842                         input.get(), sizeof(TOUCHINPUT))) {
843     CefTouchEvent touch_event;
844     for (int i = 0; i < num_points; ++i) {
845       POINT point;
846       point.x = TOUCH_COORD_TO_PIXEL(input[i].x);
847       point.y = TOUCH_COORD_TO_PIXEL(input[i].y);
848 
849       if (!IsWindows_8_Or_Newer()) {
850         // Windows 7 sends touch events for touches in the non-client area,
851         // whereas Windows 8 does not. In order to unify the behaviour, always
852         // ignore touch events in the non-client area.
853         LPARAM l_param_ht = MAKELPARAM(point.x, point.y);
854         LRESULT hittest = SendMessage(hwnd_, WM_NCHITTEST, 0, l_param_ht);
855         if (hittest != HTCLIENT)
856           return false;
857       }
858 
859       ScreenToClient(hwnd_, &point);
860       touch_event.x = DeviceToLogical(point.x, device_scale_factor_);
861       touch_event.y = DeviceToLogical(point.y, device_scale_factor_);
862 
863       // Touch point identifier stays consistent in a touch contact sequence
864       touch_event.id = input[i].dwID;
865 
866       if (input[i].dwFlags & TOUCHEVENTF_DOWN) {
867         touch_event.type = CEF_TET_PRESSED;
868       } else if (input[i].dwFlags & TOUCHEVENTF_MOVE) {
869         touch_event.type = CEF_TET_MOVED;
870       } else if (input[i].dwFlags & TOUCHEVENTF_UP) {
871         touch_event.type = CEF_TET_RELEASED;
872       }
873 
874       touch_event.radius_x = 0;
875       touch_event.radius_y = 0;
876       touch_event.rotation_angle = 0;
877       touch_event.pressure = 0;
878       touch_event.modifiers = 0;
879 
880       // Notify the browser of touch event
881       if (browser_)
882         browser_->GetHost()->SendTouchEvent(touch_event);
883     }
884     CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(lParam));
885     return true;
886   }
887 
888   return false;
889 }
890 
IsOverPopupWidget(int x,int y) const891 bool OsrWindowWin::IsOverPopupWidget(int x, int y) const {
892   if (!render_handler_)
893     return false;
894   return render_handler_->IsOverPopupWidget(x, y);
895 }
896 
GetPopupXOffset() const897 int OsrWindowWin::GetPopupXOffset() const {
898   return render_handler_->GetPopupXOffset();
899 }
900 
GetPopupYOffset() const901 int OsrWindowWin::GetPopupYOffset() const {
902   return render_handler_->GetPopupYOffset();
903 }
904 
ApplyPopupOffset(int & x,int & y) const905 void OsrWindowWin::ApplyPopupOffset(int& x, int& y) const {
906   if (IsOverPopupWidget(x, y)) {
907     x += GetPopupXOffset();
908     y += GetPopupYOffset();
909   }
910 }
911 
OnAfterCreated(CefRefPtr<CefBrowser> browser)912 void OsrWindowWin::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
913   CEF_REQUIRE_UI_THREAD();
914   DCHECK(!browser_);
915   browser_ = browser;
916 
917   if (hwnd_) {
918     // The native window will already exist for non-popup browsers.
919     EnsureRenderHandler();
920     render_handler_->SetBrowser(browser);
921   }
922 
923   if (hwnd_) {
924     // Show the browser window. Called asynchronously so that the browser has
925     // time to create associated internal objects.
926     CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::Show, this));
927   }
928 }
929 
OnBeforeClose(CefRefPtr<CefBrowser> browser)930 void OsrWindowWin::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
931   CEF_REQUIRE_UI_THREAD();
932   // Detach |this| from the ClientHandlerOsr.
933   static_cast<ClientHandlerOsr*>(browser_->GetHost()->GetClient().get())
934       ->DetachOsrDelegate();
935   browser_ = nullptr;
936   render_handler_->SetBrowser(nullptr);
937   Destroy();
938 }
939 
GetRootScreenRect(CefRefPtr<CefBrowser> browser,CefRect & rect)940 bool OsrWindowWin::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
941                                      CefRect& rect) {
942   CEF_REQUIRE_UI_THREAD();
943   return false;
944 }
945 
GetViewRect(CefRefPtr<CefBrowser> browser,CefRect & rect)946 void OsrWindowWin::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) {
947   CEF_REQUIRE_UI_THREAD();
948   DCHECK_GT(device_scale_factor_, 0);
949 
950   rect.x = rect.y = 0;
951   rect.width = DeviceToLogical(client_rect_.right - client_rect_.left,
952                                device_scale_factor_);
953   if (rect.width == 0)
954     rect.width = 1;
955   rect.height = DeviceToLogical(client_rect_.bottom - client_rect_.top,
956                                 device_scale_factor_);
957   if (rect.height == 0)
958     rect.height = 1;
959 }
960 
GetScreenPoint(CefRefPtr<CefBrowser> browser,int viewX,int viewY,int & screenX,int & screenY)961 bool OsrWindowWin::GetScreenPoint(CefRefPtr<CefBrowser> browser,
962                                   int viewX,
963                                   int viewY,
964                                   int& screenX,
965                                   int& screenY) {
966   CEF_REQUIRE_UI_THREAD();
967   DCHECK_GT(device_scale_factor_, 0);
968 
969   if (!::IsWindow(hwnd_))
970     return false;
971 
972   // Convert the point from view coordinates to actual screen coordinates.
973   POINT screen_pt = {LogicalToDevice(viewX, device_scale_factor_),
974                      LogicalToDevice(viewY, device_scale_factor_)};
975   ClientToScreen(hwnd_, &screen_pt);
976   screenX = screen_pt.x;
977   screenY = screen_pt.y;
978   return true;
979 }
980 
GetScreenInfo(CefRefPtr<CefBrowser> browser,CefScreenInfo & screen_info)981 bool OsrWindowWin::GetScreenInfo(CefRefPtr<CefBrowser> browser,
982                                  CefScreenInfo& screen_info) {
983   CEF_REQUIRE_UI_THREAD();
984   DCHECK_GT(device_scale_factor_, 0);
985 
986   if (!::IsWindow(hwnd_))
987     return false;
988 
989   CefRect view_rect;
990   GetViewRect(browser, view_rect);
991 
992   screen_info.device_scale_factor = device_scale_factor_;
993 
994   // The screen info rectangles are used by the renderer to create and position
995   // popups. Keep popups inside the view rectangle.
996   screen_info.rect = view_rect;
997   screen_info.available_rect = view_rect;
998   return true;
999 }
1000 
OnPopupShow(CefRefPtr<CefBrowser> browser,bool show)1001 void OsrWindowWin::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {
1002   render_handler_->OnPopupShow(browser, show);
1003 }
1004 
OnPopupSize(CefRefPtr<CefBrowser> browser,const CefRect & rect)1005 void OsrWindowWin::OnPopupSize(CefRefPtr<CefBrowser> browser,
1006                                const CefRect& rect) {
1007   render_handler_->OnPopupSize(browser,
1008                                LogicalToDevice(rect, device_scale_factor_));
1009 }
1010 
OnPaint(CefRefPtr<CefBrowser> browser,CefRenderHandler::PaintElementType type,const CefRenderHandler::RectList & dirtyRects,const void * buffer,int width,int height)1011 void OsrWindowWin::OnPaint(CefRefPtr<CefBrowser> browser,
1012                            CefRenderHandler::PaintElementType type,
1013                            const CefRenderHandler::RectList& dirtyRects,
1014                            const void* buffer,
1015                            int width,
1016                            int height) {
1017   EnsureRenderHandler();
1018   render_handler_->OnPaint(browser, type, dirtyRects, buffer, width, height);
1019 }
1020 
OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,CefRenderHandler::PaintElementType type,const CefRenderHandler::RectList & dirtyRects,void * share_handle)1021 void OsrWindowWin::OnAcceleratedPaint(
1022     CefRefPtr<CefBrowser> browser,
1023     CefRenderHandler::PaintElementType type,
1024     const CefRenderHandler::RectList& dirtyRects,
1025     void* share_handle) {
1026   EnsureRenderHandler();
1027   render_handler_->OnAcceleratedPaint(browser, type, dirtyRects, share_handle);
1028 }
1029 
OnCursorChange(CefRefPtr<CefBrowser> browser,CefCursorHandle cursor,cef_cursor_type_t type,const CefCursorInfo & custom_cursor_info)1030 void OsrWindowWin::OnCursorChange(CefRefPtr<CefBrowser> browser,
1031                                   CefCursorHandle cursor,
1032                                   cef_cursor_type_t type,
1033                                   const CefCursorInfo& custom_cursor_info) {
1034   CEF_REQUIRE_UI_THREAD();
1035 
1036   if (!::IsWindow(hwnd_))
1037     return;
1038 
1039   // Change the plugin window's cursor.
1040   SetClassLongPtr(hwnd_, GCLP_HCURSOR,
1041                   static_cast<LONG>(reinterpret_cast<LONG_PTR>(cursor)));
1042   SetCursor(cursor);
1043 }
1044 
StartDragging(CefRefPtr<CefBrowser> browser,CefRefPtr<CefDragData> drag_data,CefRenderHandler::DragOperationsMask allowed_ops,int x,int y)1045 bool OsrWindowWin::StartDragging(
1046     CefRefPtr<CefBrowser> browser,
1047     CefRefPtr<CefDragData> drag_data,
1048     CefRenderHandler::DragOperationsMask allowed_ops,
1049     int x,
1050     int y) {
1051   CEF_REQUIRE_UI_THREAD();
1052 
1053 #if defined(CEF_USE_ATL)
1054   if (!drop_target_)
1055     return false;
1056 
1057   current_drag_op_ = DRAG_OPERATION_NONE;
1058   CefBrowserHost::DragOperationsMask result =
1059       drop_target_->StartDragging(browser, drag_data, allowed_ops, x, y);
1060   current_drag_op_ = DRAG_OPERATION_NONE;
1061   POINT pt = {};
1062   GetCursorPos(&pt);
1063   ScreenToClient(hwnd_, &pt);
1064 
1065   browser->GetHost()->DragSourceEndedAt(
1066       DeviceToLogical(pt.x, device_scale_factor_),
1067       DeviceToLogical(pt.y, device_scale_factor_), result);
1068   browser->GetHost()->DragSourceSystemDragEnded();
1069   return true;
1070 #else
1071   // Cancel the drag. The dragging implementation requires ATL support.
1072   return false;
1073 #endif
1074 }
1075 
UpdateDragCursor(CefRefPtr<CefBrowser> browser,CefRenderHandler::DragOperation operation)1076 void OsrWindowWin::UpdateDragCursor(CefRefPtr<CefBrowser> browser,
1077                                     CefRenderHandler::DragOperation operation) {
1078   CEF_REQUIRE_UI_THREAD();
1079 
1080 #if defined(CEF_USE_ATL)
1081   current_drag_op_ = operation;
1082 #endif
1083 }
1084 
OnImeCompositionRangeChanged(CefRefPtr<CefBrowser> browser,const CefRange & selection_range,const CefRenderHandler::RectList & character_bounds)1085 void OsrWindowWin::OnImeCompositionRangeChanged(
1086     CefRefPtr<CefBrowser> browser,
1087     const CefRange& selection_range,
1088     const CefRenderHandler::RectList& character_bounds) {
1089   CEF_REQUIRE_UI_THREAD();
1090 
1091   if (ime_handler_) {
1092     // Convert from view coordinates to device coordinates.
1093     CefRenderHandler::RectList device_bounds;
1094     CefRenderHandler::RectList::const_iterator it = character_bounds.begin();
1095     for (; it != character_bounds.end(); ++it) {
1096       device_bounds.push_back(LogicalToDevice(*it, device_scale_factor_));
1097     }
1098 
1099     ime_handler_->ChangeCompositionRange(selection_range, device_bounds);
1100   }
1101 }
1102 
UpdateAccessibilityTree(CefRefPtr<CefValue> value)1103 void OsrWindowWin::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
1104   CEF_REQUIRE_UI_THREAD();
1105 
1106 #if defined(CEF_USE_ATL)
1107   if (!accessibility_handler_) {
1108     accessibility_handler_.reset(new OsrAccessibilityHelper(value, browser_));
1109   } else {
1110     accessibility_handler_->UpdateAccessibilityTree(value);
1111   }
1112 
1113   // Update |accessibility_root_| because UpdateAccessibilityTree may have
1114   // cleared it.
1115   OsrAXNode* root = accessibility_handler_->GetRootNode();
1116   accessibility_root_ =
1117       root ? root->GetNativeAccessibleObject(nullptr) : nullptr;
1118 #endif  // defined(CEF_USE_ATL)
1119 }
1120 
UpdateAccessibilityLocation(CefRefPtr<CefValue> value)1121 void OsrWindowWin::UpdateAccessibilityLocation(CefRefPtr<CefValue> value) {
1122   CEF_REQUIRE_UI_THREAD();
1123 
1124 #if defined(CEF_USE_ATL)
1125   if (accessibility_handler_) {
1126     accessibility_handler_->UpdateAccessibilityLocation(value);
1127   }
1128 #endif  // defined(CEF_USE_ATL)
1129 }
1130 
1131 #if defined(CEF_USE_ATL)
1132 
OnDragEnter(CefRefPtr<CefDragData> drag_data,CefMouseEvent ev,CefBrowserHost::DragOperationsMask effect)1133 CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragEnter(
1134     CefRefPtr<CefDragData> drag_data,
1135     CefMouseEvent ev,
1136     CefBrowserHost::DragOperationsMask effect) {
1137   if (browser_) {
1138     DeviceToLogical(ev, device_scale_factor_);
1139     browser_->GetHost()->DragTargetDragEnter(drag_data, ev, effect);
1140     browser_->GetHost()->DragTargetDragOver(ev, effect);
1141   }
1142   return current_drag_op_;
1143 }
1144 
OnDragOver(CefMouseEvent ev,CefBrowserHost::DragOperationsMask effect)1145 CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragOver(
1146     CefMouseEvent ev,
1147     CefBrowserHost::DragOperationsMask effect) {
1148   if (browser_) {
1149     DeviceToLogical(ev, device_scale_factor_);
1150     browser_->GetHost()->DragTargetDragOver(ev, effect);
1151   }
1152   return current_drag_op_;
1153 }
1154 
OnDragLeave()1155 void OsrWindowWin::OnDragLeave() {
1156   if (browser_)
1157     browser_->GetHost()->DragTargetDragLeave();
1158 }
1159 
OnDrop(CefMouseEvent ev,CefBrowserHost::DragOperationsMask effect)1160 CefBrowserHost::DragOperationsMask OsrWindowWin::OnDrop(
1161     CefMouseEvent ev,
1162     CefBrowserHost::DragOperationsMask effect) {
1163   if (browser_) {
1164     DeviceToLogical(ev, device_scale_factor_);
1165     browser_->GetHost()->DragTargetDragOver(ev, effect);
1166     browser_->GetHost()->DragTargetDrop(ev);
1167   }
1168   return current_drag_op_;
1169 }
1170 
1171 #endif  // defined(CEF_USE_ATL)
1172 
EnsureRenderHandler()1173 void OsrWindowWin::EnsureRenderHandler() {
1174   CEF_REQUIRE_UI_THREAD();
1175   if (!render_handler_) {
1176     if (settings_.shared_texture_enabled) {
1177       // Try to initialize D3D11 rendering.
1178       auto render_handler = new OsrRenderHandlerWinD3D11(settings_, hwnd_);
1179       if (render_handler->Initialize(browser_,
1180                                      client_rect_.right - client_rect_.left,
1181                                      client_rect_.bottom - client_rect_.top)) {
1182         render_handler_.reset(render_handler);
1183       } else {
1184         LOG(ERROR) << "Failed to initialize D3D11 rendering.";
1185         delete render_handler;
1186       }
1187     }
1188 
1189     // Fall back to GL rendering.
1190     if (!render_handler_) {
1191       auto render_handler = new OsrRenderHandlerWinGL(settings_, hwnd_);
1192       render_handler->Initialize(browser_);
1193       render_handler_.reset(render_handler);
1194     }
1195   }
1196 }
1197 
1198 }  // namespace client
1199