Reviewed by Adele Peterson.
[WebKit-https.git] / Source / WebKit2 / UIProcess / win / WebView.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebView.h"
28
29 #include "ChunkedUpdateDrawingAreaProxy.h"
30 #include "DrawingAreaProxyImpl.h"
31 #include "FindIndicator.h"
32 #include "Logging.h"
33 #include "NativeWebKeyboardEvent.h"
34 #include "NativeWebMouseEvent.h"
35 #include "Region.h"
36 #include "RunLoop.h"
37 #include "WKAPICast.h"
38 #include "WebContext.h"
39 #include "WebContextMenuProxyWin.h"
40 #include "WebEditCommandProxy.h"
41 #include "WebEventFactory.h"
42 #include "WebPageProxy.h"
43 #include "WebPopupMenuProxyWin.h"
44 #include <Commctrl.h>
45 #include <WebCore/BitmapInfo.h>
46 #include <WebCore/Cursor.h>
47 #include <WebCore/FloatRect.h>
48 #if USE(CG)
49 #include <WebCore/GraphicsContextCG.h>
50 #endif
51 #include <WebCore/IntRect.h>
52 #include <WebCore/SoftLinking.h>
53 #include <WebCore/WebCoreInstanceHandle.h>
54 #include <WebCore/WindowMessageBroadcaster.h>
55 #include <WebCore/WindowsTouch.h>
56 #include <wtf/text/WTFString.h>
57
58 namespace Ime {
59 // We need these functions in a separate namespace, because in the global namespace they conflict
60 // with the definitions in imm.h only by the type modifier (the macro defines them as static) and
61 // imm.h is included by windows.h
62 SOFT_LINK_LIBRARY(IMM32)
63 SOFT_LINK(IMM32, ImmGetContext, HIMC, WINAPI, (HWND hwnd), (hwnd))
64 SOFT_LINK(IMM32, ImmReleaseContext, BOOL, WINAPI, (HWND hWnd, HIMC hIMC), (hWnd, hIMC))
65 SOFT_LINK(IMM32, ImmGetCompositionStringW, LONG, WINAPI, (HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen), (hIMC, dwIndex, lpBuf, dwBufLen))
66 SOFT_LINK(IMM32, ImmSetCandidateWindow, BOOL, WINAPI, (HIMC hIMC, LPCANDIDATEFORM lpCandidate), (hIMC, lpCandidate))
67 SOFT_LINK(IMM32, ImmSetOpenStatus, BOOL, WINAPI, (HIMC hIMC, BOOL fOpen), (hIMC, fOpen))
68 SOFT_LINK(IMM32, ImmNotifyIME, BOOL, WINAPI, (HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue), (hIMC, dwAction, dwIndex, dwValue))
69 SOFT_LINK(IMM32, ImmAssociateContextEx, BOOL, WINAPI, (HWND hWnd, HIMC hIMC, DWORD dwFlags), (hWnd, hIMC, dwFlags))
70 };
71
72 // Soft link functions for gestures and panning.
73 SOFT_LINK_LIBRARY(USER32);
74 SOFT_LINK_OPTIONAL(USER32, GetGestureInfo, BOOL, WINAPI, (HGESTUREINFO, PGESTUREINFO));
75 SOFT_LINK_OPTIONAL(USER32, SetGestureConfig, BOOL, WINAPI, (HWND, DWORD, UINT, PGESTURECONFIG, UINT));
76 SOFT_LINK_OPTIONAL(USER32, CloseGestureInfoHandle, BOOL, WINAPI, (HGESTUREINFO));
77
78 SOFT_LINK_LIBRARY(Uxtheme);
79 SOFT_LINK_OPTIONAL(Uxtheme, BeginPanningFeedback, BOOL, WINAPI, (HWND));
80 SOFT_LINK_OPTIONAL(Uxtheme, EndPanningFeedback, BOOL, WINAPI, (HWND, BOOL));
81 SOFT_LINK_OPTIONAL(Uxtheme, UpdatePanningFeedback, BOOL, WINAPI, (HWND, LONG, LONG, BOOL));
82
83 using namespace WebCore;
84
85 namespace WebKit {
86
87 static const LPCWSTR kWebKit2WebViewWindowClassName = L"WebKit2WebViewWindowClass";
88
89 // Constants not available on all platforms.
90 const int WM_XP_THEMECHANGED = 0x031A;
91 const int WM_VISTA_MOUSEHWHEEL = 0x020E;
92
93 static const int kMaxToolTipWidth = 250;
94
95 enum {
96     UpdateActiveStateTimer = 1,
97 };
98
99 static bool useNewDrawingArea()
100 {
101     // FIXME: Remove this function and the old drawing area code once we aren't interested in
102     // testing the old drawing area anymore.
103     return true;
104 }
105
106 LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
107 {
108     LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0);
109     
110     if (WebView* webView = reinterpret_cast<WebView*>(longPtr))
111         return webView->wndProc(hWnd, message, wParam, lParam);
112
113     if (message == WM_CREATE) {
114         LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
115
116         // Associate the WebView with the window.
117         ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams);
118         return 0;
119     }
120
121     return ::DefWindowProc(hWnd, message, wParam, lParam);
122 }
123
124 LRESULT WebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
125 {
126     LRESULT lResult = 0;
127     bool handled = true;
128
129     switch (message) {
130     case WM_CLOSE:
131         m_page->tryClose();
132         break;
133     case WM_DESTROY:
134         m_isBeingDestroyed = true;
135         close();
136         break;
137     case WM_ERASEBKGND:
138         lResult = 1;
139         break;
140     case WM_PAINT:
141         lResult = onPaintEvent(hWnd, message, wParam, lParam, handled);
142         break;
143     case WM_PRINTCLIENT:
144         lResult = onPrintClientEvent(hWnd, message, wParam, lParam, handled);
145         break;
146     case WM_MOUSEACTIVATE:
147         setWasActivatedByMouseEvent(true);
148         handled = false;
149         break;
150     case WM_MOUSEMOVE:
151     case WM_LBUTTONDOWN:
152     case WM_MBUTTONDOWN:
153     case WM_RBUTTONDOWN:
154     case WM_LBUTTONDBLCLK:
155     case WM_MBUTTONDBLCLK:
156     case WM_RBUTTONDBLCLK:
157     case WM_LBUTTONUP:
158     case WM_MBUTTONUP:
159     case WM_RBUTTONUP:
160     case WM_MOUSELEAVE:
161         lResult = onMouseEvent(hWnd, message, wParam, lParam, handled);
162         break;
163     case WM_MOUSEWHEEL:
164     case WM_VISTA_MOUSEHWHEEL:
165         lResult = onWheelEvent(hWnd, message, wParam, lParam, handled);
166         break;
167     case WM_HSCROLL:
168         lResult = onHorizontalScroll(hWnd, message, wParam, lParam, handled);
169         break;
170     case WM_VSCROLL:
171         lResult = onVerticalScroll(hWnd, message, wParam, lParam, handled);
172         break;
173     case WM_GESTURENOTIFY:
174         lResult = onGestureNotify(hWnd, message, wParam, lParam, handled);
175         break;
176     case WM_GESTURE:
177         lResult = onGesture(hWnd, message, wParam, lParam, handled);
178         break;
179     case WM_SYSKEYDOWN:
180     case WM_KEYDOWN:
181     case WM_SYSCHAR:
182     case WM_CHAR:
183     case WM_SYSKEYUP:
184     case WM_KEYUP:
185         lResult = onKeyEvent(hWnd, message, wParam, lParam, handled);
186         break;
187     case WM_SIZE:
188         lResult = onSizeEvent(hWnd, message, wParam, lParam, handled);
189         break;
190     case WM_WINDOWPOSCHANGED:
191         lResult = onWindowPositionChangedEvent(hWnd, message, wParam, lParam, handled);
192         break;
193     case WM_SETFOCUS:
194         lResult = onSetFocusEvent(hWnd, message, wParam, lParam, handled);
195         break;
196     case WM_KILLFOCUS:
197         lResult = onKillFocusEvent(hWnd, message, wParam, lParam, handled);
198         break;
199     case WM_TIMER:
200         lResult = onTimerEvent(hWnd, message, wParam, lParam, handled);
201         break;
202     case WM_SHOWWINDOW:
203         lResult = onShowWindowEvent(hWnd, message, wParam, lParam, handled);
204         break;
205     case WM_SETCURSOR:
206         lResult = onSetCursor(hWnd, message, wParam, lParam, handled);
207         break;
208     case WM_IME_STARTCOMPOSITION:
209         handled = onIMEStartComposition();
210         break;
211     case WM_IME_REQUEST:
212         lResult = onIMERequest(wParam, lParam);
213         break;
214     case WM_IME_COMPOSITION:
215         handled = onIMEComposition(lParam);
216         break;
217     case WM_IME_ENDCOMPOSITION:
218         handled = onIMEEndComposition();
219         break;
220     case WM_IME_SELECT:
221         handled = onIMESelect(wParam, lParam);
222         break;
223     case WM_IME_SETCONTEXT:
224         handled = onIMESetContext(wParam, lParam);
225         break;
226     default:
227         handled = false;
228         break;
229     }
230
231     if (!handled)
232         lResult = ::DefWindowProc(hWnd, message, wParam, lParam);
233
234     return lResult;
235 }
236
237 bool WebView::registerWebViewWindowClass()
238 {
239     static bool haveRegisteredWindowClass = false;
240     if (haveRegisteredWindowClass)
241         return true;
242     haveRegisteredWindowClass = true;
243
244     WNDCLASSEX wcex;
245
246     wcex.cbSize = sizeof(WNDCLASSEX);
247     wcex.style          = CS_DBLCLKS;
248     wcex.lpfnWndProc    = WebView::WebViewWndProc;
249     wcex.cbClsExtra     = 0;
250     wcex.cbWndExtra     = sizeof(WebView*);
251     wcex.hInstance      = instanceHandle();
252     wcex.hIcon          = 0;
253     wcex.hCursor        = ::LoadCursor(0, IDC_ARROW);
254     wcex.hbrBackground  = 0;
255     wcex.lpszMenuName   = 0;
256     wcex.lpszClassName  = kWebKit2WebViewWindowClassName;
257     wcex.hIconSm        = 0;
258
259     return !!::RegisterClassEx(&wcex);
260 }
261
262 WebView::WebView(RECT rect, WebContext* context, WebPageGroup* pageGroup, HWND parentWindow)
263     : m_topLevelParentWindow(0)
264     , m_toolTipWindow(0)
265     , m_lastCursorSet(0)
266     , m_webCoreCursor(0)
267     , m_overrideCursor(0)
268     , m_trackingMouseLeave(false)
269     , m_isInWindow(false)
270     , m_isVisible(false)
271     , m_wasActivatedByMouseEvent(false)
272     , m_isBeingDestroyed(false)
273     , m_inIMEComposition(0)
274     , m_findIndicatorCallback(0)
275     , m_findIndicatorCallbackContext(0)
276     , m_lastPanX(0)
277     , m_lastPanY(0)
278     , m_overPanY(0)
279     , m_gestureReachedScrollingLimit(false)
280 {
281     registerWebViewWindowClass();
282
283     m_window = ::CreateWindowExW(0, kWebKit2WebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
284         rect.top, rect.left, rect.right - rect.left, rect.bottom - rect.top, parentWindow ? parentWindow : HWND_MESSAGE, 0, instanceHandle(), this);
285     ASSERT(::IsWindow(m_window));
286     // We only check our window style, and not ::IsWindowVisible, because m_isVisible only tracks
287     // this window's visibility status, while ::IsWindowVisible takes our ancestors' visibility
288     // status into account. <http://webkit.org/b/54104>
289     ASSERT(m_isVisible == static_cast<bool>(::GetWindowLong(m_window, GWL_STYLE) & WS_VISIBLE));
290
291     m_page = context->createWebPage(this, pageGroup);
292     m_page->initializeWebPage();
293
294     CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, (void**)&m_dropTargetHelper);
295
296     // FIXME: Initializing the tooltip window here matches WebKit win, but seems like something
297     // we could do on demand to save resources.
298     initializeToolTipWindow();
299
300     // Initialize the top level parent window and register it with the WindowMessageBroadcaster.
301     windowAncestryDidChange();
302 }
303
304 WebView::~WebView()
305 {
306     // Tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD.
307     if (::IsWindow(m_toolTipWindow))
308         ::DestroyWindow(m_toolTipWindow);
309 }
310
311 void WebView::initialize()
312 {
313     ::RegisterDragDrop(m_window, this);
314
315     if (shouldInitializeTrackPointHack()) {
316         // If we detected a registry key belonging to a TrackPoint driver, then create fake
317         // scrollbars, so the WebView will receive WM_VSCROLL and WM_HSCROLL messages.
318         // We create an invisible vertical scrollbar and an invisible horizontal scrollbar to allow
319         // for receiving both types of messages.
320         ::CreateWindow(TEXT("SCROLLBAR"), TEXT("FAKETRACKPOINTHSCROLLBAR"), WS_CHILD | WS_VISIBLE | SBS_HORZ, 0, 0, 0, 0, m_window, 0, instanceHandle(), 0);
321         ::CreateWindow(TEXT("SCROLLBAR"), TEXT("FAKETRACKPOINTVSCROLLBAR"), WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0, m_window, 0, instanceHandle(), 0);
322     }
323 }
324
325 void WebView::initializeUndoClient(const WKViewUndoClient* client)
326 {
327     m_undoClient.initialize(client);
328 }
329
330 void WebView::setParentWindow(HWND parentWindow)
331 {
332     if (m_window) {
333         // If the host window hasn't changed, bail.
334         if (::GetParent(m_window) == parentWindow)
335             return;
336         if (parentWindow)
337             ::SetParent(m_window, parentWindow);
338         else if (!m_isBeingDestroyed) {
339             // Turn the WebView into a message-only window so it will no longer be a child of the
340             // old parent window and will be hidden from screen. We only do this when
341             // isBeingDestroyed() is false because doing this while handling WM_DESTROY can leave
342             // m_window in a weird state (see <http://webkit.org/b/29337>).
343             ::SetParent(m_window, HWND_MESSAGE);
344         }
345     }
346
347     windowAncestryDidChange();
348 }
349
350 static HWND findTopLevelParentWindow(HWND window)
351 {
352     if (!window)
353         return 0;
354
355     HWND current = window;
356     for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent)) {
357         if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
358             return current;
359     }
360     ASSERT_NOT_REACHED();
361     return 0;
362 }
363
364 void WebView::windowAncestryDidChange()
365 {
366     HWND newTopLevelParentWindow;
367     if (m_window)
368         newTopLevelParentWindow = findTopLevelParentWindow(m_window);
369     else {
370         // There's no point in tracking active state changes of our parent window if we don't have
371         // a window ourselves.
372         newTopLevelParentWindow = 0;
373     }
374
375     if (newTopLevelParentWindow == m_topLevelParentWindow)
376         return;
377
378     if (m_topLevelParentWindow)
379         WindowMessageBroadcaster::removeListener(m_topLevelParentWindow, this);
380
381     m_topLevelParentWindow = newTopLevelParentWindow;
382
383     if (m_topLevelParentWindow)
384         WindowMessageBroadcaster::addListener(m_topLevelParentWindow, this);
385
386     updateActiveState();
387 }
388
389 LRESULT WebView::onMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
390 {
391     NativeWebMouseEvent mouseEvent = NativeWebMouseEvent(hWnd, message, wParam, lParam, m_wasActivatedByMouseEvent);
392     setWasActivatedByMouseEvent(false);
393     
394     switch (message) {
395     case WM_LBUTTONDOWN:
396     case WM_MBUTTONDOWN:
397     case WM_RBUTTONDOWN:
398         ::SetFocus(m_window);
399         ::SetCapture(m_window);
400         break; 
401     case WM_LBUTTONUP:
402     case WM_MBUTTONUP:
403     case WM_RBUTTONUP:
404         ::ReleaseCapture();
405         break;
406     case WM_MOUSEMOVE:
407         startTrackingMouseLeave();
408         break;
409     case WM_MOUSELEAVE:
410         stopTrackingMouseLeave();
411         break;
412     case WM_LBUTTONDBLCLK:
413     case WM_MBUTTONDBLCLK:
414     case WM_RBUTTONDBLCLK:
415         break;
416     default:
417         ASSERT_NOT_REACHED();
418     }
419
420     m_page->handleMouseEvent(mouseEvent);
421
422     handled = true;
423     return 0;
424 }
425
426 LRESULT WebView::onWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
427 {
428     WebWheelEvent wheelEvent = WebEventFactory::createWebWheelEvent(hWnd, message, wParam, lParam);
429     if (wheelEvent.controlKey()) {
430         // We do not want WebKit to handle Control + Wheel, this should be handled by the client application
431         // to zoom the page.
432         handled = false;
433         return 0;
434     }
435
436     m_page->handleWheelEvent(wheelEvent);
437
438     handled = true;
439     return 0;
440 }
441
442 LRESULT WebView::onHorizontalScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
443 {
444     ScrollDirection direction;
445     ScrollGranularity granularity;
446     switch (LOWORD(wParam)) {
447     case SB_LINELEFT:
448         granularity = ScrollByLine;
449         direction = ScrollLeft;
450         break;
451     case SB_LINERIGHT:
452         granularity = ScrollByLine;
453         direction = ScrollRight;
454         break;
455     case SB_PAGELEFT:
456         granularity = ScrollByDocument;
457         direction = ScrollLeft;
458         break;
459     case SB_PAGERIGHT:
460         granularity = ScrollByDocument;
461         direction = ScrollRight;
462         break;
463     default:
464         handled = false;
465         return 0;
466     }
467
468     m_page->scrollBy(direction, granularity);
469
470     handled = true;
471     return 0;
472 }
473
474 LRESULT WebView::onVerticalScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
475 {
476     ScrollDirection direction;
477     ScrollGranularity granularity;
478     switch (LOWORD(wParam)) {
479     case SB_LINEDOWN:
480         granularity = ScrollByLine;
481         direction = ScrollDown;
482         break;
483     case SB_LINEUP:
484         granularity = ScrollByLine;
485         direction = ScrollUp;
486         break;
487     case SB_PAGEDOWN:
488         granularity = ScrollByDocument;
489         direction = ScrollDown;
490         break;
491     case SB_PAGEUP:
492         granularity = ScrollByDocument;
493         direction = ScrollUp;
494         break;
495     default:
496         handled = false;
497         return 0;
498     }
499
500     m_page->scrollBy(direction, granularity);
501
502     handled = true;
503     return 0;
504 }
505
506 LRESULT WebView::onGestureNotify(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
507 {
508     // We shouldn't be getting any gesture messages without SetGestureConfig soft-linking correctly.
509     ASSERT(SetGestureConfigPtr());
510
511     GESTURENOTIFYSTRUCT* gn = reinterpret_cast<GESTURENOTIFYSTRUCT*>(lParam);
512
513     POINT localPoint = { gn->ptsLocation.x, gn->ptsLocation.y };
514     ::ScreenToClient(m_window, &localPoint);
515
516     bool canPan = m_page->gestureWillBegin(localPoint);
517
518     DWORD dwPanWant = GC_PAN | GC_PAN_WITH_INERTIA | GC_PAN_WITH_GUTTER;
519     DWORD dwPanBlock = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
520     if (canPan)
521         dwPanWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
522     else
523         dwPanBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
524
525     GESTURECONFIG gc = { GID_PAN, dwPanWant, dwPanBlock };
526     return SetGestureConfigPtr()(m_window, 0, 1, &gc, sizeof(gc));
527 }
528
529 LRESULT WebView::onGesture(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
530 {
531     ASSERT(GetGestureInfoPtr());
532     ASSERT(CloseGestureInfoHandlePtr());
533     ASSERT(UpdatePanningFeedbackPtr());
534     ASSERT(BeginPanningFeedbackPtr());
535     ASSERT(EndPanningFeedbackPtr());
536
537     if (!GetGestureInfoPtr() || !CloseGestureInfoHandlePtr() || !UpdatePanningFeedbackPtr() || !BeginPanningFeedbackPtr() || !EndPanningFeedbackPtr()) {
538         handled = false;
539         return 0;
540     }
541
542     HGESTUREINFO gestureHandle = reinterpret_cast<HGESTUREINFO>(lParam);
543     GESTUREINFO gi = {0};
544     gi.cbSize = sizeof(GESTUREINFO);
545
546     if (!GetGestureInfoPtr()(gestureHandle, &gi)) {
547         handled = false;
548         return 0;
549     }
550
551     switch (gi.dwID) {
552     case GID_BEGIN:
553         m_lastPanX = gi.ptsLocation.x;
554         m_lastPanY = gi.ptsLocation.y;
555         break;
556     case GID_END:
557         m_page->gestureDidEnd();
558         break;
559     case GID_PAN: {
560         int currentX = gi.ptsLocation.x;
561         int currentY = gi.ptsLocation.y;
562
563         // Reverse the calculations because moving your fingers up should move the screen down, and
564         // vice-versa.
565         int deltaX = m_lastPanX - currentX;
566         int deltaY = m_lastPanY - currentY;
567
568         m_lastPanX = currentX;
569         m_lastPanY = currentY;
570
571         // Calculate the overpan for window bounce.
572         m_overPanY -= deltaY;
573
574         if (deltaX || deltaY)
575             m_page->gestureDidScroll(IntSize(deltaX, deltaY));
576
577         if (gi.dwFlags & GF_BEGIN) {
578             BeginPanningFeedbackPtr()(m_window);
579             m_gestureReachedScrollingLimit = false;
580             m_overPanY = 0;
581         } else if (gi.dwFlags & GF_END) {
582             EndPanningFeedbackPtr()(m_window, true);
583             m_overPanY = 0;
584         }
585
586         // FIXME: Support horizontal window bounce - <http://webkit.org/b/58068>.
587         // FIXME: Window Bounce doesn't undo until user releases their finger - <http://webkit.org/b/58069>.
588
589         if (m_gestureReachedScrollingLimit)
590             UpdatePanningFeedbackPtr()(m_window, 0, m_overPanY, gi.dwFlags & GF_INERTIA);
591
592         CloseGestureInfoHandlePtr()(gestureHandle);
593
594         handled = true;
595         return 0;
596     }
597     default:
598         break;
599     }
600
601     // If we get to this point, the gesture has not been handled. We forward
602     // the call to DefWindowProc by returning false, and we don't need to 
603     // to call CloseGestureInfoHandle. 
604     // http://msdn.microsoft.com/en-us/library/dd353228(VS.85).aspx
605     handled = false;
606     return 0;
607 }
608
609 LRESULT WebView::onKeyEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
610 {
611     m_page->handleKeyboardEvent(NativeWebKeyboardEvent(hWnd, message, wParam, lParam));
612
613     // We claim here to always have handled the event. If the event is not in fact handled, we will
614     // find out later in didNotHandleKeyEvent.
615     handled = true;
616     return 0;
617 }
618
619 static void drawPageBackground(HDC dc, const RECT& rect)
620 {
621     // Mac checks WebPageProxy::drawsBackground and
622     // WebPageProxy::drawsTransparentBackground here, but those are always false on
623     // Windows currently (see <http://webkit.org/b/52009>).
624     ::FillRect(dc, &rect, reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1));
625 }
626
627 void WebView::paint(HDC hdc, const IntRect& dirtyRect)
628 {
629     m_page->endPrinting();
630     if (useNewDrawingArea()) {
631         if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(m_page->drawingArea())) {
632             // FIXME: We should port WebKit1's rect coalescing logic here.
633             Region unpaintedRegion;
634             drawingArea->paint(hdc, dirtyRect, unpaintedRegion);
635
636             Vector<IntRect> unpaintedRects = unpaintedRegion.rects();
637             for (size_t i = 0; i < unpaintedRects.size(); ++i) {
638                 RECT winRect = unpaintedRects[i];
639                 drawPageBackground(hdc, unpaintedRects[i]);
640             }
641         } else
642             drawPageBackground(hdc, dirtyRect);
643
644         m_page->didDraw();
645     } else {
646         if (m_page->isValid() && m_page->drawingArea() && m_page->drawingArea()->paint(dirtyRect, hdc))
647             m_page->didDraw();
648         else
649             drawPageBackground(hdc, dirtyRect);
650     }
651 }
652
653 static void flashRects(HDC dc, const IntRect rects[], size_t rectCount, HBRUSH brush)
654 {
655     for (size_t i = 0; i < rectCount; ++i) {
656         RECT winRect = rects[i];
657         ::FillRect(dc, &winRect, brush);
658     }
659
660     ::GdiFlush();
661     ::Sleep(50);
662 }
663
664 static OwnPtr<HBRUSH> createBrush(const Color& color)
665 {
666     return adoptPtr(::CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
667 }
668
669 LRESULT WebView::onPaintEvent(HWND hWnd, UINT message, WPARAM, LPARAM, bool& handled)
670 {
671     PAINTSTRUCT paintStruct;
672     HDC hdc = ::BeginPaint(m_window, &paintStruct);
673
674     if (WebPageProxy::debugPaintFlags() & kWKDebugFlashViewUpdates) {
675         static HBRUSH brush = createBrush(WebPageProxy::viewUpdatesFlashColor().rgb()).leakPtr();
676         IntRect rect = paintStruct.rcPaint;
677         flashRects(hdc, &rect, 1, brush);
678     }
679
680     paint(hdc, paintStruct.rcPaint);
681
682     ::EndPaint(m_window, &paintStruct);
683
684     handled = true;
685     return 0;
686 }
687
688 LRESULT WebView::onPrintClientEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
689 {
690     HDC hdc = reinterpret_cast<HDC>(wParam);
691     RECT winRect;
692     ::GetClientRect(hWnd, &winRect);
693
694     // Twidding the visibility flags tells the DrawingArea to resume painting. Right now, the
695     // the visible state of the view only affects whether or not painting happens, but in the
696     // future it could affect more, which we wouldn't want to touch here.
697
698     // FIXME: We should have a better way of telling the WebProcess to draw even if we're
699     // invisible than twiddling the visibility flag.
700
701     bool wasVisible = isViewVisible();
702     if (!wasVisible)
703         setIsVisible(true);
704
705     paint(hdc, winRect);
706
707     if (!wasVisible)
708         setIsVisible(false);
709
710     handled = true;
711     return 0;
712 }
713
714 LRESULT WebView::onSizeEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
715 {
716     int width = LOWORD(lParam);
717     int height = HIWORD(lParam);
718
719     if (m_page && m_page->drawingArea()) {
720         m_page->drawingArea()->setSize(IntSize(width, height), m_nextResizeScrollOffset);
721         m_nextResizeScrollOffset = IntSize();
722     }
723
724     handled = true;
725     return 0;
726 }
727
728 LRESULT WebView::onWindowPositionChangedEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
729 {
730     if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
731         updateActiveStateSoon();
732
733     handled = false;
734     return 0;
735 }
736
737 LRESULT WebView::onSetFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
738 {
739     m_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
740     handled = true;
741     return 0;
742 }
743
744 LRESULT WebView::onKillFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
745 {
746     m_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
747     handled = true;
748     return 0;
749 }
750
751 LRESULT WebView::onTimerEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
752 {
753     switch (wParam) {
754     case UpdateActiveStateTimer:
755         ::KillTimer(hWnd, UpdateActiveStateTimer);
756         updateActiveState();
757         break;
758     }
759
760     handled = true;
761     return 0;
762 }
763
764 LRESULT WebView::onShowWindowEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
765 {
766     // lParam is 0 when the message is sent because of a ShowWindow call.
767     // FIXME: Since we don't get notified when an ancestor window is hidden or shown, we will keep
768     // painting even when we have a hidden ancestor. <http://webkit.org/b/54104>
769     if (!lParam)
770         setIsVisible(wParam);
771
772     handled = false;
773     return 0;
774 }
775
776 LRESULT WebView::onSetCursor(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
777 {
778     if (!m_lastCursorSet) {
779         handled = false;
780         return 0;
781     }
782
783     ::SetCursor(m_lastCursorSet);
784     return 0;
785 }
786
787 void WebView::updateActiveState()
788 {
789     m_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
790 }
791
792 void WebView::updateActiveStateSoon()
793 {
794     // This function is called while processing the WM_NCACTIVATE message.
795     // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
796     // still return our window. If we were to call updateActiveState() in that case, we would
797     // wrongly think that we are still the active window. To work around this, we update our
798     // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
799     // the newly-activated window.
800
801     ::SetTimer(m_window, UpdateActiveStateTimer, 0, 0);
802 }
803
804 static bool initCommonControls()
805 {
806     static bool haveInitialized = false;
807     if (haveInitialized)
808         return true;
809
810     INITCOMMONCONTROLSEX init;
811     init.dwSize = sizeof(init);
812     init.dwICC = ICC_TREEVIEW_CLASSES;
813     haveInitialized = !!::InitCommonControlsEx(&init);
814     return haveInitialized;
815 }
816
817 void WebView::initializeToolTipWindow()
818 {
819     if (!initCommonControls())
820         return;
821
822     m_toolTipWindow = ::CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
823                                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
824                                        m_window, 0, 0, 0);
825     if (!m_toolTipWindow)
826         return;
827
828     TOOLINFO info = {0};
829     info.cbSize = sizeof(info);
830     info.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
831     info.uId = reinterpret_cast<UINT_PTR>(m_window);
832
833     ::SendMessage(m_toolTipWindow, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
834     ::SendMessage(m_toolTipWindow, TTM_SETMAXTIPWIDTH, 0, kMaxToolTipWidth);
835     ::SetWindowPos(m_toolTipWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
836 }
837
838 void WebView::startTrackingMouseLeave()
839 {
840     if (m_trackingMouseLeave)
841         return;
842     m_trackingMouseLeave = true;
843
844     TRACKMOUSEEVENT trackMouseEvent;
845     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
846     trackMouseEvent.dwFlags = TME_LEAVE;
847     trackMouseEvent.hwndTrack = m_window;
848
849     ::TrackMouseEvent(&trackMouseEvent);
850 }
851
852 void WebView::stopTrackingMouseLeave()
853 {
854     if (!m_trackingMouseLeave)
855         return;
856     m_trackingMouseLeave = false;
857
858     TRACKMOUSEEVENT trackMouseEvent;
859     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
860     trackMouseEvent.dwFlags = TME_LEAVE | TME_CANCEL;
861     trackMouseEvent.hwndTrack = m_window;
862
863     ::TrackMouseEvent(&trackMouseEvent);
864 }
865
866 bool WebView::shouldInitializeTrackPointHack()
867 {
868     static bool shouldCreateScrollbars;
869     static bool hasRunTrackPointCheck;
870
871     if (hasRunTrackPointCheck)
872         return shouldCreateScrollbars;
873
874     hasRunTrackPointCheck = true;
875     const wchar_t* trackPointKeys[] = { 
876         L"Software\\Lenovo\\TrackPoint",
877         L"Software\\Lenovo\\UltraNav",
878         L"Software\\Alps\\Apoint\\TrackPoint",
879         L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB",
880         L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2"
881     };
882
883     for (size_t i = 0; i < WTF_ARRAY_LENGTH(trackPointKeys); ++i) {
884         HKEY trackPointKey;
885         int readKeyResult = ::RegOpenKeyExW(HKEY_CURRENT_USER, trackPointKeys[i], 0, KEY_READ, &trackPointKey);
886         ::RegCloseKey(trackPointKey);
887         if (readKeyResult == ERROR_SUCCESS) {
888             shouldCreateScrollbars = true;
889             return shouldCreateScrollbars;
890         }
891     }
892
893     return shouldCreateScrollbars;
894 }
895
896 void WebView::close()
897 {
898     m_undoClient.initialize(0);
899     ::RevokeDragDrop(m_window);
900     if (m_window) {
901         // We can't check IsWindow(m_window) here, because that will return true even while
902         // we're already handling WM_DESTROY. So we check !m_isBeingDestroyed instead.
903         if (!m_isBeingDestroyed)
904             DestroyWindow(m_window);
905         // Either we just destroyed m_window, or it's in the process of being destroyed. Either
906         // way, we clear it out to make sure we don't try to use it later.
907         m_window = 0;
908     }
909     setParentWindow(0);
910     m_page->close();
911 }
912
913 // PageClient
914
915 PassOwnPtr<DrawingAreaProxy> WebView::createDrawingAreaProxy()
916 {
917     if (useNewDrawingArea())
918         return DrawingAreaProxyImpl::create(m_page.get());
919
920     return ChunkedUpdateDrawingAreaProxy::create(this, m_page.get());
921 }
922
923 void WebView::setViewNeedsDisplay(const WebCore::IntRect& rect)
924 {
925     RECT r = rect;
926     ::InvalidateRect(m_window, &r, false);
927 }
928
929 void WebView::displayView()
930 {
931     ::UpdateWindow(m_window);
932 }
933
934 void WebView::scrollView(const IntRect& scrollRect, const IntSize& scrollOffset)
935 {
936     // FIXME: Actually scroll the view contents.
937     setViewNeedsDisplay(scrollRect);
938 }
939
940 void WebView::flashBackingStoreUpdates(const Vector<IntRect>& updateRects)
941 {
942     static HBRUSH brush = createBrush(WebPageProxy::backingStoreUpdatesFlashColor().rgb()).leakPtr();
943     HDC dc = ::GetDC(m_window);
944     flashRects(dc, updateRects.data(), updateRects.size(), brush);
945     ::ReleaseDC(m_window, dc);
946 }
947
948 WebCore::IntSize WebView::viewSize()
949 {
950     RECT clientRect;
951     GetClientRect(m_window, &clientRect);
952
953     return IntRect(clientRect).size();
954 }
955
956 bool WebView::isViewWindowActive()
957 {    
958     HWND activeWindow = ::GetActiveWindow();
959     return (activeWindow && m_topLevelParentWindow == findTopLevelParentWindow(activeWindow));
960 }
961
962 bool WebView::isViewFocused()
963 {
964     return ::GetFocus() == m_window;
965 }
966
967 bool WebView::isViewVisible()
968 {
969     return m_isVisible;
970 }
971
972 bool WebView::isViewInWindow()
973 {
974     return m_isInWindow;
975 }
976
977 void WebView::pageClosed()
978 {
979 }
980
981 void WebView::processDidCrash()
982 {
983     updateNativeCursor();
984     ::InvalidateRect(m_window, 0, TRUE);
985 }
986
987 void WebView::didRelaunchProcess()
988 {
989     updateNativeCursor();
990     ::InvalidateRect(m_window, 0, TRUE);
991 }
992
993 void WebView::toolTipChanged(const String&, const String& newToolTip)
994 {
995     if (!m_toolTipWindow)
996         return;
997
998     if (!newToolTip.isEmpty()) {
999         // This is necessary because String::charactersWithNullTermination() is not const.
1000         String toolTip = newToolTip;
1001
1002         TOOLINFO info = {0};
1003         info.cbSize = sizeof(info);
1004         info.uFlags = TTF_IDISHWND;
1005         info.uId = reinterpret_cast<UINT_PTR>(m_window);
1006         info.lpszText = const_cast<UChar*>(toolTip.charactersWithNullTermination());
1007         ::SendMessage(m_toolTipWindow, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
1008     }
1009
1010     ::SendMessage(m_toolTipWindow, TTM_ACTIVATE, !newToolTip.isEmpty(), 0);
1011 }
1012
1013 HCURSOR WebView::cursorToShow() const
1014 {
1015     if (!m_page->isValid())
1016         return 0;
1017
1018     // We only show the override cursor if the default (arrow) cursor is showing.
1019     static HCURSOR arrowCursor = ::LoadCursor(0, IDC_ARROW);
1020     if (m_overrideCursor && m_webCoreCursor == arrowCursor)
1021         return m_overrideCursor;
1022
1023     return m_webCoreCursor;
1024 }
1025
1026 void WebView::updateNativeCursor()
1027 {
1028     m_lastCursorSet = cursorToShow();
1029     if (!m_lastCursorSet)
1030         return;
1031     ::SetCursor(m_lastCursorSet);
1032 }
1033
1034 void WebView::setCursor(const WebCore::Cursor& cursor)
1035 {
1036     if (!cursor.platformCursor()->nativeCursor())
1037         return;
1038     m_webCoreCursor = cursor.platformCursor()->nativeCursor();
1039     updateNativeCursor();
1040 }
1041
1042 void WebView::setOverrideCursor(HCURSOR overrideCursor)
1043 {
1044     m_overrideCursor = overrideCursor;
1045     updateNativeCursor();
1046 }
1047
1048 void WebView::setInitialFocus(bool forward)
1049 {
1050     m_page->setInitialFocus(forward);
1051 }
1052
1053 void WebView::setScrollOffsetOnNextResize(const IntSize& scrollOffset)
1054 {
1055     // The next time we get a WM_SIZE message, scroll by the specified amount in onSizeEvent().
1056     m_nextResizeScrollOffset = scrollOffset;
1057 }
1058
1059 void WebView::setViewportArguments(const WebCore::ViewportArguments&)
1060 {
1061 }
1062
1063 void WebView::registerEditCommand(PassRefPtr<WebEditCommandProxy> prpCommand, WebPageProxy::UndoOrRedo undoOrRedo)
1064 {
1065     RefPtr<WebEditCommandProxy> command = prpCommand;
1066     m_undoClient.registerEditCommand(this, command, undoOrRedo);
1067 }
1068
1069 void WebView::clearAllEditCommands()
1070 {
1071     m_undoClient.clearAllEditCommands(this);
1072 }
1073
1074 bool WebView::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
1075 {
1076     return m_undoClient.canUndoRedo(this, undoOrRedo);
1077 }
1078
1079 void WebView::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
1080 {
1081     m_undoClient.executeUndoRedo(this, undoOrRedo);
1082 }
1083     
1084 void WebView::reapplyEditCommand(WebEditCommandProxy* command)
1085 {
1086     if (!m_page->isValid() || !m_page->isValidEditCommand(command))
1087         return;
1088     
1089     command->reapply();
1090 }
1091
1092 void WebView::unapplyEditCommand(WebEditCommandProxy* command)
1093 {
1094     if (!m_page->isValid() || !m_page->isValidEditCommand(command))
1095         return;
1096     
1097     command->unapply();
1098 }
1099
1100 FloatRect WebView::convertToDeviceSpace(const FloatRect& rect)
1101 {
1102     return rect;
1103 }
1104
1105 IntRect WebView::windowToScreen(const IntRect& rect)
1106 {
1107     return rect;
1108 }
1109
1110 FloatRect WebView::convertToUserSpace(const FloatRect& rect)
1111 {
1112     return rect;
1113 }
1114
1115 HIMC WebView::getIMMContext() 
1116 {
1117     return Ime::ImmGetContext(m_window);
1118 }
1119
1120 void WebView::prepareCandidateWindow(HIMC hInputContext) 
1121 {
1122     IntRect caret = m_page->firstRectForCharacterInSelectedRange(0);
1123     CANDIDATEFORM form;
1124     form.dwIndex = 0;
1125     form.dwStyle = CFS_EXCLUDE;
1126     form.ptCurrentPos.x = caret.x();
1127     form.ptCurrentPos.y = caret.maxY();
1128     form.rcArea.top = caret.y();
1129     form.rcArea.bottom = caret.maxY();
1130     form.rcArea.left = caret.x();
1131     form.rcArea.right = caret.maxX();
1132     Ime::ImmSetCandidateWindow(hInputContext, &form);
1133 }
1134
1135 void WebView::resetIME()
1136 {
1137     HIMC hInputContext = getIMMContext();
1138     if (!hInputContext)
1139         return;
1140     Ime::ImmNotifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
1141     Ime::ImmReleaseContext(m_window, hInputContext);
1142 }
1143
1144 void WebView::setInputMethodState(bool enabled)
1145 {
1146     Ime::ImmAssociateContextEx(m_window, 0, enabled ? IACE_DEFAULT : 0);
1147 }
1148
1149 void WebView::compositionSelectionChanged(bool hasChanged)
1150 {
1151     if (m_page->editorState().hasComposition && !hasChanged)
1152         resetIME();
1153 }
1154
1155 bool WebView::onIMEStartComposition()
1156 {
1157     LOG(TextInput, "onIMEStartComposition");
1158     m_inIMEComposition++;
1159
1160     HIMC hInputContext = getIMMContext();
1161     if (!hInputContext)
1162         return false;
1163     prepareCandidateWindow(hInputContext);
1164     Ime::ImmReleaseContext(m_window, hInputContext);
1165     return true;
1166 }
1167
1168 static bool getCompositionString(HIMC hInputContext, DWORD type, String& result)
1169 {
1170     LONG compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, 0, 0);
1171     if (compositionLength <= 0)
1172         return false;
1173     Vector<UChar> compositionBuffer(compositionLength / 2);
1174     compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, compositionBuffer.data(), compositionLength);
1175     result = String::adopt(compositionBuffer);
1176     return true;
1177 }
1178
1179 static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, Vector<CompositionUnderline>& underlines)
1180 {
1181     if (clauses.isEmpty()) {
1182         underlines.clear();
1183         return;
1184     }
1185   
1186     size_t numBoundaries = clauses.size() - 1;
1187     underlines.resize(numBoundaries);
1188     for (unsigned i = 0; i < numBoundaries; ++i) {
1189         underlines[i].startOffset = clauses[i];
1190         underlines[i].endOffset = clauses[i + 1];
1191         BYTE attribute = attributes[clauses[i]];
1192         underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED;
1193         underlines[i].color = Color::black;
1194     }
1195 }
1196
1197 #if !LOG_DISABLED
1198 #define APPEND_ARGUMENT_NAME(name) \
1199     if (lparam & name) { \
1200         if (needsComma) \
1201             result += ", "; \
1202             result += #name; \
1203         needsComma = true; \
1204     }
1205
1206 static String imeCompositionArgumentNames(LPARAM lparam)
1207 {
1208     String result;
1209     bool needsComma = false;
1210
1211     APPEND_ARGUMENT_NAME(GCS_COMPATTR);
1212     APPEND_ARGUMENT_NAME(GCS_COMPCLAUSE);
1213     APPEND_ARGUMENT_NAME(GCS_COMPREADSTR);
1214     APPEND_ARGUMENT_NAME(GCS_COMPREADATTR);
1215     APPEND_ARGUMENT_NAME(GCS_COMPREADCLAUSE);
1216     APPEND_ARGUMENT_NAME(GCS_COMPSTR);
1217     APPEND_ARGUMENT_NAME(GCS_CURSORPOS);
1218     APPEND_ARGUMENT_NAME(GCS_DELTASTART);
1219     APPEND_ARGUMENT_NAME(GCS_RESULTCLAUSE);
1220     APPEND_ARGUMENT_NAME(GCS_RESULTREADCLAUSE);
1221     APPEND_ARGUMENT_NAME(GCS_RESULTREADSTR);
1222     APPEND_ARGUMENT_NAME(GCS_RESULTSTR);
1223     APPEND_ARGUMENT_NAME(CS_INSERTCHAR);
1224     APPEND_ARGUMENT_NAME(CS_NOMOVECARET);
1225
1226     return result;
1227 }
1228
1229 static String imeRequestName(WPARAM wparam)
1230 {
1231     switch (wparam) {
1232     case IMR_CANDIDATEWINDOW:
1233         return "IMR_CANDIDATEWINDOW";
1234     case IMR_COMPOSITIONFONT:
1235         return "IMR_COMPOSITIONFONT";
1236     case IMR_COMPOSITIONWINDOW:
1237         return "IMR_COMPOSITIONWINDOW";
1238     case IMR_CONFIRMRECONVERTSTRING:
1239         return "IMR_CONFIRMRECONVERTSTRING";
1240     case IMR_DOCUMENTFEED:
1241         return "IMR_DOCUMENTFEED";
1242     case IMR_QUERYCHARPOSITION:
1243         return "IMR_QUERYCHARPOSITION";
1244     case IMR_RECONVERTSTRING:
1245         return "IMR_RECONVERTSTRING";
1246     default:
1247         return "Unknown (" + String::number(wparam) + ")";
1248     }
1249 }
1250 #endif
1251
1252 bool WebView::onIMEComposition(LPARAM lparam)
1253 {
1254     LOG(TextInput, "onIMEComposition %s", imeCompositionArgumentNames(lparam).latin1().data());
1255     HIMC hInputContext = getIMMContext();
1256     if (!hInputContext)
1257         return true;
1258
1259     if (!m_page->editorState().isContentEditable)
1260         return true;
1261
1262     prepareCandidateWindow(hInputContext);
1263
1264     if (lparam & GCS_RESULTSTR || !lparam) {
1265         String compositionString;
1266         if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam)
1267             return true;
1268         
1269         m_page->confirmComposition(compositionString);
1270         return true;
1271     }
1272
1273     String compositionString;
1274     if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString))
1275         return true;
1276     
1277     // Composition string attributes
1278     int numAttributes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, 0, 0);
1279     Vector<BYTE> attributes(numAttributes);
1280     Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, attributes.data(), numAttributes);
1281
1282     // Get clauses
1283     int numBytes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, 0, 0);
1284     Vector<DWORD> clauses(numBytes / sizeof(DWORD));
1285     Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, clauses.data(), numBytes);
1286
1287     Vector<CompositionUnderline> underlines;
1288     compositionToUnderlines(clauses, attributes, underlines);
1289
1290     int cursorPosition = LOWORD(Ime::ImmGetCompositionStringW(hInputContext, GCS_CURSORPOS, 0, 0));
1291
1292     m_page->setComposition(compositionString, underlines, cursorPosition);
1293
1294     return true;
1295 }
1296
1297 bool WebView::onIMEEndComposition()
1298 {
1299     LOG(TextInput, "onIMEEndComposition");
1300     // If the composition hasn't been confirmed yet, it needs to be cancelled.
1301     // This happens after deleting the last character from inline input hole.
1302     if (m_page->editorState().hasComposition)
1303         m_page->confirmComposition(String());
1304
1305     if (m_inIMEComposition)
1306         m_inIMEComposition--;
1307
1308     return true;
1309 }
1310
1311 LRESULT WebView::onIMERequestCharPosition(IMECHARPOSITION* charPos)
1312 {
1313     if (charPos->dwCharPos && !m_page->editorState().hasComposition)
1314         return 0;
1315     IntRect caret = m_page->firstRectForCharacterInSelectedRange(charPos->dwCharPos);
1316     charPos->pt.x = caret.x();
1317     charPos->pt.y = caret.y();
1318     ::ClientToScreen(m_window, &charPos->pt);
1319     charPos->cLineHeight = caret.height();
1320     ::GetWindowRect(m_window, &charPos->rcDocument);
1321     return true;
1322 }
1323
1324 LRESULT WebView::onIMERequestReconvertString(RECONVERTSTRING* reconvertString)
1325 {
1326     String text = m_page->getSelectedText();
1327     unsigned totalSize = sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
1328     
1329     if (!reconvertString)
1330         return totalSize;
1331
1332     if (totalSize > reconvertString->dwSize)
1333         return 0;
1334     reconvertString->dwCompStrLen = text.length();
1335     reconvertString->dwStrLen = text.length();
1336     reconvertString->dwTargetStrLen = text.length();
1337     reconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
1338     memcpy(reconvertString + 1, text.characters(), text.length() * sizeof(UChar));
1339     return totalSize;
1340 }
1341
1342 LRESULT WebView::onIMERequest(WPARAM request, LPARAM data)
1343 {
1344     LOG(TextInput, "onIMERequest %s", imeRequestName(request).latin1().data());
1345     if (!m_page->editorState().isContentEditable)
1346         return 0;
1347
1348     switch (request) {
1349     case IMR_RECONVERTSTRING:
1350         return onIMERequestReconvertString(reinterpret_cast<RECONVERTSTRING*>(data));
1351
1352     case IMR_QUERYCHARPOSITION:
1353         return onIMERequestCharPosition(reinterpret_cast<IMECHARPOSITION*>(data));
1354     }
1355     return 0;
1356 }
1357
1358 bool WebView::onIMESelect(WPARAM wparam, LPARAM lparam)
1359 {
1360     UNUSED_PARAM(wparam);
1361     UNUSED_PARAM(lparam);
1362     LOG(TextInput, "onIMESelect locale %ld %s", lparam, wparam ? "select" : "deselect");
1363     return false;
1364 }
1365
1366 bool WebView::onIMESetContext(WPARAM wparam, LPARAM)
1367 {
1368     LOG(TextInput, "onIMESetContext %s", wparam ? "active" : "inactive");
1369     return false;
1370 }
1371
1372 void WebView::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool wasEventHandled)
1373 {
1374     // Calling ::DefWindowProcW will ensure that pressing the Alt key will generate a WM_SYSCOMMAND
1375     // event, e.g. See <http://webkit.org/b/47671>.
1376     if (!wasEventHandled)
1377         ::DefWindowProcW(event.nativeEvent()->hwnd, event.nativeEvent()->message, event.nativeEvent()->wParam, event.nativeEvent()->lParam);
1378 }
1379
1380 PassRefPtr<WebPopupMenuProxy> WebView::createPopupMenuProxy(WebPageProxy* page)
1381 {
1382     return WebPopupMenuProxyWin::create(this, page);
1383 }
1384
1385 PassRefPtr<WebContextMenuProxy> WebView::createContextMenuProxy(WebPageProxy* page)
1386 {
1387     return WebContextMenuProxyWin::create(m_window, page);
1388 }
1389
1390 void WebView::setFindIndicator(PassRefPtr<FindIndicator> prpFindIndicator, bool fadeOut)
1391 {
1392     if (!m_findIndicatorCallback)
1393         return;
1394
1395     HBITMAP hbmp = 0;
1396     IntRect selectionRect;
1397
1398     if (RefPtr<FindIndicator> findIndicator = prpFindIndicator) {
1399         if (ShareableBitmap* contentImage = findIndicator->contentImage()) {
1400             // Render the contentImage to an HBITMAP.
1401             void* bits;
1402             HDC hdc = ::CreateCompatibleDC(0);
1403             int width = contentImage->bounds().width();
1404             int height = contentImage->bounds().height();
1405             BitmapInfo bitmapInfo = BitmapInfo::create(contentImage->size());
1406
1407             hbmp = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0);
1408             HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp));
1409 #if USE(CG)
1410             RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(bits, width, height,
1411                 8, width * sizeof(RGBQUAD), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
1412
1413             GraphicsContext graphicsContext(context.get());
1414             contentImage->paint(graphicsContext, IntPoint(), contentImage->bounds());
1415 #else
1416             // FIXME: Implement!
1417 #endif
1418
1419             ::SelectObject(hdc, hbmpOld);
1420             ::DeleteDC(hdc);
1421         }
1422
1423         selectionRect = IntRect(findIndicator->selectionRectInWindowCoordinates());
1424     }
1425     
1426     // The callback is responsible for calling ::DeleteObject(hbmp).
1427     (*m_findIndicatorCallback)(toAPI(this), hbmp, selectionRect, fadeOut, m_findIndicatorCallbackContext);
1428 }
1429
1430 void WebView::setFindIndicatorCallback(WKViewFindIndicatorCallback callback, void* context)
1431 {
1432     m_findIndicatorCallback = callback;
1433     m_findIndicatorCallbackContext = context;
1434 }
1435
1436 WKViewFindIndicatorCallback WebView::getFindIndicatorCallback(void** context)
1437 {
1438     if (context)
1439         *context = m_findIndicatorCallbackContext;
1440     
1441     return m_findIndicatorCallback;
1442 }
1443
1444 void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
1445 {
1446 }
1447
1448 void WebView::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
1449 {
1450 }
1451
1452 double WebView::customRepresentationZoomFactor()
1453 {
1454     return 1;
1455 }
1456
1457 void WebView::setCustomRepresentationZoomFactor(double)
1458 {
1459 }
1460
1461 void WebView::didChangeScrollbarsForMainFrame() const
1462 {
1463 }
1464
1465 void WebView::findStringInCustomRepresentation(const String&, FindOptions, unsigned)
1466 {
1467 }
1468
1469 void WebView::countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned)
1470 {
1471 }
1472
1473 void WebView::setIsInWindow(bool isInWindow)
1474 {
1475     m_isInWindow = isInWindow;
1476     m_page->viewStateDidChange(WebPageProxy::ViewIsInWindow);
1477 }
1478
1479 void WebView::setIsVisible(bool isVisible)
1480 {
1481     m_isVisible = isVisible;
1482
1483     if (m_page)
1484         m_page->viewStateDidChange(WebPageProxy::ViewIsVisible);
1485 }
1486
1487 #if USE(ACCELERATED_COMPOSITING)
1488
1489 void WebView::enterAcceleratedCompositingMode(const LayerTreeContext&)
1490 {
1491     ASSERT(useNewDrawingArea());
1492     // FIXME: Implement.
1493     ASSERT_NOT_REACHED();
1494 }
1495
1496 void WebView::exitAcceleratedCompositingMode()
1497 {
1498     ASSERT(useNewDrawingArea());
1499     // FIXME: Implement.
1500     ASSERT_NOT_REACHED();
1501 }
1502
1503 #endif // USE(ACCELERATED_COMPOSITING)
1504
1505 HWND WebView::nativeWindow()
1506 {
1507     return m_window;
1508 }
1509
1510 // WebCore::WindowMessageListener
1511
1512 void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
1513 {
1514     switch (message) {
1515     case WM_NCACTIVATE:
1516         updateActiveStateSoon();
1517         break;
1518     case WM_SETTINGCHANGE:
1519         // systemParameterChanged(wParam);
1520         break;
1521     }
1522 }
1523
1524 HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
1525 {
1526     *ppvObject = 0;
1527     if (IsEqualGUID(riid, IID_IUnknown))
1528         *ppvObject = static_cast<IUnknown*>(this);
1529     else if (IsEqualGUID(riid, IID_IDropTarget))
1530         *ppvObject = static_cast<IDropTarget*>(this);
1531     else
1532         return E_NOINTERFACE;
1533
1534     AddRef();
1535     return S_OK;
1536 }
1537
1538 ULONG STDMETHODCALLTYPE WebView::AddRef(void)
1539 {
1540     ref();
1541     return refCount();
1542 }
1543
1544 ULONG STDMETHODCALLTYPE WebView::Release(void)
1545 {
1546     deref();
1547     return refCount();
1548 }
1549
1550 static DWORD dragOperationToDragCursor(DragOperation op)
1551 {
1552     DWORD res = DROPEFFECT_NONE;
1553     if (op & DragOperationCopy) 
1554         res = DROPEFFECT_COPY;
1555     else if (op & DragOperationLink) 
1556         res = DROPEFFECT_LINK;
1557     else if (op & DragOperationMove) 
1558         res = DROPEFFECT_MOVE;
1559     else if (op & DragOperationGeneric) 
1560         res = DROPEFFECT_MOVE; // This appears to be the Firefox behaviour
1561     return res;
1562 }
1563
1564 WebCore::DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const
1565 {
1566     if (!m_page)
1567         return DragOperationNone;
1568
1569     // Conforms to Microsoft's key combinations as documented for 
1570     // IDropTarget::DragOver. Note, grfKeyState is the current 
1571     // state of the keyboard modifier keys on the keyboard. See:
1572     // <http://msdn.microsoft.com/en-us/library/ms680129(VS.85).aspx>.
1573     DragOperation operation = m_page->dragOperation();
1574
1575     if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
1576         operation = DragOperationLink;
1577     else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
1578         operation = DragOperationCopy;
1579     else if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
1580         operation = DragOperationGeneric;
1581
1582     return operation;
1583 }
1584
1585 HRESULT STDMETHODCALLTYPE WebView::DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1586 {
1587     m_dragData = 0;
1588     m_page->resetDragOperation();
1589
1590     if (m_dropTargetHelper)
1591         m_dropTargetHelper->DragEnter(m_window, pDataObject, (POINT*)&pt, *pdwEffect);
1592
1593     POINTL localpt = pt;
1594     ::ScreenToClient(m_window, (LPPOINT)&localpt);
1595     DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1596     m_page->dragEntered(&data);
1597     *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
1598
1599     m_lastDropEffect = *pdwEffect;
1600     m_dragData = pDataObject;
1601
1602     return S_OK;
1603 }
1604
1605 HRESULT STDMETHODCALLTYPE WebView::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1606 {
1607     if (m_dropTargetHelper)
1608         m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
1609
1610     if (m_dragData) {
1611         POINTL localpt = pt;
1612         ::ScreenToClient(m_window, (LPPOINT)&localpt);
1613         DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1614         m_page->dragUpdated(&data);
1615         *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
1616     } else
1617         *pdwEffect = DROPEFFECT_NONE;
1618
1619     m_lastDropEffect = *pdwEffect;
1620     return S_OK;
1621 }
1622
1623 HRESULT STDMETHODCALLTYPE WebView::DragLeave()
1624 {
1625     if (m_dropTargetHelper)
1626         m_dropTargetHelper->DragLeave();
1627
1628     if (m_dragData) {
1629         DragData data(m_dragData.get(), IntPoint(), IntPoint(), DragOperationNone);
1630         m_page->dragExited(&data);
1631         m_dragData = 0;
1632         m_page->resetDragOperation();
1633     }
1634     return S_OK;
1635 }
1636
1637 HRESULT STDMETHODCALLTYPE WebView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1638 {
1639     if (m_dropTargetHelper)
1640         m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
1641
1642     m_dragData = 0;
1643     *pdwEffect = m_lastDropEffect;
1644     POINTL localpt = pt;
1645     ::ScreenToClient(m_window, (LPPOINT)&localpt);
1646     DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1647
1648     SandboxExtension::Handle sandboxExtensionHandle;
1649     m_page->performDrag(&data, String(), sandboxExtensionHandle);
1650     return S_OK;
1651 }
1652
1653 } // namespace WebKit