62e0c42b77b8174cd01b9ca0cf58802da99c7c3d
[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 FloatRect WebView::convertToUserSpace(const FloatRect& rect)
810 {
811     return rect;
812 }
813
814 HIMC WebView::getIMMContext() 
815 {
816     return Ime::ImmGetContext(m_window);
817 }
818
819 void WebView::prepareCandidateWindow(HIMC hInputContext) 
820 {
821     IntRect caret = m_page->firstRectForCharacterInSelectedRange(0);
822     CANDIDATEFORM form;
823     form.dwIndex = 0;
824     form.dwStyle = CFS_EXCLUDE;
825     form.ptCurrentPos.x = caret.x();
826     form.ptCurrentPos.y = caret.maxY();
827     form.rcArea.top = caret.y();
828     form.rcArea.bottom = caret.maxY();
829     form.rcArea.left = caret.x();
830     form.rcArea.right = caret.maxX();
831     Ime::ImmSetCandidateWindow(hInputContext, &form);
832 }
833
834 void WebView::resetIME()
835 {
836     HIMC hInputContext = getIMMContext();
837     if (!hInputContext)
838         return;
839     Ime::ImmNotifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
840     Ime::ImmReleaseContext(m_window, hInputContext);
841 }
842
843 void WebView::setInputMethodState(bool enabled)
844 {
845     Ime::ImmAssociateContextEx(m_window, 0, enabled ? IACE_DEFAULT : 0);
846 }
847
848 void WebView::compositionSelectionChanged(bool hasChanged)
849 {
850     if (m_page->selectionState().hasComposition && !hasChanged)
851         resetIME();
852 }
853
854 bool WebView::onIMEStartComposition()
855 {
856     LOG(TextInput, "onIMEStartComposition");
857     m_inIMEComposition++;
858
859     HIMC hInputContext = getIMMContext();
860     if (!hInputContext)
861         return false;
862     prepareCandidateWindow(hInputContext);
863     Ime::ImmReleaseContext(m_window, hInputContext);
864     return true;
865 }
866
867 static bool getCompositionString(HIMC hInputContext, DWORD type, String& result)
868 {
869     LONG compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, 0, 0);
870     if (compositionLength <= 0)
871         return false;
872     Vector<UChar> compositionBuffer(compositionLength / 2);
873     compositionLength = Ime::ImmGetCompositionStringW(hInputContext, type, compositionBuffer.data(), compositionLength);
874     result = String::adopt(compositionBuffer);
875     return true;
876 }
877
878 static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, Vector<CompositionUnderline>& underlines)
879 {
880     if (clauses.isEmpty()) {
881         underlines.clear();
882         return;
883     }
884   
885     size_t numBoundaries = clauses.size() - 1;
886     underlines.resize(numBoundaries);
887     for (unsigned i = 0; i < numBoundaries; ++i) {
888         underlines[i].startOffset = clauses[i];
889         underlines[i].endOffset = clauses[i + 1];
890         BYTE attribute = attributes[clauses[i]];
891         underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED;
892         underlines[i].color = Color::black;
893     }
894 }
895
896 #if !LOG_DISABLED
897 #define APPEND_ARGUMENT_NAME(name) \
898     if (lparam & name) { \
899         if (needsComma) \
900             result += ", "; \
901             result += #name; \
902         needsComma = true; \
903     }
904
905 static String imeCompositionArgumentNames(LPARAM lparam)
906 {
907     String result;
908     bool needsComma = false;
909
910     APPEND_ARGUMENT_NAME(GCS_COMPATTR);
911     APPEND_ARGUMENT_NAME(GCS_COMPCLAUSE);
912     APPEND_ARGUMENT_NAME(GCS_COMPREADSTR);
913     APPEND_ARGUMENT_NAME(GCS_COMPREADATTR);
914     APPEND_ARGUMENT_NAME(GCS_COMPREADCLAUSE);
915     APPEND_ARGUMENT_NAME(GCS_COMPSTR);
916     APPEND_ARGUMENT_NAME(GCS_CURSORPOS);
917     APPEND_ARGUMENT_NAME(GCS_DELTASTART);
918     APPEND_ARGUMENT_NAME(GCS_RESULTCLAUSE);
919     APPEND_ARGUMENT_NAME(GCS_RESULTREADCLAUSE);
920     APPEND_ARGUMENT_NAME(GCS_RESULTREADSTR);
921     APPEND_ARGUMENT_NAME(GCS_RESULTSTR);
922     APPEND_ARGUMENT_NAME(CS_INSERTCHAR);
923     APPEND_ARGUMENT_NAME(CS_NOMOVECARET);
924
925     return result;
926 }
927
928 static String imeRequestName(WPARAM wparam)
929 {
930     switch (wparam) {
931     case IMR_CANDIDATEWINDOW:
932         return "IMR_CANDIDATEWINDOW";
933     case IMR_COMPOSITIONFONT:
934         return "IMR_COMPOSITIONFONT";
935     case IMR_COMPOSITIONWINDOW:
936         return "IMR_COMPOSITIONWINDOW";
937     case IMR_CONFIRMRECONVERTSTRING:
938         return "IMR_CONFIRMRECONVERTSTRING";
939     case IMR_DOCUMENTFEED:
940         return "IMR_DOCUMENTFEED";
941     case IMR_QUERYCHARPOSITION:
942         return "IMR_QUERYCHARPOSITION";
943     case IMR_RECONVERTSTRING:
944         return "IMR_RECONVERTSTRING";
945     default:
946         return "Unknown (" + String::number(wparam) + ")";
947     }
948 }
949 #endif
950
951 bool WebView::onIMEComposition(LPARAM lparam)
952 {
953     LOG(TextInput, "onIMEComposition %s", imeCompositionArgumentNames(lparam).latin1().data());
954     HIMC hInputContext = getIMMContext();
955     if (!hInputContext)
956         return true;
957
958     if (!m_page->selectionState().isContentEditable)
959         return true;
960
961     prepareCandidateWindow(hInputContext);
962
963     if (lparam & GCS_RESULTSTR || !lparam) {
964         String compositionString;
965         if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam)
966             return true;
967         
968         m_page->confirmComposition(compositionString);
969         return true;
970     }
971
972     String compositionString;
973     if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString))
974         return true;
975     
976     // Composition string attributes
977     int numAttributes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, 0, 0);
978     Vector<BYTE> attributes(numAttributes);
979     Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPATTR, attributes.data(), numAttributes);
980
981     // Get clauses
982     int numBytes = Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, 0, 0);
983     Vector<DWORD> clauses(numBytes / sizeof(DWORD));
984     Ime::ImmGetCompositionStringW(hInputContext, GCS_COMPCLAUSE, clauses.data(), numBytes);
985
986     Vector<CompositionUnderline> underlines;
987     compositionToUnderlines(clauses, attributes, underlines);
988
989     int cursorPosition = LOWORD(Ime::ImmGetCompositionStringW(hInputContext, GCS_CURSORPOS, 0, 0));
990
991     m_page->setComposition(compositionString, underlines, cursorPosition);
992
993     return true;
994 }
995
996 bool WebView::onIMEEndComposition()
997 {
998     LOG(TextInput, "onIMEEndComposition");
999     // If the composition hasn't been confirmed yet, it needs to be cancelled.
1000     // This happens after deleting the last character from inline input hole.
1001     if (m_page->selectionState().hasComposition)
1002         m_page->confirmComposition(String());
1003
1004     if (m_inIMEComposition)
1005         m_inIMEComposition--;
1006
1007     return true;
1008 }
1009
1010 LRESULT WebView::onIMERequestCharPosition(IMECHARPOSITION* charPos)
1011 {
1012     if (charPos->dwCharPos && !m_page->selectionState().hasComposition)
1013         return 0;
1014     IntRect caret = m_page->firstRectForCharacterInSelectedRange(charPos->dwCharPos);
1015     charPos->pt.x = caret.x();
1016     charPos->pt.y = caret.y();
1017     ::ClientToScreen(m_window, &charPos->pt);
1018     charPos->cLineHeight = caret.height();
1019     ::GetWindowRect(m_window, &charPos->rcDocument);
1020     return true;
1021 }
1022
1023 LRESULT WebView::onIMERequestReconvertString(RECONVERTSTRING* reconvertString)
1024 {
1025     String text = m_page->getSelectedText();
1026     unsigned totalSize = sizeof(RECONVERTSTRING) + text.length() * sizeof(UChar);
1027     
1028     if (!reconvertString)
1029         return totalSize;
1030
1031     if (totalSize > reconvertString->dwSize)
1032         return 0;
1033     reconvertString->dwCompStrLen = text.length();
1034     reconvertString->dwStrLen = text.length();
1035     reconvertString->dwTargetStrLen = text.length();
1036     reconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
1037     memcpy(reconvertString + 1, text.characters(), text.length() * sizeof(UChar));
1038     return totalSize;
1039 }
1040
1041 LRESULT WebView::onIMERequest(WPARAM request, LPARAM data)
1042 {
1043     LOG(TextInput, "onIMERequest %s", imeRequestName(request).latin1().data());
1044     if (!m_page->selectionState().isContentEditable)
1045         return 0;
1046
1047     switch (request) {
1048     case IMR_RECONVERTSTRING:
1049         return onIMERequestReconvertString(reinterpret_cast<RECONVERTSTRING*>(data));
1050
1051     case IMR_QUERYCHARPOSITION:
1052         return onIMERequestCharPosition(reinterpret_cast<IMECHARPOSITION*>(data));
1053     }
1054     return 0;
1055 }
1056
1057 bool WebView::onIMESelect(WPARAM wparam, LPARAM lparam)
1058 {
1059     UNUSED_PARAM(wparam);
1060     UNUSED_PARAM(lparam);
1061     LOG(TextInput, "onIMESelect locale %ld %s", lparam, wparam ? "select" : "deselect");
1062     return false;
1063 }
1064
1065 bool WebView::onIMESetContext(WPARAM wparam, LPARAM)
1066 {
1067     LOG(TextInput, "onIMESetContext %s", wparam ? "active" : "inactive");
1068     return false;
1069 }
1070
1071 void WebView::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool wasEventHandled)
1072 {
1073     // Calling ::DefWindowProcW will ensure that pressing the Alt key will generate a WM_SYSCOMMAND
1074     // event, e.g. See <http://webkit.org/b/47671>.
1075     if (!wasEventHandled)
1076         ::DefWindowProcW(event.nativeEvent()->hwnd, event.nativeEvent()->message, event.nativeEvent()->wParam, event.nativeEvent()->lParam);
1077 }
1078
1079 PassRefPtr<WebPopupMenuProxy> WebView::createPopupMenuProxy(WebPageProxy* page)
1080 {
1081     return WebPopupMenuProxyWin::create(this, page);
1082 }
1083
1084 PassRefPtr<WebContextMenuProxy> WebView::createContextMenuProxy(WebPageProxy* page)
1085 {
1086     return WebContextMenuProxyWin::create(m_window, page);
1087 }
1088
1089 void WebView::setFindIndicator(PassRefPtr<FindIndicator> prpFindIndicator, bool fadeOut)
1090 {
1091     if (!m_findIndicatorCallback)
1092         return;
1093
1094     HBITMAP hbmp = 0;
1095     IntRect selectionRect;
1096
1097     if (RefPtr<FindIndicator> findIndicator = prpFindIndicator) {
1098         if (ShareableBitmap* contentImage = findIndicator->contentImage()) {
1099             // Render the contentImage to an HBITMAP.
1100             void* bits;
1101             HDC hdc = ::CreateCompatibleDC(0);
1102             int width = contentImage->bounds().width();
1103             int height = contentImage->bounds().height();
1104             BitmapInfo bitmapInfo = BitmapInfo::create(contentImage->size());
1105
1106             hbmp = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0);
1107             HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp));
1108             RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(bits, width, height,
1109                 8, width * sizeof(RGBQUAD), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
1110
1111             GraphicsContext graphicsContext(context.get());
1112             contentImage->paint(graphicsContext, IntPoint(), contentImage->bounds());
1113
1114             ::SelectObject(hdc, hbmpOld);
1115             ::DeleteDC(hdc);
1116         }
1117
1118         selectionRect = IntRect(findIndicator->selectionRectInWindowCoordinates());
1119     }
1120     
1121     // The callback is responsible for calling ::DeleteObject(hbmp).
1122     (*m_findIndicatorCallback)(toAPI(this), hbmp, selectionRect, fadeOut, m_findIndicatorCallbackContext);
1123 }
1124
1125 void WebView::setFindIndicatorCallback(WKViewFindIndicatorCallback callback, void* context)
1126 {
1127     m_findIndicatorCallback = callback;
1128     m_findIndicatorCallbackContext = context;
1129 }
1130
1131 WKViewFindIndicatorCallback WebView::getFindIndicatorCallback(void** context)
1132 {
1133     if (context)
1134         *context = m_findIndicatorCallbackContext;
1135     
1136     return m_findIndicatorCallback;
1137 }
1138
1139 void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
1140 {
1141 }
1142
1143 void WebView::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
1144 {
1145 }
1146
1147 double WebView::customRepresentationZoomFactor()
1148 {
1149     return 1;
1150 }
1151
1152 void WebView::setCustomRepresentationZoomFactor(double)
1153 {
1154 }
1155
1156 void WebView::didChangeScrollbarsForMainFrame() const
1157 {
1158 }
1159
1160 void WebView::setIsInWindow(bool isInWindow)
1161 {
1162     m_isInWindow = isInWindow;
1163     m_page->viewStateDidChange(WebPageProxy::ViewIsInWindow);
1164 }
1165
1166 #if USE(ACCELERATED_COMPOSITING)
1167
1168 void WebView::enterAcceleratedCompositingMode(const LayerTreeContext&)
1169 {
1170     ASSERT(useNewDrawingArea());
1171     // FIXME: Implement.
1172     ASSERT_NOT_REACHED();
1173 }
1174
1175 void WebView::exitAcceleratedCompositingMode()
1176 {
1177     ASSERT(useNewDrawingArea());
1178     // FIXME: Implement.
1179     ASSERT_NOT_REACHED();
1180 }
1181
1182 #endif // USE(ACCELERATED_COMPOSITING)
1183
1184 HWND WebView::nativeWindow()
1185 {
1186     return m_window;
1187 }
1188
1189 // WebCore::WindowMessageListener
1190
1191 void WebView::windowReceivedMessage(HWND, UINT message, WPARAM wParam, LPARAM)
1192 {
1193     switch (message) {
1194     case WM_NCACTIVATE:
1195         updateActiveStateSoon();
1196         break;
1197     case WM_SETTINGCHANGE:
1198         // systemParameterChanged(wParam);
1199         break;
1200     }
1201 }
1202
1203 HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
1204 {
1205     *ppvObject = 0;
1206     if (IsEqualGUID(riid, IID_IUnknown))
1207         *ppvObject = static_cast<IUnknown*>(this);
1208     else if (IsEqualGUID(riid, IID_IDropTarget))
1209         *ppvObject = static_cast<IDropTarget*>(this);
1210     else
1211         return E_NOINTERFACE;
1212
1213     AddRef();
1214     return S_OK;
1215 }
1216
1217 ULONG STDMETHODCALLTYPE WebView::AddRef(void)
1218 {
1219     ref();
1220     return refCount();
1221 }
1222
1223 ULONG STDMETHODCALLTYPE WebView::Release(void)
1224 {
1225     deref();
1226     return refCount();
1227 }
1228
1229 static DWORD dragOperationToDragCursor(DragOperation op)
1230 {
1231     DWORD res = DROPEFFECT_NONE;
1232     if (op & DragOperationCopy) 
1233         res = DROPEFFECT_COPY;
1234     else if (op & DragOperationLink) 
1235         res = DROPEFFECT_LINK;
1236     else if (op & DragOperationMove) 
1237         res = DROPEFFECT_MOVE;
1238     else if (op & DragOperationGeneric) 
1239         res = DROPEFFECT_MOVE; // This appears to be the Firefox behaviour
1240     return res;
1241 }
1242
1243 WebCore::DragOperation WebView::keyStateToDragOperation(DWORD grfKeyState) const
1244 {
1245     if (!m_page)
1246         return DragOperationNone;
1247
1248     // Conforms to Microsoft's key combinations as documented for 
1249     // IDropTarget::DragOver. Note, grfKeyState is the current 
1250     // state of the keyboard modifier keys on the keyboard. See:
1251     // <http://msdn.microsoft.com/en-us/library/ms680129(VS.85).aspx>.
1252     DragOperation operation = m_page->dragOperation();
1253
1254     if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
1255         operation = DragOperationLink;
1256     else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
1257         operation = DragOperationCopy;
1258     else if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
1259         operation = DragOperationGeneric;
1260
1261     return operation;
1262 }
1263
1264 HRESULT STDMETHODCALLTYPE WebView::DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1265 {
1266     m_dragData = 0;
1267     m_page->resetDragOperation();
1268
1269     if (m_dropTargetHelper)
1270         m_dropTargetHelper->DragEnter(m_window, pDataObject, (POINT*)&pt, *pdwEffect);
1271
1272     POINTL localpt = pt;
1273     ::ScreenToClient(m_window, (LPPOINT)&localpt);
1274     DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1275     m_page->performDragControllerAction(DragControllerActionEntered, &data);
1276     *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
1277
1278     m_lastDropEffect = *pdwEffect;
1279     m_dragData = pDataObject;
1280
1281     return S_OK;
1282 }
1283
1284 HRESULT STDMETHODCALLTYPE WebView::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1285 {
1286     if (m_dropTargetHelper)
1287         m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
1288
1289     if (m_dragData) {
1290         POINTL localpt = pt;
1291         ::ScreenToClient(m_window, (LPPOINT)&localpt);
1292         DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1293         m_page->performDragControllerAction(DragControllerActionUpdated, &data);
1294         *pdwEffect = dragOperationToDragCursor(m_page->dragOperation());
1295     } else
1296         *pdwEffect = DROPEFFECT_NONE;
1297
1298     m_lastDropEffect = *pdwEffect;
1299     return S_OK;
1300 }
1301
1302 HRESULT STDMETHODCALLTYPE WebView::DragLeave()
1303 {
1304     if (m_dropTargetHelper)
1305         m_dropTargetHelper->DragLeave();
1306
1307     if (m_dragData) {
1308         DragData data(m_dragData.get(), IntPoint(), IntPoint(), DragOperationNone);
1309         m_page->performDragControllerAction(DragControllerActionExited, &data);
1310         m_dragData = 0;
1311         m_page->resetDragOperation();
1312     }
1313     return S_OK;
1314 }
1315
1316 HRESULT STDMETHODCALLTYPE WebView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
1317 {
1318     if (m_dropTargetHelper)
1319         m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
1320
1321     m_dragData = 0;
1322     *pdwEffect = m_lastDropEffect;
1323     POINTL localpt = pt;
1324     ::ScreenToClient(m_window, (LPPOINT)&localpt);
1325     DragData data(pDataObject, IntPoint(localpt.x, localpt.y), IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
1326     m_page->performDragControllerAction(DragControllerActionPerformDrag, &data);
1327     return S_OK;
1328 }
1329
1330 } // namespace WebKit