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