Move FileSystem to WTF
[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 "DrawingAreaProxyImpl.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     if (!page->drawsBackground())
455         return;
456
457     ::FillRect(dc, &rect, reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1));
458 }
459
460 void WebView::paint(HDC hdc, const IntRect& dirtyRect)
461 {
462     if (dirtyRect.isEmpty())
463         return;
464     m_page->endPrinting();
465     if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(m_page->drawingArea())) {
466         // FIXME: We should port WebKit1's rect coalescing logic here.
467         Region unpaintedRegion;
468         cairo_surface_t* surface = cairo_win32_surface_create(hdc);
469         cairo_t* context = cairo_create(surface);
470
471         drawingArea->paint(context, dirtyRect, unpaintedRegion);
472
473         cairo_destroy(context);
474         cairo_surface_destroy(surface);
475
476         Vector<IntRect> unpaintedRects = unpaintedRegion.rects();
477         for (auto& rect : unpaintedRects)
478             drawPageBackground(hdc, m_page.get(), rect);
479     } else
480         drawPageBackground(hdc, m_page.get(), dirtyRect);
481 }
482
483 LRESULT WebView::onPaintEvent(HWND hWnd, UINT message, WPARAM, LPARAM, bool& handled)
484 {
485     // Update child windows now so that any areas of our window they reveal will be included in the
486     // invalid region that ::BeginPaint sees.
487
488     PAINTSTRUCT paintStruct;
489     HDC hdc = ::BeginPaint(m_window, &paintStruct);
490     paint(hdc, paintStruct.rcPaint);
491
492     ::EndPaint(m_window, &paintStruct);
493
494     handled = true;
495     return 0;
496 }
497
498 LRESULT WebView::onPrintClientEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
499 {
500     HDC hdc = reinterpret_cast<HDC>(wParam);
501     RECT winRect;
502     ::GetClientRect(hWnd, &winRect);
503
504     paint(hdc, winRect);
505
506     handled = true;
507     return 0;
508 }
509
510 LRESULT WebView::onSizeEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
511 {
512     int width = LOWORD(lParam);
513     int height = HIWORD(lParam);
514
515     if (m_page && m_page->drawingArea()) {
516         // FIXME specify correctly layerPosition.
517         m_page->drawingArea()->setSize(IntSize(width, height), m_nextResizeScrollOffset);
518         m_nextResizeScrollOffset = IntSize();
519     }
520
521     handled = true;
522     return 0;
523 }
524
525 LRESULT WebView::onWindowPositionChangedEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
526 {
527     if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
528         updateActiveStateSoon();
529
530     handled = false;
531     return 0;
532 }
533
534 LRESULT WebView::onSetFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
535 {
536     m_page->activityStateDidChange(ActivityState::IsFocused);
537     handled = true;
538     return 0;
539 }
540
541 LRESULT WebView::onKillFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
542 {
543     m_page->activityStateDidChange(ActivityState::IsFocused);
544     handled = true;
545     return 0;
546 }
547
548 LRESULT WebView::onTimerEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
549 {
550     switch (wParam) {
551     case UpdateActiveStateTimer:
552         ::KillTimer(hWnd, UpdateActiveStateTimer);
553         updateActiveState();
554         break;
555     }
556
557     handled = true;
558     return 0;
559 }
560
561 LRESULT WebView::onShowWindowEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
562 {
563     // lParam is 0 when the message is sent because of a ShowWindow call.
564     // FIXME: Since we don't get notified when an ancestor window is hidden or shown, we will keep
565     // painting even when we have a hidden ancestor. <http://webkit.org/b/54104>
566     if (!lParam)
567         setIsVisible(wParam);
568
569     handled = false;
570     return 0;
571 }
572
573 LRESULT WebView::onSetCursor(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
574 {
575     if (!m_lastCursorSet) {
576         handled = false;
577         return 0;
578     }
579
580     ::SetCursor(m_lastCursorSet);
581     return 0;
582 }
583
584 LRESULT WebView::onMenuCommand(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
585 {
586     auto hMenu = reinterpret_cast<HMENU>(lParam);
587     auto index = static_cast<unsigned>(wParam);
588
589     MENUITEMINFO menuItemInfo;
590     menuItemInfo.cbSize = sizeof(menuItemInfo);
591     menuItemInfo.cch = 0;
592     menuItemInfo.fMask = MIIM_STRING;
593     ::GetMenuItemInfo(hMenu, index, TRUE, &menuItemInfo);
594
595     menuItemInfo.cch++;
596     Vector<WCHAR> buffer(menuItemInfo.cch);
597     menuItemInfo.dwTypeData = buffer.data();
598     menuItemInfo.fMask |= MIIM_ID;
599
600     ::GetMenuItemInfo(hMenu, index, TRUE, &menuItemInfo);
601
602     String title(buffer.data(), menuItemInfo.cch);
603     ContextMenuAction action = static_cast<ContextMenuAction>(menuItemInfo.wID);
604     bool enabled = !(menuItemInfo.fState & MFS_DISABLED);
605     bool checked = menuItemInfo.fState & MFS_CHECKED;
606     WebContextMenuItemData item(ContextMenuItemType::ActionType, action, title, enabled, checked);
607     m_page->contextMenuItemSelected(item);
608
609     handled = true;
610     return 0;
611 }
612
613 void WebView::updateActiveState()
614 {
615     m_page->activityStateDidChange(ActivityState::WindowIsActive);
616 }
617
618 void WebView::updateActiveStateSoon()
619 {
620     // This function is called while processing the WM_NCACTIVATE message.
621     // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
622     // still return our window. If we were to call updateActiveState() in that case, we would
623     // wrongly think that we are still the active window. To work around this, we update our
624     // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
625     // the newly-activated window.
626
627     ::SetTimer(m_window, UpdateActiveStateTimer, 0, 0);
628 }
629
630 static bool initCommonControls()
631 {
632     static bool haveInitialized = false;
633     if (haveInitialized)
634         return true;
635
636     INITCOMMONCONTROLSEX init;
637     init.dwSize = sizeof(init);
638     init.dwICC = ICC_TREEVIEW_CLASSES;
639     haveInitialized = !!::InitCommonControlsEx(&init);
640     return haveInitialized;
641 }
642
643 void WebView::initializeToolTipWindow()
644 {
645     if (!initCommonControls())
646         return;
647
648     m_toolTipWindow = ::CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
649         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
650         m_window, 0, 0, 0);
651     if (!m_toolTipWindow)
652         return;
653
654     TOOLINFO info { };
655     info.cbSize = sizeof(info);
656     info.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
657     info.uId = reinterpret_cast<UINT_PTR>(m_window);
658
659     ::SendMessage(m_toolTipWindow, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
660     ::SendMessage(m_toolTipWindow, TTM_SETMAXTIPWIDTH, 0, kMaxToolTipWidth);
661     ::SetWindowPos(m_toolTipWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
662 }
663
664 void WebView::startTrackingMouseLeave()
665 {
666     if (m_trackingMouseLeave)
667         return;
668     m_trackingMouseLeave = true;
669
670     TRACKMOUSEEVENT trackMouseEvent;
671     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
672     trackMouseEvent.dwFlags = TME_LEAVE;
673     trackMouseEvent.hwndTrack = m_window;
674
675     ::TrackMouseEvent(&trackMouseEvent);
676 }
677
678 void WebView::stopTrackingMouseLeave()
679 {
680     if (!m_trackingMouseLeave)
681         return;
682     m_trackingMouseLeave = false;
683
684     TRACKMOUSEEVENT trackMouseEvent;
685     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
686     trackMouseEvent.dwFlags = TME_LEAVE | TME_CANCEL;
687     trackMouseEvent.hwndTrack = m_window;
688
689     ::TrackMouseEvent(&trackMouseEvent);
690 }
691
692 bool WebView::shouldInitializeTrackPointHack()
693 {
694     static bool shouldCreateScrollbars;
695     static bool hasRunTrackPointCheck;
696
697     if (hasRunTrackPointCheck)
698         return shouldCreateScrollbars;
699
700     hasRunTrackPointCheck = true;
701     const wchar_t* trackPointKeys[] = {
702         L"Software\\Lenovo\\TrackPoint",
703         L"Software\\Lenovo\\UltraNav",
704         L"Software\\Alps\\Apoint\\TrackPoint",
705         L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
706         L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"
707     };
708
709     for (size_t i = 0; i < WTF_ARRAY_LENGTH(trackPointKeys); ++i) {
710         HKEY trackPointKey;
711         int readKeyResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, trackPointKeys[i], 0, KEY_READ, &trackPointKey);
712         ::RegCloseKey(trackPointKey);
713         if (readKeyResult == ERROR_SUCCESS) {
714             shouldCreateScrollbars = true;
715             return shouldCreateScrollbars;
716         }
717     }
718
719     return shouldCreateScrollbars;
720 }
721
722 void WebView::close()
723 {
724     if (m_window) {
725         // We can't check IsWindow(m_window) here, because that will return true even while
726         // we're already handling WM_DESTROY. So we check !m_isBeingDestroyed instead.
727         if (!m_isBeingDestroyed)
728             DestroyWindow(m_window);
729         // Either we just destroyed m_window, or it's in the process of being destroyed. Either
730         // way, we clear it out to make sure we don't try to use it later.
731         m_window = 0;
732     }
733     setParentWindow(0);
734     m_page->close();
735 }
736
737 HCURSOR WebView::cursorToShow() const
738 {
739     if (!m_page->isValid())
740         return 0;
741
742     // We only show the override cursor if the default (arrow) cursor is showing.
743     static HCURSOR arrowCursor = ::LoadCursor(0, IDC_ARROW);
744     if (m_overrideCursor && m_webCoreCursor == arrowCursor)
745         return m_overrideCursor;
746
747     return m_webCoreCursor;
748 }
749
750 void WebView::setCursor(const WebCore::Cursor& cursor)
751 {
752     if (!cursor.platformCursor()->nativeCursor())
753         return;
754     m_webCoreCursor = cursor.platformCursor()->nativeCursor();
755     updateNativeCursor();
756 }
757
758 void WebView::updateNativeCursor()
759 {
760     m_lastCursorSet = cursorToShow();
761     if (!m_lastCursorSet)
762         return;
763     ::SetCursor(m_lastCursorSet);
764 }
765
766 void WebView::setOverrideCursor(HCURSOR overrideCursor)
767 {
768     m_overrideCursor = overrideCursor;
769     updateNativeCursor();
770 }
771
772 void WebView::setIsInWindow(bool isInWindow)
773 {
774     m_isInWindow = isInWindow;
775     if (m_page)
776         m_page->activityStateDidChange(ActivityState::IsInWindow);
777 }
778
779 void WebView::setIsVisible(bool isVisible)
780 {
781     m_isVisible = isVisible;
782     if (m_page)
783         m_page->activityStateDidChange(ActivityState::IsVisible);
784 }
785
786 bool WebView::isWindowActive()
787 {
788     HWND activeWindow = ::GetActiveWindow();
789     return (activeWindow && m_topLevelParentWindow == findTopLevelParentWindow(activeWindow));
790 }
791
792 bool WebView::isFocused()
793 {
794     return ::GetFocus() == m_window;
795 }
796
797 bool WebView::isVisible()
798 {
799     return m_isVisible;
800 }
801
802 bool WebView::isInWindow()
803 {
804     return m_isInWindow;
805 }
806
807 void WebView::setScrollOffsetOnNextResize(const IntSize& scrollOffset)
808 {
809     // The next time we get a WM_SIZE message, scroll by the specified amount in onSizeEvent().
810     m_nextResizeScrollOffset = scrollOffset;
811 }
812
813 void WebView::setViewNeedsDisplay(const WebCore::Region& region)
814 {
815     const RECT r = region.bounds();
816     ::InvalidateRect(m_window, &r, true);
817 }
818
819 #if ENABLE(INPUT_TYPE_COLOR)
820 PassRefPtr<WebColorChooserProxy> WebView::createColorChooserProxy(WebPageProxy*, const WebCore::Color&, const WebCore::IntRect&)
821 {
822     notImplemented();
823     return 0;
824 }
825 #endif
826
827 void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
828 {
829 }
830
831 double WebView::customRepresentationZoomFactor()
832 {
833     return 1;
834 }
835
836 void WebView::setCustomRepresentationZoomFactor(double)
837 {
838 }
839
840 void WebView::findStringInCustomRepresentation(const String&, FindOptions, unsigned)
841 {
842 }
843
844 void WebView::countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned)
845 {
846 }
847
848 HWND WebView::nativeWindow()
849 {
850     return m_window;
851 }
852
853 // WebCore::WindowMessageListener
854
855 void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
856 {
857     switch (message) {
858     case WM_NCACTIVATE:
859         updateActiveStateSoon();
860         break;
861     case WM_SETTINGCHANGE:
862         break;
863     }
864 }
865
866 void WebView::setToolTip(const String& toolTip)
867 {
868     if (!m_toolTipWindow)
869         return;
870
871     if (!toolTip.isEmpty()) {
872         TOOLINFO info { };
873         info.cbSize = sizeof(info);
874         info.uFlags = TTF_IDISHWND;
875         info.uId = reinterpret_cast<UINT_PTR>(nativeWindow());
876         Vector<UChar> toolTipCharacters = toolTip.charactersWithNullTermination(); // Retain buffer long enough to make the SendMessage call
877         info.lpszText = const_cast<UChar*>(toolTipCharacters.data());
878         ::SendMessage(m_toolTipWindow, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
879     }
880
881     ::SendMessage(m_toolTipWindow, TTM_ACTIVATE, !toolTip.isEmpty(), 0);
882 }
883
884 } // namespace WebKit