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_(NULL),
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::Bind(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::Bind(&OsrWindowWin::ShowPopup, this, parent_hwnd,
162 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::Bind(&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()->SendFocusEvent(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::Bind(&OsrWindowWin::Hide, this));
212 return;
213 }
214
215 if (!browser_)
216 return;
217
218 // Remove focus from the browser.
219 browser_->GetHost()->SendFocusEvent(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::Bind(&OsrWindowWin::SetBounds, this, x, y, width,
232 height));
233 return;
234 }
235
236 if (hwnd_) {
237 // Set the browser window bounds.
238 ::SetWindowPos(hwnd_, NULL, 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::Bind(&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::Bind(&OsrWindowWin::SetDeviceScaleFactor, this,
260 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(NULL);
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_ != NULL);
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_ = NULL;
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::Bind(&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 = NULL;
375 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
376 wcex.hbrBackground = background_brush;
377 wcex.lpszMenuName = NULL;
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, NULL);
556 self->hwnd_ = NULL;
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()->SendFocusEvent(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 // 2 Either CTRL key is pressed.
805 // 4 Either ALT key is pressed.
806 SHORT scan_res = ::VkKeyScanExW(wParam, current_layout);
807 if (((scan_res >> 8) & 0xFF) == (2 | 4)) { // ctrl-alt pressed
808 event.modifiers &= ~(EVENTFLAG_CONTROL_DOWN | EVENTFLAG_ALT_DOWN);
809 event.modifiers |= EVENTFLAG_ALTGR_DOWN;
810 }
811 }
812
813 browser_->GetHost()->SendKeyEvent(event);
814 }
815
OnPaint()816 void OsrWindowWin::OnPaint() {
817 // Paint nothing here. Invalidate will cause OnPaint to be called for the
818 // render handler.
819 PAINTSTRUCT ps;
820 BeginPaint(hwnd_, &ps);
821 EndPaint(hwnd_, &ps);
822
823 if (browser_)
824 browser_->GetHost()->Invalidate(PET_VIEW);
825 }
826
OnEraseBkgnd()827 bool OsrWindowWin::OnEraseBkgnd() {
828 // Erase the background when the browser does not exist.
829 return (browser_ == nullptr);
830 }
831
OnTouchEvent(UINT message,WPARAM wParam,LPARAM lParam)832 bool OsrWindowWin::OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam) {
833 // Handle touch events on Windows.
834 int num_points = LOWORD(wParam);
835 // Chromium only supports upto 16 touch points.
836 if (num_points < 0 || num_points > 16)
837 return false;
838 std::unique_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]);
839 if (GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(lParam), num_points,
840 input.get(), sizeof(TOUCHINPUT))) {
841 CefTouchEvent touch_event;
842 for (int i = 0; i < num_points; ++i) {
843 POINT point;
844 point.x = TOUCH_COORD_TO_PIXEL(input[i].x);
845 point.y = TOUCH_COORD_TO_PIXEL(input[i].y);
846
847 if (!IsWindows_8_Or_Newer()) {
848 // Windows 7 sends touch events for touches in the non-client area,
849 // whereas Windows 8 does not. In order to unify the behaviour, always
850 // ignore touch events in the non-client area.
851 LPARAM l_param_ht = MAKELPARAM(point.x, point.y);
852 LRESULT hittest = SendMessage(hwnd_, WM_NCHITTEST, 0, l_param_ht);
853 if (hittest != HTCLIENT)
854 return false;
855 }
856
857 ScreenToClient(hwnd_, &point);
858 touch_event.x = DeviceToLogical(point.x, device_scale_factor_);
859 touch_event.y = DeviceToLogical(point.y, device_scale_factor_);
860
861 // Touch point identifier stays consistent in a touch contact sequence
862 touch_event.id = input[i].dwID;
863
864 if (input[i].dwFlags & TOUCHEVENTF_DOWN) {
865 touch_event.type = CEF_TET_PRESSED;
866 } else if (input[i].dwFlags & TOUCHEVENTF_MOVE) {
867 touch_event.type = CEF_TET_MOVED;
868 } else if (input[i].dwFlags & TOUCHEVENTF_UP) {
869 touch_event.type = CEF_TET_RELEASED;
870 }
871
872 touch_event.radius_x = 0;
873 touch_event.radius_y = 0;
874 touch_event.rotation_angle = 0;
875 touch_event.pressure = 0;
876 touch_event.modifiers = 0;
877
878 // Notify the browser of touch event
879 if (browser_)
880 browser_->GetHost()->SendTouchEvent(touch_event);
881 }
882 CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(lParam));
883 return true;
884 }
885
886 return false;
887 }
888
IsOverPopupWidget(int x,int y) const889 bool OsrWindowWin::IsOverPopupWidget(int x, int y) const {
890 if (!render_handler_)
891 return false;
892 return render_handler_->IsOverPopupWidget(x, y);
893 }
894
GetPopupXOffset() const895 int OsrWindowWin::GetPopupXOffset() const {
896 return render_handler_->GetPopupXOffset();
897 }
898
GetPopupYOffset() const899 int OsrWindowWin::GetPopupYOffset() const {
900 return render_handler_->GetPopupYOffset();
901 }
902
ApplyPopupOffset(int & x,int & y) const903 void OsrWindowWin::ApplyPopupOffset(int& x, int& y) const {
904 if (IsOverPopupWidget(x, y)) {
905 x += GetPopupXOffset();
906 y += GetPopupYOffset();
907 }
908 }
909
OnAfterCreated(CefRefPtr<CefBrowser> browser)910 void OsrWindowWin::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
911 CEF_REQUIRE_UI_THREAD();
912 DCHECK(!browser_);
913 browser_ = browser;
914
915 if (hwnd_) {
916 // The native window will already exist for non-popup browsers.
917 EnsureRenderHandler();
918 render_handler_->SetBrowser(browser);
919 }
920
921 if (hwnd_) {
922 // Show the browser window. Called asynchronously so that the browser has
923 // time to create associated internal objects.
924 CefPostTask(TID_UI, base::Bind(&OsrWindowWin::Show, this));
925 }
926 }
927
OnBeforeClose(CefRefPtr<CefBrowser> browser)928 void OsrWindowWin::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
929 CEF_REQUIRE_UI_THREAD();
930 // Detach |this| from the ClientHandlerOsr.
931 static_cast<ClientHandlerOsr*>(browser_->GetHost()->GetClient().get())
932 ->DetachOsrDelegate();
933 browser_ = nullptr;
934 render_handler_->SetBrowser(nullptr);
935 Destroy();
936 }
937
GetRootScreenRect(CefRefPtr<CefBrowser> browser,CefRect & rect)938 bool OsrWindowWin::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
939 CefRect& rect) {
940 CEF_REQUIRE_UI_THREAD();
941 return false;
942 }
943
GetViewRect(CefRefPtr<CefBrowser> browser,CefRect & rect)944 void OsrWindowWin::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) {
945 CEF_REQUIRE_UI_THREAD();
946 DCHECK_GT(device_scale_factor_, 0);
947
948 rect.x = rect.y = 0;
949 rect.width = DeviceToLogical(client_rect_.right - client_rect_.left,
950 device_scale_factor_);
951 if (rect.width == 0)
952 rect.width = 1;
953 rect.height = DeviceToLogical(client_rect_.bottom - client_rect_.top,
954 device_scale_factor_);
955 if (rect.height == 0)
956 rect.height = 1;
957 }
958
GetScreenPoint(CefRefPtr<CefBrowser> browser,int viewX,int viewY,int & screenX,int & screenY)959 bool OsrWindowWin::GetScreenPoint(CefRefPtr<CefBrowser> browser,
960 int viewX,
961 int viewY,
962 int& screenX,
963 int& screenY) {
964 CEF_REQUIRE_UI_THREAD();
965 DCHECK_GT(device_scale_factor_, 0);
966
967 if (!::IsWindow(hwnd_))
968 return false;
969
970 // Convert the point from view coordinates to actual screen coordinates.
971 POINT screen_pt = {LogicalToDevice(viewX, device_scale_factor_),
972 LogicalToDevice(viewY, device_scale_factor_)};
973 ClientToScreen(hwnd_, &screen_pt);
974 screenX = screen_pt.x;
975 screenY = screen_pt.y;
976 return true;
977 }
978
GetScreenInfo(CefRefPtr<CefBrowser> browser,CefScreenInfo & screen_info)979 bool OsrWindowWin::GetScreenInfo(CefRefPtr<CefBrowser> browser,
980 CefScreenInfo& screen_info) {
981 CEF_REQUIRE_UI_THREAD();
982 DCHECK_GT(device_scale_factor_, 0);
983
984 if (!::IsWindow(hwnd_))
985 return false;
986
987 CefRect view_rect;
988 GetViewRect(browser, view_rect);
989
990 screen_info.device_scale_factor = device_scale_factor_;
991
992 // The screen info rectangles are used by the renderer to create and position
993 // popups. Keep popups inside the view rectangle.
994 screen_info.rect = view_rect;
995 screen_info.available_rect = view_rect;
996 return true;
997 }
998
OnPopupShow(CefRefPtr<CefBrowser> browser,bool show)999 void OsrWindowWin::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {
1000 render_handler_->OnPopupShow(browser, show);
1001 }
1002
OnPopupSize(CefRefPtr<CefBrowser> browser,const CefRect & rect)1003 void OsrWindowWin::OnPopupSize(CefRefPtr<CefBrowser> browser,
1004 const CefRect& rect) {
1005 render_handler_->OnPopupSize(browser,
1006 LogicalToDevice(rect, device_scale_factor_));
1007 }
1008
OnPaint(CefRefPtr<CefBrowser> browser,CefRenderHandler::PaintElementType type,const CefRenderHandler::RectList & dirtyRects,const void * buffer,int width,int height)1009 void OsrWindowWin::OnPaint(CefRefPtr<CefBrowser> browser,
1010 CefRenderHandler::PaintElementType type,
1011 const CefRenderHandler::RectList& dirtyRects,
1012 const void* buffer,
1013 int width,
1014 int height) {
1015 EnsureRenderHandler();
1016 render_handler_->OnPaint(browser, type, dirtyRects, buffer, width, height);
1017 }
1018
OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,CefRenderHandler::PaintElementType type,const CefRenderHandler::RectList & dirtyRects,void * share_handle)1019 void OsrWindowWin::OnAcceleratedPaint(
1020 CefRefPtr<CefBrowser> browser,
1021 CefRenderHandler::PaintElementType type,
1022 const CefRenderHandler::RectList& dirtyRects,
1023 void* share_handle) {
1024 EnsureRenderHandler();
1025 render_handler_->OnAcceleratedPaint(browser, type, dirtyRects, share_handle);
1026 }
1027
OnCursorChange(CefRefPtr<CefBrowser> browser,CefCursorHandle cursor,cef_cursor_type_t type,const CefCursorInfo & custom_cursor_info)1028 void OsrWindowWin::OnCursorChange(CefRefPtr<CefBrowser> browser,
1029 CefCursorHandle cursor,
1030 cef_cursor_type_t type,
1031 const CefCursorInfo& custom_cursor_info) {
1032 CEF_REQUIRE_UI_THREAD();
1033
1034 if (!::IsWindow(hwnd_))
1035 return;
1036
1037 // Change the plugin window's cursor.
1038 SetClassLongPtr(hwnd_, GCLP_HCURSOR,
1039 static_cast<LONG>(reinterpret_cast<LONG_PTR>(cursor)));
1040 SetCursor(cursor);
1041 }
1042
StartDragging(CefRefPtr<CefBrowser> browser,CefRefPtr<CefDragData> drag_data,CefRenderHandler::DragOperationsMask allowed_ops,int x,int y)1043 bool OsrWindowWin::StartDragging(
1044 CefRefPtr<CefBrowser> browser,
1045 CefRefPtr<CefDragData> drag_data,
1046 CefRenderHandler::DragOperationsMask allowed_ops,
1047 int x,
1048 int y) {
1049 CEF_REQUIRE_UI_THREAD();
1050
1051 #if defined(CEF_USE_ATL)
1052 if (!drop_target_)
1053 return false;
1054
1055 current_drag_op_ = DRAG_OPERATION_NONE;
1056 CefBrowserHost::DragOperationsMask result =
1057 drop_target_->StartDragging(browser, drag_data, allowed_ops, x, y);
1058 current_drag_op_ = DRAG_OPERATION_NONE;
1059 POINT pt = {};
1060 GetCursorPos(&pt);
1061 ScreenToClient(hwnd_, &pt);
1062
1063 browser->GetHost()->DragSourceEndedAt(
1064 DeviceToLogical(pt.x, device_scale_factor_),
1065 DeviceToLogical(pt.y, device_scale_factor_), result);
1066 browser->GetHost()->DragSourceSystemDragEnded();
1067 return true;
1068 #else
1069 // Cancel the drag. The dragging implementation requires ATL support.
1070 return false;
1071 #endif
1072 }
1073
UpdateDragCursor(CefRefPtr<CefBrowser> browser,CefRenderHandler::DragOperation operation)1074 void OsrWindowWin::UpdateDragCursor(CefRefPtr<CefBrowser> browser,
1075 CefRenderHandler::DragOperation operation) {
1076 CEF_REQUIRE_UI_THREAD();
1077
1078 #if defined(CEF_USE_ATL)
1079 current_drag_op_ = operation;
1080 #endif
1081 }
1082
OnImeCompositionRangeChanged(CefRefPtr<CefBrowser> browser,const CefRange & selection_range,const CefRenderHandler::RectList & character_bounds)1083 void OsrWindowWin::OnImeCompositionRangeChanged(
1084 CefRefPtr<CefBrowser> browser,
1085 const CefRange& selection_range,
1086 const CefRenderHandler::RectList& character_bounds) {
1087 CEF_REQUIRE_UI_THREAD();
1088
1089 if (ime_handler_) {
1090 // Convert from view coordinates to device coordinates.
1091 CefRenderHandler::RectList device_bounds;
1092 CefRenderHandler::RectList::const_iterator it = character_bounds.begin();
1093 for (; it != character_bounds.end(); ++it) {
1094 device_bounds.push_back(LogicalToDevice(*it, device_scale_factor_));
1095 }
1096
1097 ime_handler_->ChangeCompositionRange(selection_range, device_bounds);
1098 }
1099 }
1100
UpdateAccessibilityTree(CefRefPtr<CefValue> value)1101 void OsrWindowWin::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
1102 CEF_REQUIRE_UI_THREAD();
1103
1104 #if defined(CEF_USE_ATL)
1105 if (!accessibility_handler_) {
1106 accessibility_handler_.reset(new OsrAccessibilityHelper(value, browser_));
1107 } else {
1108 accessibility_handler_->UpdateAccessibilityTree(value);
1109 }
1110
1111 // Update |accessibility_root_| because UpdateAccessibilityTree may have
1112 // cleared it.
1113 OsrAXNode* root = accessibility_handler_->GetRootNode();
1114 accessibility_root_ =
1115 root ? root->GetNativeAccessibleObject(nullptr) : nullptr;
1116 #endif // defined(CEF_USE_ATL)
1117 }
1118
UpdateAccessibilityLocation(CefRefPtr<CefValue> value)1119 void OsrWindowWin::UpdateAccessibilityLocation(CefRefPtr<CefValue> value) {
1120 CEF_REQUIRE_UI_THREAD();
1121
1122 #if defined(CEF_USE_ATL)
1123 if (accessibility_handler_) {
1124 accessibility_handler_->UpdateAccessibilityLocation(value);
1125 }
1126 #endif // defined(CEF_USE_ATL)
1127 }
1128
1129 #if defined(CEF_USE_ATL)
1130
OnDragEnter(CefRefPtr<CefDragData> drag_data,CefMouseEvent ev,CefBrowserHost::DragOperationsMask effect)1131 CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragEnter(
1132 CefRefPtr<CefDragData> drag_data,
1133 CefMouseEvent ev,
1134 CefBrowserHost::DragOperationsMask effect) {
1135 if (browser_) {
1136 DeviceToLogical(ev, device_scale_factor_);
1137 browser_->GetHost()->DragTargetDragEnter(drag_data, ev, effect);
1138 browser_->GetHost()->DragTargetDragOver(ev, effect);
1139 }
1140 return current_drag_op_;
1141 }
1142
OnDragOver(CefMouseEvent ev,CefBrowserHost::DragOperationsMask effect)1143 CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragOver(
1144 CefMouseEvent ev,
1145 CefBrowserHost::DragOperationsMask effect) {
1146 if (browser_) {
1147 DeviceToLogical(ev, device_scale_factor_);
1148 browser_->GetHost()->DragTargetDragOver(ev, effect);
1149 }
1150 return current_drag_op_;
1151 }
1152
OnDragLeave()1153 void OsrWindowWin::OnDragLeave() {
1154 if (browser_)
1155 browser_->GetHost()->DragTargetDragLeave();
1156 }
1157
OnDrop(CefMouseEvent ev,CefBrowserHost::DragOperationsMask effect)1158 CefBrowserHost::DragOperationsMask OsrWindowWin::OnDrop(
1159 CefMouseEvent ev,
1160 CefBrowserHost::DragOperationsMask effect) {
1161 if (browser_) {
1162 DeviceToLogical(ev, device_scale_factor_);
1163 browser_->GetHost()->DragTargetDragOver(ev, effect);
1164 browser_->GetHost()->DragTargetDrop(ev);
1165 }
1166 return current_drag_op_;
1167 }
1168
1169 #endif // defined(CEF_USE_ATL)
1170
EnsureRenderHandler()1171 void OsrWindowWin::EnsureRenderHandler() {
1172 CEF_REQUIRE_UI_THREAD();
1173 if (!render_handler_) {
1174 if (settings_.shared_texture_enabled) {
1175 // Try to initialize D3D11 rendering.
1176 auto render_handler = new OsrRenderHandlerWinD3D11(settings_, hwnd_);
1177 if (render_handler->Initialize(browser_,
1178 client_rect_.right - client_rect_.left,
1179 client_rect_.bottom - client_rect_.top)) {
1180 render_handler_.reset(render_handler);
1181 } else {
1182 LOG(ERROR) << "Failed to initialize D3D11 rendering.";
1183 delete render_handler;
1184 }
1185 }
1186
1187 // Fall back to GL rendering.
1188 if (!render_handler_) {
1189 auto render_handler = new OsrRenderHandlerWinGL(settings_, hwnd_);
1190 render_handler->Initialize(browser_);
1191 render_handler_.reset(render_handler);
1192 }
1193 }
1194 }
1195
1196 } // namespace client
1197