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