AX: Webkit2 not sending UAZoomFocusChanged notifications
[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 "Region.h"
35 #include "RunLoop.h"
36 #include "WKAPICast.h"
37 #include "WebContext.h"
38 #include "WebContextMenuProxyWin.h"
39 #include "WebEditCommandProxy.h"
40 #include "WebEventFactory.h"
41 #include "WebPageProxy.h"
42 #include "WebPopupMenuProxyWin.h"
43 #include <Commctrl.h>
44 #include <WebCore/BitmapInfo.h>
45 #include <WebCore/Cursor.h>
46 #include <WebCore/FloatRect.h>
47 #include <WebCore/GraphicsContextCG.h>
48 #include <WebCore/IntRect.h>
49 #include <WebCore/SoftLinking.h>
50 #include <WebCore/WebCoreInstanceHandle.h>
51 #include <WebCore/WindowMessageBroadcaster.h>
52 #include <wtf/text/WTFString.h>
53
54 namespace Ime {
55 // We need these functions in a separate namespace, because in the global namespace they conflict
56 // with the definitions in imm.h only by the type modifier (the macro defines them as static) and
57 // imm.h is included by windows.h
58 SOFT_LINK_LIBRARY(IMM32)
59 SOFT_LINK(IMM32, ImmGetContext, HIMC, WINAPI, (HWND hwnd), (hwnd))
60 SOFT_LINK(IMM32, ImmReleaseContext, BOOL, WINAPI, (HWND hWnd, HIMC hIMC), (hWnd, hIMC))
61 SOFT_LINK(IMM32, ImmGetCompositionStringW, LONG, WINAPI, (HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen), (hIMC, dwIndex, lpBuf, dwBufLen))
62 SOFT_LINK(IMM32, ImmSetCandidateWindow, BOOL, WINAPI, (HIMC hIMC, LPCANDIDATEFORM lpCandidate), (hIMC, lpCandidate))
63 SOFT_LINK(IMM32, ImmSetOpenStatus, BOOL, WINAPI, (HIMC hIMC, BOOL fOpen), (hIMC, fOpen))
64 SOFT_LINK(IMM32, ImmNotifyIME, BOOL, WINAPI, (HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue), (hIMC, dwAction, dwIndex, dwValue))
65 SOFT_LINK(IMM32, ImmAssociateContextEx, BOOL, WINAPI, (HWND hWnd, HIMC hIMC, DWORD dwFlags), (hWnd, hIMC, dwFlags))
66 };
67
68 using namespace WebCore;
69
70 namespace WebKit {
71
72 static const LPCWSTR kWebKit2WebViewWindowClassName = L"WebKit2WebViewWindowClass";
73
74 // Constants not available on all platforms.
75 const int WM_XP_THEMECHANGED = 0x031A;
76 const int WM_VISTA_MOUSEHWHEEL = 0x020E;
77
78 static const int kMaxToolTipWidth = 250;
79
80 enum {
81     UpdateActiveStateTimer = 1,
82 };
83
84 static bool useNewDrawingArea()
85 {
86     // FIXME: Remove this function and the old drawing area code once we aren't interested in
87     // testing the old drawing area anymore.
88     return true;
89 }
90
91 LRESULT CALLBACK WebView::WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
92 {
93     LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0);
94     
95     if (WebView* webView = reinterpret_cast<WebView*>(longPtr))
96         return webView->wndProc(hWnd, message, wParam, lParam);
97
98     if (message == WM_CREATE) {
99         LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
100
101         // Associate the WebView with the window.
102         ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams);
103         return 0;
104     }
105
106     return ::DefWindowProc(hWnd, message, wParam, lParam);
107 }
108
109 LRESULT WebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
110 {
111     LRESULT lResult = 0;
112     bool handled = true;
113
114     switch (message) {
115     case WM_CLOSE:
116         m_page->tryClose();
117         break;
118     case WM_DESTROY:
119         m_isBeingDestroyed = true;
120         close();
121         break;
122     case WM_ERASEBKGND:
123         lResult = 1;
124         break;
125     case WM_PAINT:
126         lResult = onPaintEvent(hWnd, message, wParam, lParam, handled);
127         break;
128     case WM_PRINTCLIENT:
129         lResult = onPrintClientEvent(hWnd, message, wParam, lParam, handled);
130         break;
131     case WM_MOUSEACTIVATE:
132         setWasActivatedByMouseEvent(true);
133         handled = false;
134         break;
135     case WM_MOUSEMOVE:
136     case WM_LBUTTONDOWN:
137     case WM_MBUTTONDOWN:
138     case WM_RBUTTONDOWN:
139     case WM_LBUTTONDBLCLK:
140     case WM_MBUTTONDBLCLK:
141     case WM_RBUTTONDBLCLK:
142     case WM_LBUTTONUP:
143     case WM_MBUTTONUP:
144     case WM_RBUTTONUP:
145     case WM_MOUSELEAVE:
146         lResult = onMouseEvent(hWnd, message, wParam, lParam, handled);
147         break;
148     case WM_MOUSEWHEEL:
149     case WM_VISTA_MOUSEHWHEEL:
150         lResult = onWheelEvent(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_IME_STARTCOMPOSITION:
182         handled = onIMEStartComposition();
183         break;
184     case WM_IME_REQUEST:
185         lResult = onIMERequest(wParam, lParam);
186         break;
187     case WM_IME_COMPOSITION:
188         handled = onIMEComposition(lParam);
189         break;
190     case WM_IME_ENDCOMPOSITION:
191         handled = onIMEEndComposition();
192         break;
193     case WM_IME_SELECT:
194         handled = onIMESelect(wParam, lParam);
195         break;
196     case WM_IME_SETCONTEXT:
197         handled = onIMESetContext(wParam, lParam);
198         break;
199     default:
200         handled = false;
201         break;
202     }
203
204     if (!handled)
205         lResult = ::DefWindowProc(hWnd, message, wParam, lParam);
206
207     return lResult;
208 }
209
210 bool WebView::registerWebViewWindowClass()
211 {
212     static bool haveRegisteredWindowClass = false;
213     if (haveRegisteredWindowClass)
214         return true;
215     haveRegisteredWindowClass = true;
216
217     WNDCLASSEX wcex;
218
219     wcex.cbSize = sizeof(WNDCLASSEX);
220     wcex.style          = CS_DBLCLKS;
221     wcex.lpfnWndProc    = WebView::WebViewWndProc;
222     wcex.cbClsExtra     = 0;
223     wcex.cbWndExtra     = sizeof(WebView*);
224     wcex.hInstance      = instanceHandle();
225     wcex.hIcon          = 0;
226     wcex.hCursor        = ::LoadCursor(0, IDC_ARROW);
227     wcex.hbrBackground  = 0;
228     wcex.lpszMenuName   = 0;
229     wcex.lpszClassName  = kWebKit2WebViewWindowClassName;
230     wcex.hIconSm        = 0;
231
232     return !!::RegisterClassEx(&wcex);
233 }
234
235 WebView::WebView(RECT rect, WebContext* context, WebPageGroup* pageGroup, HWND parentWindow)
236     : m_topLevelParentWindow(0)
237     , m_toolTipWindow(0)
238     , m_lastCursorSet(0)
239     , m_webCoreCursor(0)
240     , m_overrideCursor(0)
241     , m_trackingMouseLeave(false)
242     , m_isInWindow(false)
243     , m_isVisible(false)
244     , m_wasActivatedByMouseEvent(false)
245     , m_isBeingDestroyed(false)
246     , m_inIMEComposition(0)
247     , m_findIndicatorCallback(0)
248     , m_findIndicatorCallbackContext(0)
249 {
250     registerWebViewWindowClass();
251
252     m_window = ::CreateWindowExW(0, kWebKit2WebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
253         rect.top, rect.left, rect.right - rect.left, rect.bottom - rect.top, parentWindow ? parentWindow : HWND_MESSAGE, 0, instanceHandle(), this);
254     ASSERT(::IsWindow(m_window));
255     // We only check our window style, and not ::IsWindowVisible, because m_isVisible only tracks
256     // this window's visibility status, while ::IsWindowVisible takes our ancestors' visibility
257     // status into account. <http://webkit.org/b/54104>
258     ASSERT(m_isVisible == static_cast<bool>(::GetWindowLong(m_window, GWL_STYLE) & WS_VISIBLE));
259
260     m_page = context->createWebPage(this, pageGroup);
261     m_page->initializeWebPage();
262
263     CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, (void**)&m_dropTargetHelper);
264
265     // FIXME: Initializing the tooltip window here matches WebKit win, but seems like something
266     // we could do on demand to save resources.
267     initializeToolTipWindow();
268
269     // Initialize the top level parent window and register it with the WindowMessageBroadcaster.
270     windowAncestryDidChange();
271 }
272
273 WebView::~WebView()
274 {
275     // Tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD.
276     if (::IsWindow(m_toolTipWindow))
277         ::DestroyWindow(m_toolTipWindow);
278 }
279
280 void WebView::initialize()
281 {
282     ::RegisterDragDrop(m_window, this);
283 }
284
285 void WebView::setParentWindow(HWND parentWindow)
286 {
287     if (m_window) {
288         // If the host window hasn't changed, bail.
289         if (::GetParent(m_window) == parentWindow)
290             return;
291         if (parentWindow)
292             ::SetParent(m_window, parentWindow);
293         else if (!m_isBeingDestroyed) {
294             // Turn the WebView into a message-only window so it will no longer be a child of the
295             // old parent window and will be hidden from screen. We only do this when
296             // isBeingDestroyed() is false because doing this while handling WM_DESTROY can leave
297             // m_window in a weird state (see <http://webkit.org/b/29337>).
298             ::SetParent(m_window, HWND_MESSAGE);
299         }
300     }
301
302     windowAncestryDidChange();
303 }
304
305 static HWND findTopLevelParentWindow(HWND window)
306 {
307     if (!window)
308         return 0;
309
310     HWND current = window;
311     for (HWND parent = GetParent(current); current; current = parent, parent = GetParent(parent)) {
312         if (!parent || !(GetWindowLongPtr(current, GWL_STYLE) & (WS_POPUP | WS_CHILD)))
313             return current;
314     }
315     ASSERT_NOT_REACHED();
316     return 0;
317 }
318
319 void WebView::windowAncestryDidChange()
320 {
321     HWND newTopLevelParentWindow;
322     if (m_window)
323         newTopLevelParentWindow = findTopLevelParentWindow(m_window);
324     else {
325         // There's no point in tracking active state changes of our parent window if we don't have
326         // a window ourselves.
327         newTopLevelParentWindow = 0;
328     }
329
330     if (newTopLevelParentWindow == m_topLevelParentWindow)
331         return;
332
333     if (m_topLevelParentWindow)
334         WindowMessageBroadcaster::removeListener(m_topLevelParentWindow, this);
335
336     m_topLevelParentWindow = newTopLevelParentWindow;
337
338     if (m_topLevelParentWindow)
339         WindowMessageBroadcaster::addListener(m_topLevelParentWindow, this);
340
341     updateActiveState();
342 }
343
344 LRESULT WebView::onMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
345 {
346     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(hWnd, message, wParam, lParam, m_wasActivatedByMouseEvent);
347     setWasActivatedByMouseEvent(false);
348     
349     switch (message) {
350     case WM_LBUTTONDOWN:
351     case WM_MBUTTONDOWN:
352     case WM_RBUTTONDOWN:
353         ::SetFocus(m_window);
354         ::SetCapture(m_window);
355         break; 
356     case WM_LBUTTONUP:
357     case WM_MBUTTONUP:
358     case WM_RBUTTONUP:
359         ::ReleaseCapture();
360         break;
361     case WM_MOUSEMOVE:
362         startTrackingMouseLeave();
363         break;
364     case WM_MOUSELEAVE:
365         stopTrackingMouseLeave();
366         break;
367     case WM_LBUTTONDBLCLK:
368     case WM_MBUTTONDBLCLK:
369     case WM_RBUTTONDBLCLK:
370         break;
371     default:
372         ASSERT_NOT_REACHED();
373     }
374
375     m_page->handleMouseEvent(mouseEvent);
376
377     handled = true;
378     return 0;
379 }
380
381 LRESULT WebView::onWheelEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
382 {
383     WebWheelEvent wheelEvent = WebEventFactory::createWebWheelEvent(hWnd, message, wParam, lParam);
384     if (wheelEvent.controlKey()) {
385         // We do not want WebKit to handle Control + Wheel, this should be handled by the client application
386         // to zoom the page.
387         handled = false;
388         return 0;
389     }
390
391     m_page->handleWheelEvent(wheelEvent);
392
393     handled = true;
394     return 0;
395 }
396
397 LRESULT WebView::onKeyEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
398 {
399     m_page->handleKeyboardEvent(NativeWebKeyboardEvent(hWnd, message, wParam, lParam));
400
401     // We claim here to always have handled the event. If the event is not in fact handled, we will
402     // find out later in didNotHandleKeyEvent.
403     handled = true;
404     return 0;
405 }
406
407 static void drawPageBackground(HDC dc, const RECT& rect)
408 {
409     // Mac checks WebPageProxy::drawsBackground and
410     // WebPageProxy::drawsTransparentBackground here, but those are always false on
411     // Windows currently (see <http://webkit.org/b/52009>).
412     ::FillRect(dc, &rect, reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1));
413 }
414
415 void WebView::paint(HDC hdc, const IntRect& dirtyRect)
416 {
417     m_page->endPrinting();
418     if (useNewDrawingArea()) {
419         if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(m_page->drawingArea())) {
420             // FIXME: We should port WebKit1's rect coalescing logic here.
421             Region unpaintedRegion;
422             drawingArea->paint(hdc, dirtyRect, unpaintedRegion);
423
424             Vector<IntRect> unpaintedRects = unpaintedRegion.rects();
425             for (size_t i = 0; i < unpaintedRects.size(); ++i) {
426                 RECT winRect = unpaintedRects[i];
427                 drawPageBackground(hdc, unpaintedRects[i]);
428             }
429         } else
430             drawPageBackground(hdc, dirtyRect);
431
432         m_page->didDraw();
433     } else {
434         if (m_page->isValid() && m_page->drawingArea() && m_page->drawingArea()->paint(dirtyRect, hdc))
435             m_page->didDraw();
436         else
437             drawPageBackground(hdc, dirtyRect);
438     }
439 }
440
441 static void flashRects(HDC dc, const IntRect rects[], size_t rectCount, HBRUSH brush)
442 {
443     for (size_t i = 0; i < rectCount; ++i) {
444         RECT winRect = rects[i];
445         ::FillRect(dc, &winRect, brush);
446     }
447
448     ::GdiFlush();
449     ::Sleep(50);
450 }
451
452 static OwnPtr<HBRUSH> createBrush(const Color& color)
453 {
454     return adoptPtr(::CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
455 }
456
457 LRESULT WebView::onPaintEvent(HWND hWnd, UINT message, WPARAM, LPARAM, bool& handled)
458 {
459     PAINTSTRUCT paintStruct;
460     HDC hdc = ::BeginPaint(m_window, &paintStruct);
461
462     if (WebPageProxy::debugPaintFlags() & kWKDebugFlashViewUpdates) {
463         static HBRUSH brush = createBrush(WebPageProxy::viewUpdatesFlashColor().rgb()).leakPtr();
464         IntRect rect = paintStruct.rcPaint;
465         flashRects(hdc, &rect, 1, brush);
466     }
467
468     paint(hdc, paintStruct.rcPaint);
469
470     ::EndPaint(m_window, &paintStruct);
471
472     handled = true;
473     return 0;
474 }
475
476 LRESULT WebView::onPrintClientEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
477 {
478     HDC hdc = reinterpret_cast<HDC>(wParam);
479     RECT winRect;
480     ::GetClientRect(hWnd, &winRect);
481
482     paint(hdc, winRect);
483
484     handled = true;
485     return 0;
486 }
487
488 LRESULT WebView::onSizeEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
489 {
490     int width = LOWORD(lParam);
491     int height = HIWORD(lParam);
492
493     if (m_page && m_page->drawingArea())
494         m_page->drawingArea()->setSize(IntSize(width, height), IntSize());
495
496     handled = true;
497     return 0;
498 }
499
500 LRESULT WebView::onWindowPositionChangedEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
501 {
502     if (reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW)
503         updateActiveStateSoon();
504
505     handled = false;
506     return 0;
507 }
508
509 LRESULT WebView::onSetFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
510 {
511     m_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
512     handled = true;
513     return 0;
514 }
515
516 LRESULT WebView::onKillFocusEvent(HWND, UINT, WPARAM, LPARAM lParam, bool& handled)
517 {
518     m_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
519     handled = true;
520     return 0;
521 }
522
523 LRESULT WebView::onTimerEvent(HWND hWnd, UINT, WPARAM wParam, LPARAM, bool& handled)
524 {
525     switch (wParam) {
526     case UpdateActiveStateTimer:
527         ::KillTimer(hWnd, UpdateActiveStateTimer);
528         updateActiveState();
529         break;
530     }
531
532     handled = true;
533     return 0;
534 }
535
536 LRESULT WebView::onShowWindowEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
537 {
538     // lParam is 0 when the message is sent because of a ShowWindow call.
539     // FIXME: Since we don't get notified when an ancestor window is hidden or shown, we will keep
540     // painting even when we have a hidden ancestor. <http://webkit.org/b/54104>
541     if (!lParam) {
542         m_isVisible = wParam;
543         if (m_page)
544             m_page->viewStateDidChange(WebPageProxy::ViewIsVisible);
545     }
546
547     handled = false;
548     return 0;
549 }
550
551 LRESULT WebView::onSetCursor(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
552 {
553     if (!m_lastCursorSet) {
554         handled = false;
555         return 0;
556     }
557
558     ::SetCursor(m_lastCursorSet);
559     return 0;
560 }
561
562 void WebView::updateActiveState()
563 {
564     m_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
565 }
566
567 void WebView::updateActiveStateSoon()
568 {
569     // This function is called while processing the WM_NCACTIVATE message.
570     // While processing WM_NCACTIVATE when we are being deactivated, GetActiveWindow() will
571     // still return our window. If we were to call updateActiveState() in that case, we would
572     // wrongly think that we are still the active window. To work around this, we update our
573     // active state after a 0-delay timer fires, at which point GetActiveWindow() will return
574     // the newly-activated window.
575
576     ::SetTimer(m_window, UpdateActiveStateTimer, 0, 0);
577 }
578
579 static bool initCommonControls()
580 {
581     static bool haveInitialized = false;
582     if (haveInitialized)
583         return true;
584
585     INITCOMMONCONTROLSEX init;
586     init.dwSize = sizeof(init);
587     init.dwICC = ICC_TREEVIEW_CLASSES;
588     haveInitialized = !!::InitCommonControlsEx(&init);
589     return haveInitialized;
590 }
591
592 void WebView::initializeToolTipWindow()
593 {
594     if (!initCommonControls())
595         return;
596
597     m_toolTipWindow = ::CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
598                                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
599                                        m_window, 0, 0, 0);
600     if (!m_toolTipWindow)
601         return;
602
603     TOOLINFO info = {0};
604     info.cbSize = sizeof(info);
605     info.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
606     info.uId = reinterpret_cast<UINT_PTR>(m_window);
607
608     ::SendMessage(m_toolTipWindow, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
609     ::SendMessage(m_toolTipWindow, TTM_SETMAXTIPWIDTH, 0, kMaxToolTipWidth);
610     ::SetWindowPos(m_toolTipWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
611 }
612
613 void WebView::startTrackingMouseLeave()
614 {
615     if (m_trackingMouseLeave)
616         return;
617     m_trackingMouseLeave = true;
618
619     TRACKMOUSEEVENT trackMouseEvent;
620     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
621     trackMouseEvent.dwFlags = TME_LEAVE;
622     trackMouseEvent.hwndTrack = m_window;
623
624     ::TrackMouseEvent(&trackMouseEvent);
625 }
626
627 void WebView::stopTrackingMouseLeave()
628 {
629     if (!m_trackingMouseLeave)
630         return;
631     m_trackingMouseLeave = false;
632
633     TRACKMOUSEEVENT trackMouseEvent;
634     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
635     trackMouseEvent.dwFlags = TME_LEAVE | TME_CANCEL;
636     trackMouseEvent.hwndTrack = m_window;
637
638     ::TrackMouseEvent(&trackMouseEvent);
639 }
640
641 void WebView::close()
642 {
643     ::RevokeDragDrop(m_window);
644     setParentWindow(0);
645     m_page->close();
646 }
647
648 // PageClient
649
650 PassOwnPtr<DrawingAreaProxy> WebView::createDrawingAreaProxy()
651 {
652     if (useNewDrawingArea())
653         return DrawingAreaProxyImpl::create(m_page.get());
654
655     return ChunkedUpdateDrawingAreaProxy::create(this, m_page.get());
656 }
657
658 void WebView::setViewNeedsDisplay(const WebCore::IntRect& rect)
659 {
660     RECT r = rect;
661     ::InvalidateRect(m_window, &r, false);
662 }
663
664 void WebView::displayView()
665 {
666     ::UpdateWindow(m_window);
667 }
668
669 void WebView::scrollView(const IntRect& scrollRect, const IntSize& scrollOffset)
670 {
671     // FIXME: Actually scroll the view contents.
672     setViewNeedsDisplay(scrollRect);
673 }
674
675 void WebView::flashBackingStoreUpdates(const Vector<IntRect>& updateRects)
676 {
677     static HBRUSH brush = createBrush(WebPageProxy::backingStoreUpdatesFlashColor().rgb()).leakPtr();
678     HDC dc = ::GetDC(m_window);
679     flashRects(dc, updateRects.data(), updateRects.size(), brush);
680     ::ReleaseDC(m_window, dc);
681 }
682
683 WebCore::IntSize WebView::viewSize()
684 {
685     RECT clientRect;
686     GetClientRect(m_window, &clientRect);
687
688     return IntRect(clientRect).size();
689 }
690
691 bool WebView::isViewWindowActive()
692 {    
693     HWND activeWindow = ::GetActiveWindow();
694     return (activeWindow && m_topLevelParentWindow == findTopLevelParentWindow(activeWindow));
695 }
696
697 bool WebView::isViewFocused()
698 {
699     return ::GetFocus() == m_window;
700 }
701
702 bool WebView::isViewVisible()
703 {
704     return m_isVisible;
705 }
706
707 bool WebView::isViewInWindow()
708 {
709     return m_isInWindow;
710 }
711
712 void WebView::pageClosed()
713 {
714 }
715
716 void WebView::processDidCrash()
717 {
718     updateNativeCursor();
719     ::InvalidateRect(m_window, 0, TRUE);
720 }
721
722 void WebView::didRelaunchProcess()
723 {
724     updateNativeCursor();
725     ::InvalidateRect(m_window, 0, TRUE);
726 }
727
728 void WebView::takeFocus(bool)
729 {
730 }
731
732 void WebView::toolTipChanged(const String&, const String& newToolTip)
733 {
734     if (!m_toolTipWindow)
735         return;
736
737     if (!newToolTip.isEmpty()) {
738         // This is necessary because String::charactersWithNullTermination() is not const.
739         String toolTip = newToolTip;
740
741         TOOLINFO info = {0};
742         info.cbSize = sizeof(info);
743         info.uFlags = TTF_IDISHWND;
744         info.uId = reinterpret_cast<UINT_PTR>(m_window);
745         info.lpszText = const_cast<UChar*>(toolTip.charactersWithNullTermination());
746         ::SendMessage(m_toolTipWindow, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
747     }
748
749     ::SendMessage(m_toolTipWindow, TTM_ACTIVATE, !newToolTip.isEmpty(), 0);
750 }
751
752 HCURSOR WebView::cursorToShow() const
753 {
754     if (!m_page->isValid())
755         return 0;
756
757     // We only show the override cursor if the default (arrow) cursor is showing.
758     static HCURSOR arrowCursor = ::LoadCursor(0, IDC_ARROW);
759     if (m_overrideCursor && m_webCoreCursor == arrowCursor)
760         return m_overrideCursor;
761
762     return m_webCoreCursor;
763 }
764
765 void WebView::updateNativeCursor()
766 {
767     m_lastCursorSet = cursorToShow();
768     if (!m_lastCursorSet)
769         return;
770     ::SetCursor(m_lastCursorSet);
771 }
772
773 void WebView::setCursor(const WebCore::Cursor& cursor)
774 {
775     if (!cursor.platformCursor()->nativeCursor())
776         return;
777     m_webCoreCursor = cursor.platformCursor()->nativeCursor();
778     updateNativeCursor();
779 }
780
781 void WebView::setOverrideCursor(HCURSOR overrideCursor)
782 {
783     m_overrideCursor = overrideCursor;
784     updateNativeCursor();
785 }
786
787 void WebView::setInitialFocus(bool forward)
788 {
789     m_page->setInitialFocus(forward);
790 }
791
792 void WebView::setViewportArguments(const WebCore::ViewportArguments&)
793 {
794 }
795
796 void WebView::registerEditCommand(PassRefPtr<WebEditCommandProxy>, WebPageProxy::UndoOrRedo)
797 {
798 }
799
800 void WebView::clearAllEditCommands()
801 {
802 }
803
804 FloatRect WebView::convertToDeviceSpace(const FloatRect& rect)
805 {
806     return rect;
807 }
808
809 IntRect WebView::windowToScreen(const IntRect& rect)
810 {
811     return rect;
812 }
813
814 FloatRect WebView::convertToUserSpace(const FloatRect& rect)
815 {
816     return rect;
817 }
818
819 HIMC WebView::getIMMContext() 
820 {
821     return Ime::ImmGetContext(m_window);
822 }
823
824 void WebView::prepareCandidateWindow(HIMC hInputContext) 
825 {
826     IntRect caret = m_page->firstRectForCharacterInSelectedRange(0);
827     CANDIDATEFORM form;
828     form.dwIndex = 0;
829     form.dwStyle = CFS_EXCLUDE;
830     form.ptCurrentPos.x = caret.x();
831     form.ptCurrentPos.y = caret.maxY();
832     form.rcArea.top = caret.y();
833     form.rcArea.bottom = caret.maxY();
834     form.rcArea.left = caret.x();
835     form.rcArea.right = caret.maxX();
836     Ime::ImmSetCandidateWindow(hInputContext, &form);
837 }
838
839 void WebView::resetIME()
840 {
841     HIMC hInputContext = getIMMContext();
842     if (!hInputContext)
843         return;
844     Ime::ImmNotifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
845     Ime::ImmReleaseContext(m_window, hInputContext);
846 }
847
848 void WebView::setInputMethodState(bool enabled)
849 {
850     Ime::ImmAssociateContextEx(m_window, 0, enabled ? IACE_DEFAULT : 0);
851 }
852
853 void WebView::compositionSelectionChanged(bool hasChanged)
854 {
855     if (m_page->selectionState().hasComposition && !hasChanged)
856         resetIME();
857 }
858
859 bool WebView::onIMEStartComposition()
860 {
861     LOG(TextInput, "onIMEStartComposition");
862     m_inIMEComposition++;
863
864     HIMC hInputContext = getIMMContext();
865     if (!hInputContext)
866         return false;
867     prepareCandidateWindow(hInputContext);
868     Ime::ImmReleaseContext(m_window, hInputContext);
869     return true;
870 }
871
872 static bool getCompositionString(HIMC hInputContext, DWORD type, String& result)
873 {
874     LONG compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, 0, 0);
875     if (compositionLength <= 0)
876         return false;
877     Vector<UChar> compositionBuffer(compositionLength / 2);
878     compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, compositionBuffer.data(), compositionLength);
879     result = String::adopt(compositionBuffer);
880     return true;
881 }
882
883 static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, Vector<CompositionUnderline>& underlines)
884 {
885     if (clauses.isEmpty()) {
886         underlines.clear();
887         return;
888     }
889   
890     size_t numBoundaries = clauses.size() - 1;
891     underlines.resize(numBoundaries);
892     for (unsigned i = 0; i < numBoundaries; ++i) {
893         underlines[i].startOffset = clauses[i];
894         underlines[i].endOffset = clauses[i + 1];
895         BYTE attribute = attributes[clauses[i]];
896         underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED;
897         underlines[i].color = Color::black;
898     }
899 }
900
901 #if !LOG_DISABLED
902 #define APPEND_ARGUMENT_NAME(name) \
903     if (lparam & name) { \
904         if (needsComma) \
905             result += ", "; \
906             result += #name; \
907         needsComma = true; \
908     }
909
910 static String imeCompositionArgumentNames(LPARAM lparam)
911 {
912     String result;
913     bool needsComma = false;
914
915     APPEND_ARGUMENT_NAME(GCS_COMPATTR);
916     APPEND_ARGUMENT_NAME(GCS_COMPCLAUSE);
917     APPEND_ARGUMENT_NAME(GCS_COMPREADSTR);
918     APPEND_ARGUMENT_NAME(GCS_COMPREADATTR);
919     APPEND_ARGUMENT_NAME(GCS_COMPREADCLAUSE);
920     APPEND_ARGUMENT_NAME(GCS_COMPSTR);
921     APPEND_ARGUMENT_NAME(GCS_CURSORPOS);
922     APPEND_ARGUMENT_NAME(GCS_DELTASTART);
923     APPEND_ARGUMENT_NAME(GCS_RESULTCLAUSE);
924     APPEND_ARGUMENT_NAME(GCS_RESULTREADCLAUSE);
925     APPEND_ARGUMENT_NAME(GCS_RESULTREADSTR);
926     APPEND_ARGUMENT_NAME(GCS_RESULTSTR);
927     APPEND_ARGUMENT_NAME(CS_INSERTCHAR);
928     APPEND_ARGUMENT_NAME(CS_NOMOVECARET);
929
930     return result;
931 }
932
933 static String imeRequestName(WPARAM wparam)
934 {
935     switch (wparam) {
936     case IMR_CANDIDATEWINDOW:
937         return "IMR_CANDIDATEWINDOW";
938     case IMR_COMPOSITIONFONT:
939         return "IMR_COMPOSITIONFONT";
940     case IMR_COMPOSITIONWINDOW:
941         return "IMR_COMPOSITIONWINDOW";
942     case IMR_CONFIRMRECONVERTSTRING:
943         return "IMR_CONFIRMRECONVERTSTRING";
944     case IMR_DOCUMENTFEED:
945         return "IMR_DOCUMENTFEED";
946     case IMR_QUERYCHARPOSITION:
947         return "IMR_QUERYCHARPOSITION";
948     case IMR_RECONVERTSTRING:
949         return "IMR_RECONVERTSTRING";
950     default:
951         return "Unknown (" + String::number(wparam) + ")";
952     }
953 }
954 #endif
955
956 bool WebView::onIMEComposition(LPARAM lparam)
957 {
958     LOG(TextInput, "onIMEComposition %s", imeCompositionArgumentNames(lparam).latin1().data());
959     HIMC hInputContext = getIMMContext();
960     if (!hInputContext)
961         return true;
962
963     if (!m_page->selectionState().isContentEditable)
964         return true;
965
966     prepareCandidateWindow(hInputContext);
967
968     if (lparam & GCS_RESULTSTR || !lparam) {
969         String compositionString;
970         if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam)
971             return true;
972         
973         m_page->confirmComposition(compositionString);
974         return true;
975     }
976
977     String compositionString;
978     if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString))
979         return true;
980     
981     // Composition string attributes
982     int numAttributes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, 0, 0);
983     Vector<BYTE> attributes(numAttributes);
984     Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, attributes.data(), numAttributes);
985
986     // Get clauses
987     int numBytes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, 0, 0);
988     Vector<DWORD> clauses(numBytes / sizeof(DWORD));
989     Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, clauses.data(), numBytes);
990
991     Vector<CompositionUnderline> underlines;
992     compositionToUnderlines(clauses, attributes, underlines);
993
994     int cursorPosition = LOWORD(Ime::ImmGetCompositionStringW(hInputContext, GCS_CURSORPOS, 0, 0));
995
996     m_page->setComposition(compositionString, underlines, cursorPosition);
997
998     return true;
999 }
1000
1001 bool WebView::onIMEEndComposition()
1002 {
1003     LOG(TextInput, "onIMEEndComposition");
1004     // If the composition hasn't been confirmed yet, it needs to be cancelled.
1005     // This happens after deleting the last character from inline input hole.
1006     if (m_page->selectionState().hasComposition)
1007         m_page->confirmComposition(String());
1008
1009     if (m_inIMEComposition)
1010         m_inIMEComposition--;
1011
1012     return true;
1013 }
1014
1015 LRESULT WebView::onIMERequestCharPosition(IMECHARPOSITION* charPos)
1016 {
1017     if (charPos->dwCharPos && !m_page->selectionState().hasComposition)
1018         return 0;
1019     IntRect caret = m_page->firstRectForCharacterInSelectedRange(charPos->dwCharPos);
1020     charPos->pt.x = caret.x();
1021     charPos->pt.y = caret.y();
1022     ::ClientToScreen(m_window, &charPos->pt);
1023     charPos->cLineHeight = caret.height();
1024     ::GetWindowRect(m_window, &charPos->rcDocument);
1025     return true;
1026 }
1027
1028 LRESULT WebView::onIMERequestReconvertString(RECONVERTSTRING* reconvertString)
1029 {
1030     String text = m_page->getSelectedText();
1031     unsigned totalSize = sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
1032     
1033     if (!reconvertString)
1034         return totalSize;
1035
1036     if (totalSize > reconvertString->dwSize)
1037         return 0;
1038     reconvertString->dwCompStrLen = text.length();
1039     reconvertString->dwStrLen = text.length();
1040     reconvertString->dwTargetStrLen = text.length();
1041     reconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
1042     memcpy(reconvertString + 1, text.characters(), text.length() * sizeof(UChar));
1043     return totalSize;
1044 }
1045
1046 LRESULT WebView::onIMERequest(WPARAM request, LPARAM data)
1047 {
1048     LOG(TextInput, "onIMERequest %s", imeRequestName(request).latin1().data());
1049     if (!m_page->selectionState().isContentEditable)
1050         return 0;
1051
1052     switch (request) {
1053     case IMR_RECONVERTSTRING:
1054         return onIMERequestReconvertString(reinterpret_cast<RECONVERTSTRING*>(data));
1055
1056     case IMR_QUERYCHARPOSITION:
1057         return onIMERequestCharPosition(reinterpret_cast<IMECHARPOSITION*>(data));
1058     }
1059     return 0;
1060 }
1061
1062 bool WebView::onIMESelect(WPARAM wparam, LPARAM lparam)
1063 {
1064     UNUSED_PARAM(wparam);
1065     UNUSED_PARAM(lparam);
1066     LOG(TextInput, "onIMESelect locale %ld %s", lparam, wparam ? "select" : "deselect");
1067     return false;
1068 }
1069
1070 bool WebView::onIMESetContext(WPARAM wparam, LPARAM)
1071 {
1072     LOG(TextInput, "onIMESetContext %s", wparam ? "active" : "inactive");
1073     return false;
1074 }
1075
1076 void WebView::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool wasEventHandled)
1077 {
1078     // Calling ::DefWindowProcW will ensure that pressing the Alt key will generate a WM_SYSCOMMAND
1079     // event, e.g. See <http://webkit.org/b/47671>.
1080     if (!wasEventHandled)
1081         ::DefWindowProcW(event.nativeEvent()->hwnd, event.nativeEvent()->message, event.nativeEvent()->wParam, event.nativeEvent()->lParam);
1082 }
1083
1084 PassRefPtr<WebPopupMenuProxy> WebView::createPopupMenuProxy(WebPageProxy* page)
1085 {
1086     return WebPopupMenuProxyWin::create(this, page);
1087 }
1088
1089 PassRefPtr<WebContextMenuProxy> WebView::createContextMenuProxy(WebPageProxy* page)
1090 {
1091     return WebContextMenuProxyWin::create(m_window, page);
1092 }
1093
1094 void WebView::setFindIndicator(PassRefPtr<FindIndicator> prpFindIndicator, bool fadeOut)
1095 {
1096     if (!m_findIndicatorCallback)
1097         return;
1098
1099     HBITMAP hbmp = 0;
1100     IntRect selectionRect;
1101
1102     if (RefPtr<FindIndicator> findIndicator = prpFindIndicator) {
1103         if (ShareableBitmap* contentImage = findIndicator->contentImage()) {
1104             // Render the contentImage to an HBITMAP.
1105             void* bits;
1106             HDC hdc = ::CreateCompatibleDC(0);
1107             int width = contentImage->bounds().width();
1108             int height = contentImage->bounds().height();
1109             BitmapInfo bitmapInfo = BitmapInfo::create(contentImage->size());
1110
1111             hbmp = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0);
1112             HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp));
1113             RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(bits, width, height,
1114                 8, width * sizeof(RGBQUAD), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
1115
1116             GraphicsContext graphicsContext(context.get());
1117             contentImage->paint(graphicsContext, IntPoint(), contentImage->bounds());
1118
1119             ::SelectObject(hdc, hbmpOld);
1120             ::DeleteDC(hdc);
1121         }
1122
1123         selectionRect = IntRect(findIndicator->selectionRectInWindowCoordinates());
1124     }
1125     
1126     // The callback is responsible for calling ::DeleteObject(hbmp).
1127     (*m_findIndicatorCallback)(toAPI(this), hbmp, selectionRect, fadeOut, m_findIndicatorCallbackContext);
1128 }
1129
1130 void WebView::setFindIndicatorCallback(WKViewFindIndicatorCallback callback, void* context)
1131 {
1132     m_findIndicatorCallback = callback;
1133     m_findIndicatorCallbackContext = context;
1134 }
1135
1136 WKViewFindIndicatorCallback WebView::getFindIndicatorCallback(void** context)
1137 {
1138     if (context)
1139         *context = m_findIndicatorCallbackContext;
1140     
1141     return m_findIndicatorCallback;
1142 }
1143
1144 void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
1145 {
1146 }
1147
1148 void WebView::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
1149 {
1150 }
1151
1152 double WebView::customRepresentationZoomFactor()
1153 {
1154     return 1;
1155 }
1156
1157 void WebView::setCustomRepresentationZoomFactor(double)
1158 {
1159 }
1160
1161 void WebView::didChangeScrollbarsForMainFrame() const
1162 {
1163 }
1164
1165 void WebView::setIsInWindow(bool isInWindow)
1166 {
1167     m_isInWindow = isInWindow;
1168     m_page->viewStateDidChange(WebPageProxy::ViewIsInWindow);
1169 }
1170
1171 #if USE(ACCELERATED_COMPOSITING)
1172
1173 void WebView::enterAcceleratedCompositingMode(const LayerTreeContext&)
1174 {
1175     ASSERT(useNewDrawingArea());
1176     // FIXME: Implement.
1177     ASSERT_NOT_REACHED();
1178 }
1179
1180 void WebView::exitAcceleratedCompositingMode()
1181 {
1182     ASSERT(useNewDrawingArea());
1183     // FIXME: Implement.
1184     ASSERT_NOT_REACHED();
1185 }
1186
1187 #endif // USE(ACCELERATED_COMPOSITING)
1188
1189 HWND WebView::nativeWindow()
1190 {
1191     return m_window;
1192 }
1193
1194 // WebCore::WindowMessageListener
1195
1196 void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
1197 {
1198     switch (message) {
1199     case WM_NCACTIVATE:
1200         updateActiveStateSoon();
1201         break;
1202     case WM_SETTINGCHANGE:
1203         // systemParameterChanged(wParam);
1204         break;
1205     }
1206 }
1207
1208 HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
1209 {
1210     *ppvObject = 0;
1211     if (IsEqualGUID(riid, IID_IUnknown))
1212         *ppvObject = static_cast<IUnknown*>(this);
1213     else if (IsEqualGUID(riid, IID_IDropTarget))
1214         *ppvObject = static_cast<IDropTarget*>(this);
1215     else
1216         return E_NOINTERFACE;
1217
1218     AddRef();
1219     return S_OK;
1220 }
1221
1222 ULONG STDMETHODCALLTYPE WebView::AddRef(void)
1223 {
1224     ref();
1225     return refCount();
1226 }
1227
1228 ULONG STDMETHODCALLTYPE WebView::Release(void)
1229 {
1230     deref();
1231     return refCount();
1232 }
1233
1234 static DWORD dragOperationToDragCursor(DragOperation op)
1235 {
1236     DWORD res = DROPEFFECT_NONE;
1237     if (op & DragOperationCopy) 
1238         res = DROPEFFECT_COPY;
1239     else if (op & DragOperationLink) 
1240         res = DROPEFFECT_LINK;
1241     else if (op & DragOperationMove) 
1242         res = DROPEFFECT_MOVE;
1243     else if (op & DragOperationGeneric) 
1244         res = DROPEFFECT_MOVE; // This appears to be the Firefox behaviour
1245     return res;
1246 }
1247
1248 WebCore::DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const
1249 {
1250     if (!m_page)
1251         return DragOperationNone;
1252
1253     // Conforms to Microsoft's key combinations as documented for 
1254     // IDropTarget::DragOver. Note, grfKeyState is the current 
1255     // state of the keyboard modifier keys on the keyboard. See:
1256     // <http://msdn.microsoft.com/en-us/library/ms680129(VS.85).aspx>.
1257     DragOperation operation = m_page->dragOperation();
1258
1259     if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
1260         operation = DragOperationLink;
1261     else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
1262         operation = DragOperationCopy;
1263     else if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
1264         operation = DragOperationGeneric;
1265
1266     return operation;
1267 }
1268
1269 HRESULT STDMETHODCALLTYPE WebView::DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1270 {
1271     m_dragData = 0;
1272     m_page->resetDragOperation();
1273
1274     if (m_dropTargetHelper)
1275         m_dropTargetHelper->DragEnter(m_window, pDataObject, (POINT*)&pt, *pdwEffect);
1276
1277     POINTL localpt = pt;
1278     ::ScreenToClient(m_window, (LPPOINT)&localpt);
1279     DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1280     m_page->performDragControllerAction(DragControllerActionEntered, &data);
1281     *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
1282
1283     m_lastDropEffect = *pdwEffect;
1284     m_dragData = pDataObject;
1285
1286     return S_OK;
1287 }
1288
1289 HRESULT STDMETHODCALLTYPE WebView::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1290 {
1291     if (m_dropTargetHelper)
1292         m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
1293
1294     if (m_dragData) {
1295         POINTL localpt = pt;
1296         ::ScreenToClient(m_window, (LPPOINT)&localpt);
1297         DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1298         m_page->performDragControllerAction(DragControllerActionUpdated, &data);
1299         *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
1300     } else
1301         *pdwEffect = DROPEFFECT_NONE;
1302
1303     m_lastDropEffect = *pdwEffect;
1304     return S_OK;
1305 }
1306
1307 HRESULT STDMETHODCALLTYPE WebView::DragLeave()
1308 {
1309     if (m_dropTargetHelper)
1310         m_dropTargetHelper->DragLeave();
1311
1312     if (m_dragData) {
1313         DragData data(m_dragData.get(), IntPoint(), IntPoint(), DragOperationNone);
1314         m_page->performDragControllerAction(DragControllerActionExited, &data);
1315         m_dragData = 0;
1316         m_page->resetDragOperation();
1317     }
1318     return S_OK;
1319 }
1320
1321 HRESULT STDMETHODCALLTYPE WebView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1322 {
1323     if (m_dropTargetHelper)
1324         m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
1325
1326     m_dragData = 0;
1327     *pdwEffect = m_lastDropEffect;
1328     POINTL localpt = pt;
1329     ::ScreenToClient(m_window, (LPPOINT)&localpt);
1330     DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1331     m_page->performDragControllerAction(DragControllerActionPerformDrag, &data);
1332     return S_OK;
1333 }
1334
1335 } // namespace WebKit