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