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