[Win] Remove -DUCHAR_TYPE=wchar_t stopgap and learn to live with char16_t.
[WebKit-https.git] / Source / WebKit / UIProcess / win / WebView.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2017 Sony Interactive Entertainment Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "WebView.h"
29
30 #include "APIPageConfiguration.h"
31 #include "DrawingAreaProxyCoordinatedGraphics.h"
32 #include "Logging.h"
33 #include "NativeWebKeyboardEvent.h"
34 #include "NativeWebMouseEvent.h"
35 #include "NativeWebWheelEvent.h"
36 #include "WKAPICast.h"
37 #include "WebContextMenuProxyWin.h"
38 #include "WebEditCommandProxy.h"
39 #include "WebEventFactory.h"
40 #include "WebPageGroup.h"
41 #include "WebPageProxy.h"
42 #include "WebProcessPool.h"
43 #include <Commctrl.h>
44 #include <WebCore/BitmapInfo.h>
45 #include <WebCore/Cursor.h>
46 #include <WebCore/Editor.h>
47 #include <WebCore/FloatRect.h>
48 #include <WebCore/HWndDC.h>
49 #include <WebCore/IntRect.h>
50 #include <WebCore/NotImplemented.h>
51 #include <WebCore/Region.h>
52 #include <WebCore/WebCoreInstanceHandle.h>
53 #include <WebCore/WindowMessageBroadcaster.h>
54 #include <WebCore/WindowsTouch.h>
55 #include <cairo-win32.h>
56 #include <cairo.h>
57 #include <wtf/FileSystem.h>
58 #include <wtf/SoftLinking.h>
59 #include <wtf/text/StringBuffer.h>
60 #include <wtf/text/StringBuilder.h>
61 #include <wtf/text/WTFString.h>
62
63 namespace WebKit {
64 using namespace WebCore;
65
66 static const LPCWSTR kWebKit2WebViewWindowClassName = L"WebKit2WebViewWindowClass";
67
68 static const int kMaxToolTipWidth = 250;
69
70 enum {
71     UpdateActiveStateTimer = 1,
72 };
73
74 LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
75 {
76     LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0);
77
78     if (WebView* webView = reinterpret_cast<WebView*>(longPtr))
79         return webView->wndProc(hWnd, message, wParam, lParam);
80
81     if (message == WM_CREATE) {
82         LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
83
84         // Associate the WebView with the window.
85         ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams);
86         return 0;
87     }
88
89     return ::DefWindowProc(hWnd, message, wParam, lParam);
90 }
91
92 LRESULT WebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
93 {
94     LRESULT lResult = 0;
95     bool handled = true;
96
97     switch (message) {
98     case WM_CLOSE:
99         m_page->tryClose();
100         break;
101     case WM_DESTROY:
102         m_isBeingDestroyed = true;
103         close();
104         break;
105     case WM_ERASEBKGND:
106         lResult = 1;
107         break;
108     case WM_PAINT:
109         lResult = onPaintEvent(hWnd, message, wParam, lParam, handled);
110         break;
111     case WM_PRINTCLIENT:
112         lResult = onPrintClientEvent(hWnd, message, wParam, lParam, handled);
113         break;
114     case WM_MOUSEACTIVATE:
115         setWasActivatedByMouseEvent(true);
116         handled = false;
117         break;
118     case WM_MOUSEMOVE:
119     case WM_LBUTTONDOWN:
120     case WM_MBUTTONDOWN:
121     case WM_RBUTTONDOWN:
122     case WM_LBUTTONDBLCLK:
123     case WM_MBUTTONDBLCLK:
124     case WM_RBUTTONDBLCLK:
125     case WM_LBUTTONUP:
126     case WM_MBUTTONUP:
127     case WM_RBUTTONUP:
128     case WM_MOUSELEAVE:
129         lResult = onMouseEvent(hWnd, message, wParam, lParam, handled);
130         break;
131     case WM_MOUSEWHEEL:
132         lResult = onWheelEvent(hWnd, message, wParam, lParam, handled);
133         break;
134     case WM_HSCROLL:
135         lResult = onHorizontalScroll(hWnd, message, wParam, lParam, handled);
136         break;
137     case WM_VSCROLL:
138         lResult = onVerticalScroll(hWnd, message, wParam, lParam, handled);
139         break;
140     case WM_SYSKEYDOWN:
141     case WM_KEYDOWN:
142     case WM_SYSCHAR:
143     case WM_CHAR:
144     case WM_SYSKEYUP:
145     case WM_KEYUP:
146         lResult = onKeyEvent(hWnd, message, wParam, lParam, handled);
147         break;
148     case WM_SIZE:
149         lResult = onSizeEvent(hWnd, message, wParam, lParam, handled);
150         break;
151     case WM_WINDOWPOSCHANGED:
152         lResult = onWindowPositionChangedEvent(hWnd, message, wParam, lParam, handled);
153         break;
154     case WM_SETFOCUS:
155         lResult = onSetFocusEvent(hWnd, message, wParam, lParam, handled);
156         break;
157     case WM_KILLFOCUS:
158         lResult = onKillFocusEvent(hWnd, message, wParam, lParam, handled);
159         break;
160     case WM_TIMER:
161         lResult = onTimerEvent(hWnd, message, wParam, lParam, handled);
162         break;
163     case WM_SHOWWINDOW:
164         lResult = onShowWindowEvent(hWnd, message, wParam, lParam, handled);
165         break;
166     case WM_SETCURSOR:
167         lResult = onSetCursor(hWnd, message, wParam, lParam, handled);
168         break;
169     case WM_MENUCOMMAND:
170         lResult = onMenuCommand(hWnd, message, wParam, lParam, handled);
171         break;
172     default:
173         handled = false;
174         break;
175     }
176
177     if (!handled)
178         lResult = ::DefWindowProc(hWnd, message, wParam, lParam);
179
180     return lResult;
181 }
182
183 bool WebView::registerWebViewWindowClass()
184 {
185     static bool haveRegisteredWindowClass = false;
186     if (haveRegisteredWindowClass)
187         return true;
188     haveRegisteredWindowClass = true;
189
190     WNDCLASSEX wcex;
191
192     wcex.cbSize = sizeof(WNDCLASSEX);
193     wcex.style = CS_DBLCLKS;
194     wcex.lpfnWndProc = WebView::WebViewWndProc;
195     wcex.cbClsExtra = 0;
196     wcex.cbWndExtra = sizeof(WebView*);
197     wcex.hInstance = instanceHandle();
198     wcex.hIcon = 0;
199     wcex.hCursor = ::LoadCursor(0, IDC_ARROW);
200     wcex.hbrBackground = 0;
201     wcex.lpszMenuName = 0;
202     wcex.lpszClassName = kWebKit2WebViewWindowClassName;
203     wcex.hIconSm = 0;
204
205     return !!::RegisterClassEx(&wcex);
206 }
207
208 WebView::WebView(RECT rect, const API::PageConfiguration& configuration, HWND parentWindow)
209     : m_pageClient(std::make_unique<PageClientImpl>(*this))
210 {
211     registerWebViewWindowClass();
212
213     m_window = ::CreateWindowExW(0, kWebKit2WebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
214         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, parentWindow ? parentWindow : HWND_MESSAGE, 0, instanceHandle(), this);
215     ASSERT(::IsWindow(m_window));
216     // We only check our window style, and not ::IsWindowVisible, because m_isVisible only tracks
217     // this window's visibility status, while ::IsWindowVisible takes our ancestors' visibility
218     // status into account. <http://webkit.org/b/54104>
219     ASSERT(m_isVisible == static_cast<bool>(::GetWindowLong(m_window, GWL_STYLE) & WS_VISIBLE));
220
221     auto pageConfiguration = configuration.copy();
222     auto* preferences = pageConfiguration->preferences();
223     if (!preferences && pageConfiguration->pageGroup()) {
224         preferences = &pageConfiguration->pageGroup()->preferences();
225         pageConfiguration->setPreferences(preferences);
226     }
227     if (preferences) {
228         // Disable accelerated compositing until it is supported.
229         preferences->setAcceleratedCompositingEnabled(false);
230     }
231
232     WebProcessPool* processPool = pageConfiguration->processPool();
233     m_page = processPool->createWebPage(*m_pageClient, WTFMove(pageConfiguration));
234     m_page->initializeWebPage();
235
236     if (m_page->drawingArea())
237         m_page->drawingArea()->setSize(IntSize(rect.right - rect.left, rect.bottom - rect.top));
238
239     // FIXME: Initializing the tooltip window here matches WebKit win, but seems like something
240     // we could do on demand to save resources.
241     initializeToolTipWindow();
242
243     // Initialize the top level parent window and register it with the WindowMessageBroadcaster.
244     windowAncestryDidChange();
245 }
246
247 WebView::~WebView()
248 {
249     // Tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD.
250     if (::IsWindow(m_toolTipWindow))
251         ::DestroyWindow(m_toolTipWindow);
252 }
253
254 void WebView::initialize()
255 {
256     if (shouldInitializeTrackPointHack()) {
257         // If we detected a registry key belonging to a TrackPoint driver, then create fake
258         // scrollbars, so the WebView will receive WM_VSCROLL and WM_HSCROLL messages.
259         // We create an invisible vertical scrollbar and an invisible horizontal scrollbar to allow
260         // for receiving both types of messages.
261         ::CreateWindow(TEXT("SCROLLBAR"), TEXT("FAKETRACKPOINTHSCROLLBAR"), WS_CHILD | WS_VISIBLE | SBS_HORZ, 0, 0, 0, 0, m_window, 0, instanceHandle(), 0);
262         ::CreateWindow(TEXT("SCROLLBAR"), TEXT("FAKETRACKPOINTVSCROLLBAR"), WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0, m_window, 0, instanceHandle(), 0);
263     }
264 }
265
266 void WebView::setParentWindow(HWND parentWindow)
267 {
268     if (m_window) {
269         // If the host window hasn't changed, bail.
270         if (::GetParent(m_window) == parentWindow)
271             return;
272         if (parentWindow)
273             ::SetParent(m_window, parentWindow);
274         else if (!m_isBeingDestroyed) {
275             // Turn the WebView into a message-only window so it will no longer be a child of the
276             // old parent window and will be hidden from screen. We only do this when
277             // isBeingDestroyed() is false because doing this while handling WM_DESTROY can leave
278             // m_window in a weird state (see <http://webkit.org/b/29337>).
279             ::SetParent(m_window, HWND_MESSAGE);
280         }
281     }
282
283     windowAncestryDidChange();
284 }
285
286 static HWND findTopLevelParentWindow(HWND window)
287 {
288     if (!window)
289         return 0;
290
291     HWND current = window;
292     for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent)) {
293         if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
294             return current;
295     }
296     ASSERT_NOT_REACHED();
297     return 0;
298 }
299
300 void WebView::windowAncestryDidChange()
301 {
302     HWND newTopLevelParentWindow;
303     if (m_window)
304         newTopLevelParentWindow = findTopLevelParentWindow(m_window);
305     else {
306         // There's no point in tracking active state changes of our parent window if we don't have
307         // a window ourselves.
308         newTopLevelParentWindow = 0;
309     }
310
311     if (newTopLevelParentWindow == m_topLevelParentWindow)
312         return;
313
314     if (m_topLevelParentWindow)
315         WindowMessageBroadcaster::removeListener(m_topLevelParentWindow, this);
316
317     m_topLevelParentWindow = newTopLevelParentWindow;
318
319     if (m_topLevelParentWindow)
320         WindowMessageBroadcaster::addListener(m_topLevelParentWindow, this);
321
322     updateActiveState();
323 }
324
325 LRESULT WebView::onMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
326 {
327     NativeWebMouseEvent mouseEvent = NativeWebMouseEvent(hWnd, message, wParam, lParam, m_wasActivatedByMouseEvent);
328     setWasActivatedByMouseEvent(false);
329
330     switch (message) {
331     case WM_LBUTTONDOWN:
332     case WM_MBUTTONDOWN:
333     case WM_RBUTTONDOWN:
334         ::SetFocus(m_window);
335         ::SetCapture(m_window);
336         break;
337     case WM_LBUTTONUP:
338     case WM_MBUTTONUP:
339     case WM_RBUTTONUP:
340         ::ReleaseCapture();
341         break;
342     case WM_MOUSEMOVE:
343         startTrackingMouseLeave();
344         break;
345     case WM_MOUSELEAVE:
346         stopTrackingMouseLeave();
347         break;
348     case WM_LBUTTONDBLCLK:
349     case WM_MBUTTONDBLCLK:
350     case WM_RBUTTONDBLCLK:
351         break;
352     default:
353         ASSERT_NOT_REACHED();
354     }
355
356     m_page->handleMouseEvent(mouseEvent);
357
358     handled = true;
359     return 0;
360 }
361
362 LRESULT WebView::onWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
363 {
364     NativeWebWheelEvent wheelEvent(hWnd, message, wParam, lParam);
365     if (wheelEvent.controlKey()) {
366         // We do not want WebKit to handle Control + Wheel, this should be handled by the client application
367         // to zoom the page.
368         handled = false;
369         return 0;
370     }
371
372     m_page->handleWheelEvent(wheelEvent);
373
374     handled = true;
375     return 0;
376 }
377
378 LRESULT WebView::onHorizontalScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
379 {
380     ScrollDirection direction;
381     ScrollGranularity granularity;
382     switch (LOWORD(wParam)) {
383     case SB_LINELEFT:
384         granularity = ScrollByLine;
385         direction = ScrollLeft;
386         break;
387     case SB_LINERIGHT:
388         granularity = ScrollByLine;
389         direction = ScrollRight;
390         break;
391     case SB_PAGELEFT:
392         granularity = ScrollByDocument;
393         direction = ScrollLeft;
394         break;
395     case SB_PAGERIGHT:
396         granularity = ScrollByDocument;
397         direction = ScrollRight;
398         break;
399     default:
400         handled = false;
401         return 0;
402     }
403
404     m_page->scrollBy(direction, granularity);
405
406     handled = true;
407     return 0;
408 }
409
410 LRESULT WebView::onVerticalScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
411 {
412     ScrollDirection direction;
413     ScrollGranularity granularity;
414     switch (LOWORD(wParam)) {
415     case SB_LINEDOWN:
416         granularity = ScrollByLine;
417         direction = ScrollDown;
418         break;
419     case SB_LINEUP:
420         granularity = ScrollByLine;
421         direction = ScrollUp;
422         break;
423     case SB_PAGEDOWN:
424         granularity = ScrollByDocument;
425         direction = ScrollDown;
426         break;
427     case SB_PAGEUP:
428         granularity = ScrollByDocument;
429         direction = ScrollUp;
430         break;
431     default:
432         handled = false;
433         return 0;
434     }
435
436     m_page->scrollBy(direction, granularity);
437
438     handled = true;
439     return 0;
440 }
441
442 LRESULT WebView::onKeyEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
443 {
444     m_page->handleKeyboardEvent(NativeWebKeyboardEvent(hWnd, message, wParam, lParam));
445
446     // We claim here to always have handled the event. If the event is not in fact handled, we will
447     // find out later in didNotHandleKeyEvent.
448     handled = true;
449     return 0;
450 }
451
452 static void drawPageBackground(HDC dc, const WebPageProxy* page, const RECT& rect)
453 {
454     auto& backgroundColor = page->backgroundColor();
455     if (!backgroundColor || backgroundColor.value().isVisible())
456         return;
457
458     ::FillRect(dc, &rect, reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1));
459 }
460
461 void WebView::paint(HDC hdc, const IntRect& dirtyRect)
462 {
463     if (dirtyRect.isEmpty())
464         return;
465     m_page->endPrinting();
466     if (auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(m_page->drawingArea())) {
467         // FIXME: We should port WebKit1's rect coalescing logic here.
468         Region unpaintedRegion;
469         cairo_surface_t* surface = cairo_win32_surface_create(hdc);
470         cairo_t* context = cairo_create(surface);
471
472         drawingArea->paint(context, dirtyRect, unpaintedRegion);
473
474         cairo_destroy(context);
475         cairo_surface_destroy(surface);
476
477         Vector<IntRect> unpaintedRects = unpaintedRegion.rects();
478         for (auto& rect : unpaintedRects)
479             drawPageBackground(hdc, m_page.get(), rect);
480     } else
481         drawPageBackground(hdc, m_page.get(), dirtyRect);
482 }
483
484 LRESULT WebView::onPaintEvent(HWND hWnd, UINT message, WPARAM, LPARAM, bool& handled)
485 {
486     // Update child windows now so that any areas of our window they reveal will be included in the
487     // invalid region that ::BeginPaint sees.
488
489     PAINTSTRUCT paintStruct;
490     HDC hdc = ::BeginPaint(m_window, &paintStruct);
491     paint(hdc, paintStruct.rcPaint);
492
493     ::EndPaint(m_window, &paintStruct);
494
495     handled = true;
496     return 0;
497 }
498
499 LRESULT WebView::onPrintClientEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
500 {
501     HDC hdc = reinterpret_cast<HDC>(wParam);
502     RECT winRect;
503     ::GetClientRect(hWnd, &winRect);
504
505     paint(hdc, winRect);
506
507     handled = true;
508     return 0;
509 }
510
511 LRESULT WebView::onSizeEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
512 {
513     int width = LOWORD(lParam);
514     int height = HIWORD(lParam);
515
516     if (m_page && m_page->drawingArea()) {
517         // FIXME specify correctly layerPosition.
518         m_page->drawingArea()->setSize(IntSize(width, height), m_nextResizeScrollOffset);
519         m_nextResizeScrollOffset = IntSize();
520     }
521
522     handled = true;
523     return 0;
524 }
525
526 LRESULT WebView::onWindowPositionChangedEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
527 {
528     if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
529         updateActiveStateSoon();
530
531     handled = false;
532     return 0;
533 }
534
535 LRESULT WebView::onSetFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
536 {
537     m_page->activityStateDidChange(ActivityState::IsFocused);
538     handled = true;
539     return 0;
540 }
541
542 LRESULT WebView::onKillFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
543 {
544     m_page->activityStateDidChange(ActivityState::IsFocused);
545     handled = true;
546     return 0;
547 }
548
549 LRESULT WebView::onTimerEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
550 {
551     switch (wParam) {
552     case UpdateActiveStateTimer:
553         ::KillTimer(hWnd, UpdateActiveStateTimer);
554         updateActiveState();
555         break;
556     }
557
558     handled = true;
559     return 0;
560 }
561
562 LRESULT WebView::onShowWindowEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
563 {
564     // lParam is 0 when the message is sent because of a ShowWindow call.
565     // FIXME: Since we don't get notified when an ancestor window is hidden or shown, we will keep
566     // painting even when we have a hidden ancestor. <http://webkit.org/b/54104>
567     if (!lParam)
568         setIsVisible(wParam);
569
570     handled = false;
571     return 0;
572 }
573
574 LRESULT WebView::onSetCursor(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
575 {
576     if (!m_lastCursorSet) {
577         handled = false;
578         return 0;
579     }
580
581     ::SetCursor(m_lastCursorSet);
582     return 0;
583 }
584
585 LRESULT WebView::onMenuCommand(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
586 {
587     auto hMenu = reinterpret_cast<HMENU>(lParam);
588     auto index = static_cast<unsigned>(wParam);
589
590     MENUITEMINFO menuItemInfo;
591     menuItemInfo.cbSize = sizeof(menuItemInfo);
592     menuItemInfo.cch = 0;
593     menuItemInfo.fMask = MIIM_STRING;
594     ::GetMenuItemInfo(hMenu, index, TRUE, &menuItemInfo);
595
596     menuItemInfo.cch++;
597     Vector<WCHAR> buffer(menuItemInfo.cch);
598     menuItemInfo.dwTypeData = buffer.data();
599     menuItemInfo.fMask |= MIIM_ID;
600
601     ::GetMenuItemInfo(hMenu, index, TRUE, &menuItemInfo);
602
603     String title(buffer.data(), menuItemInfo.cch);
604     ContextMenuAction action = static_cast<ContextMenuAction>(menuItemInfo.wID);
605     bool enabled = !(menuItemInfo.fState & MFS_DISABLED);
606     bool checked = menuItemInfo.fState & MFS_CHECKED;
607     WebContextMenuItemData item(ContextMenuItemType::ActionType, action, title, enabled, checked);
608     m_page->contextMenuItemSelected(item);
609
610     handled = true;
611     return 0;
612 }
613
614 void WebView::updateActiveState()
615 {
616     m_page->activityStateDidChange(ActivityState::WindowIsActive);
617 }
618
619 void WebView::updateActiveStateSoon()
620 {
621     // This function is called while processing the WM_NCACTIVATE message.
622     // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
623     // still return our window. If we were to call updateActiveState() in that case, we would
624     // wrongly think that we are still the active window. To work around this, we update our
625     // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
626     // the newly-activated window.
627
628     ::SetTimer(m_window, UpdateActiveStateTimer, 0, 0);
629 }
630
631 static bool initCommonControls()
632 {
633     static bool haveInitialized = false;
634     if (haveInitialized)
635         return true;
636
637     INITCOMMONCONTROLSEX init;
638     init.dwSize = sizeof(init);
639     init.dwICC = ICC_TREEVIEW_CLASSES;
640     haveInitialized = !!::InitCommonControlsEx(&init);
641     return haveInitialized;
642 }
643
644 void WebView::initializeToolTipWindow()
645 {
646     if (!initCommonControls())
647         return;
648
649     m_toolTipWindow = ::CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
650         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
651         m_window, 0, 0, 0);
652     if (!m_toolTipWindow)
653         return;
654
655     TOOLINFO info { };
656     info.cbSize = sizeof(info);
657     info.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
658     info.uId = reinterpret_cast<UINT_PTR>(m_window);
659
660     ::SendMessage(m_toolTipWindow, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
661     ::SendMessage(m_toolTipWindow, TTM_SETMAXTIPWIDTH, 0, kMaxToolTipWidth);
662     ::SetWindowPos(m_toolTipWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
663 }
664
665 void WebView::startTrackingMouseLeave()
666 {
667     if (m_trackingMouseLeave)
668         return;
669     m_trackingMouseLeave = true;
670
671     TRACKMOUSEEVENT trackMouseEvent;
672     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
673     trackMouseEvent.dwFlags = TME_LEAVE;
674     trackMouseEvent.hwndTrack = m_window;
675
676     ::TrackMouseEvent(&trackMouseEvent);
677 }
678
679 void WebView::stopTrackingMouseLeave()
680 {
681     if (!m_trackingMouseLeave)
682         return;
683     m_trackingMouseLeave = false;
684
685     TRACKMOUSEEVENT trackMouseEvent;
686     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
687     trackMouseEvent.dwFlags = TME_LEAVE | TME_CANCEL;
688     trackMouseEvent.hwndTrack = m_window;
689
690     ::TrackMouseEvent(&trackMouseEvent);
691 }
692
693 bool WebView::shouldInitializeTrackPointHack()
694 {
695     static bool shouldCreateScrollbars;
696     static bool hasRunTrackPointCheck;
697
698     if (hasRunTrackPointCheck)
699         return shouldCreateScrollbars;
700
701     hasRunTrackPointCheck = true;
702     const wchar_t* trackPointKeys[] = {
703         L"Software\\Lenovo\\TrackPoint",
704         L"Software\\Lenovo\\UltraNav",
705         L"Software\\Alps\\Apoint\\TrackPoint",
706         L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
707         L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"
708     };
709
710     for (size_t i = 0; i < WTF_ARRAY_LENGTH(trackPointKeys); ++i) {
711         HKEY trackPointKey;
712         int readKeyResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, trackPointKeys[i], 0, KEY_READ, &trackPointKey);
713         ::RegCloseKey(trackPointKey);
714         if (readKeyResult == ERROR_SUCCESS) {
715             shouldCreateScrollbars = true;
716             return shouldCreateScrollbars;
717         }
718     }
719
720     return shouldCreateScrollbars;
721 }
722
723 void WebView::close()
724 {
725     if (m_window) {
726         // We can't check IsWindow(m_window) here, because that will return true even while
727         // we're already handling WM_DESTROY. So we check !m_isBeingDestroyed instead.
728         if (!m_isBeingDestroyed)
729             DestroyWindow(m_window);
730         // Either we just destroyed m_window, or it's in the process of being destroyed. Either
731         // way, we clear it out to make sure we don't try to use it later.
732         m_window = 0;
733     }
734     setParentWindow(0);
735     m_page->close();
736 }
737
738 HCURSOR WebView::cursorToShow() const
739 {
740     if (!m_page->isValid())
741         return 0;
742
743     // We only show the override cursor if the default (arrow) cursor is showing.
744     static HCURSOR arrowCursor = ::LoadCursor(0, IDC_ARROW);
745     if (m_overrideCursor && m_webCoreCursor == arrowCursor)
746         return m_overrideCursor;
747
748     return m_webCoreCursor;
749 }
750
751 void WebView::setCursor(const WebCore::Cursor& cursor)
752 {
753     if (!cursor.platformCursor()->nativeCursor())
754         return;
755     m_webCoreCursor = cursor.platformCursor()->nativeCursor();
756     updateNativeCursor();
757 }
758
759 void WebView::updateNativeCursor()
760 {
761     m_lastCursorSet = cursorToShow();
762     if (!m_lastCursorSet)
763         return;
764     ::SetCursor(m_lastCursorSet);
765 }
766
767 void WebView::setOverrideCursor(HCURSOR overrideCursor)
768 {
769     m_overrideCursor = overrideCursor;
770     updateNativeCursor();
771 }
772
773 void WebView::setIsInWindow(bool isInWindow)
774 {
775     m_isInWindow = isInWindow;
776     if (m_page)
777         m_page->activityStateDidChange(ActivityState::IsInWindow);
778 }
779
780 void WebView::setIsVisible(bool isVisible)
781 {
782     m_isVisible = isVisible;
783     if (m_page)
784         m_page->activityStateDidChange(ActivityState::IsVisible);
785 }
786
787 bool WebView::isWindowActive()
788 {
789     HWND activeWindow = ::GetActiveWindow();
790     return (activeWindow && m_topLevelParentWindow == findTopLevelParentWindow(activeWindow));
791 }
792
793 bool WebView::isFocused()
794 {
795     return ::GetFocus() == m_window;
796 }
797
798 bool WebView::isVisible()
799 {
800     return m_isVisible;
801 }
802
803 bool WebView::isInWindow()
804 {
805     return m_isInWindow;
806 }
807
808 void WebView::setScrollOffsetOnNextResize(const IntSize& scrollOffset)
809 {
810     // The next time we get a WM_SIZE message, scroll by the specified amount in onSizeEvent().
811     m_nextResizeScrollOffset = scrollOffset;
812 }
813
814 void WebView::setViewNeedsDisplay(const WebCore::Region& region)
815 {
816     const RECT r = region.bounds();
817     ::InvalidateRect(m_window, &r, true);
818 }
819
820 #if ENABLE(INPUT_TYPE_COLOR)
821 PassRefPtr<WebColorChooserProxy> WebView::createColorChooserProxy(WebPageProxy*, const WebCore::Color&, const WebCore::IntRect&)
822 {
823     notImplemented();
824     return 0;
825 }
826 #endif
827
828 void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
829 {
830 }
831
832 double WebView::customRepresentationZoomFactor()
833 {
834     return 1;
835 }
836
837 void WebView::setCustomRepresentationZoomFactor(double)
838 {
839 }
840
841 void WebView::findStringInCustomRepresentation(const String&, FindOptions, unsigned)
842 {
843 }
844
845 void WebView::countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned)
846 {
847 }
848
849 HWND WebView::nativeWindow()
850 {
851     return m_window;
852 }
853
854 // WebCore::WindowMessageListener
855
856 void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
857 {
858     switch (message) {
859     case WM_NCACTIVATE:
860         updateActiveStateSoon();
861         break;
862     case WM_SETTINGCHANGE:
863         break;
864     }
865 }
866
867 void WebView::setToolTip(const String& toolTip)
868 {
869     if (!m_toolTipWindow)
870         return;
871
872     if (!toolTip.isEmpty()) {
873         TOOLINFO info { };
874         info.cbSize = sizeof(info);
875         info.uFlags = TTF_IDISHWND;
876         info.uId = reinterpret_cast<UINT_PTR>(nativeWindow());
877         Vector<wchar_t> toolTipCharacters = toolTip.wideCharacters(); // Retain buffer long enough to make the SendMessage call
878         info.lpszText = const_cast<wchar_t*>(toolTipCharacters.data());
879         ::SendMessage(m_toolTipWindow, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
880     }
881
882     ::SendMessage(m_toolTipWindow, TTM_ACTIVATE, !toolTip.isEmpty(), 0);
883 }
884
885 } // namespace WebKit