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