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
useNewDrawingArea()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
WebViewWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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
wndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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
registerWebViewWindowClass()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
WebView(RECT rect,WebContext * context,WebPageGroup * pageGroup,HWND parentWindow)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
~WebView()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
initialize()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
initializeUndoClient(const WKViewUndoClient * client)325 void WebView::initializeUndoClient(const WKViewUndoClient* client)
326 {
327 m_undoClient.initialize(client);
328 }
329
setParentWindow(HWND parentWindow)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
findTopLevelParentWindow(HWND window)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
windowAncestryDidChange()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
onMouseEvent(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
onWheelEvent(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
onHorizontalScroll(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
onVerticalScroll(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
onGestureNotify(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
onGesture(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
onKeyEvent(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
drawPageBackground(HDC dc,const RECT & rect)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
paint(HDC hdc,const IntRect & dirtyRect)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
flashRects(HDC dc,const IntRect rects[],size_t rectCount,HBRUSH brush)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
createBrush(const Color & color)664 static OwnPtr<HBRUSH> createBrush(const Color& color)
665 {
666 return adoptPtr(::CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
667 }
668
onPaintEvent(HWND hWnd,UINT message,WPARAM,LPARAM,bool & handled)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
onPrintClientEvent(HWND hWnd,UINT,WPARAM wParam,LPARAM,bool & handled)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
onSizeEvent(HWND,UINT,WPARAM,LPARAM lParam,bool & handled)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
onWindowPositionChangedEvent(HWND,UINT,WPARAM,LPARAM lParam,bool & handled)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
onSetFocusEvent(HWND,UINT,WPARAM,LPARAM lParam,bool & handled)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
onKillFocusEvent(HWND,UINT,WPARAM,LPARAM lParam,bool & handled)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
onTimerEvent(HWND hWnd,UINT,WPARAM wParam,LPARAM,bool & handled)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
onShowWindowEvent(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
onSetCursor(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam,bool & handled)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
updateActiveState()787 void WebView::updateActiveState()
788 {
789 m_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
790 }
791
updateActiveStateSoon()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
initCommonControls()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
initializeToolTipWindow()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
startTrackingMouseLeave()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
stopTrackingMouseLeave()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
shouldInitializeTrackPointHack()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
close()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
createDrawingAreaProxy()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
setViewNeedsDisplay(const WebCore::IntRect & rect)923 void WebView::setViewNeedsDisplay(const WebCore::IntRect& rect)
924 {
925 RECT r = rect;
926 ::InvalidateRect(m_window, &r, false);
927 }
928
displayView()929 void WebView::displayView()
930 {
931 ::UpdateWindow(m_window);
932 }
933
scrollView(const IntRect & scrollRect,const IntSize & scrollOffset)934 void WebView::scrollView(const IntRect& scrollRect, const IntSize& scrollOffset)
935 {
936 // FIXME: Actually scroll the view contents.
937 setViewNeedsDisplay(scrollRect);
938 }
939
flashBackingStoreUpdates(const Vector<IntRect> & updateRects)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
viewSize()948 WebCore::IntSize WebView::viewSize()
949 {
950 RECT clientRect;
951 GetClientRect(m_window, &clientRect);
952
953 return IntRect(clientRect).size();
954 }
955
isViewWindowActive()956 bool WebView::isViewWindowActive()
957 {
958 HWND activeWindow = ::GetActiveWindow();
959 return (activeWindow && m_topLevelParentWindow == findTopLevelParentWindow(activeWindow));
960 }
961
isViewFocused()962 bool WebView::isViewFocused()
963 {
964 return ::GetFocus() == m_window;
965 }
966
isViewVisible()967 bool WebView::isViewVisible()
968 {
969 return m_isVisible;
970 }
971
isViewInWindow()972 bool WebView::isViewInWindow()
973 {
974 return m_isInWindow;
975 }
976
pageClosed()977 void WebView::pageClosed()
978 {
979 }
980
processDidCrash()981 void WebView::processDidCrash()
982 {
983 updateNativeCursor();
984 ::InvalidateRect(m_window, 0, TRUE);
985 }
986
didRelaunchProcess()987 void WebView::didRelaunchProcess()
988 {
989 updateNativeCursor();
990 ::InvalidateRect(m_window, 0, TRUE);
991 }
992
toolTipChanged(const String &,const String & newToolTip)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
cursorToShow() const1013 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
updateNativeCursor()1026 void WebView::updateNativeCursor()
1027 {
1028 m_lastCursorSet = cursorToShow();
1029 if (!m_lastCursorSet)
1030 return;
1031 ::SetCursor(m_lastCursorSet);
1032 }
1033
setCursor(const WebCore::Cursor & cursor)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
setOverrideCursor(HCURSOR overrideCursor)1042 void WebView::setOverrideCursor(HCURSOR overrideCursor)
1043 {
1044 m_overrideCursor = overrideCursor;
1045 updateNativeCursor();
1046 }
1047
setInitialFocus(bool forward)1048 void WebView::setInitialFocus(bool forward)
1049 {
1050 m_page->setInitialFocus(forward);
1051 }
1052
setScrollOffsetOnNextResize(const IntSize & scrollOffset)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
setViewportArguments(const WebCore::ViewportArguments &)1059 void WebView::setViewportArguments(const WebCore::ViewportArguments&)
1060 {
1061 }
1062
registerEditCommand(PassRefPtr<WebEditCommandProxy> prpCommand,WebPageProxy::UndoOrRedo undoOrRedo)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
clearAllEditCommands()1069 void WebView::clearAllEditCommands()
1070 {
1071 m_undoClient.clearAllEditCommands(this);
1072 }
1073
canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)1074 bool WebView::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
1075 {
1076 return m_undoClient.canUndoRedo(this, undoOrRedo);
1077 }
1078
executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)1079 void WebView::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
1080 {
1081 m_undoClient.executeUndoRedo(this, undoOrRedo);
1082 }
1083
reapplyEditCommand(WebEditCommandProxy * command)1084 void WebView::reapplyEditCommand(WebEditCommandProxy* command)
1085 {
1086 if (!m_page->isValid() || !m_page->isValidEditCommand(command))
1087 return;
1088
1089 command->reapply();
1090 }
1091
unapplyEditCommand(WebEditCommandProxy * command)1092 void WebView::unapplyEditCommand(WebEditCommandProxy* command)
1093 {
1094 if (!m_page->isValid() || !m_page->isValidEditCommand(command))
1095 return;
1096
1097 command->unapply();
1098 }
1099
convertToDeviceSpace(const FloatRect & rect)1100 FloatRect WebView::convertToDeviceSpace(const FloatRect& rect)
1101 {
1102 return rect;
1103 }
1104
windowToScreen(const IntRect & rect)1105 IntRect WebView::windowToScreen(const IntRect& rect)
1106 {
1107 return rect;
1108 }
1109
convertToUserSpace(const FloatRect & rect)1110 FloatRect WebView::convertToUserSpace(const FloatRect& rect)
1111 {
1112 return rect;
1113 }
1114
getIMMContext()1115 HIMC WebView::getIMMContext()
1116 {
1117 return Ime::ImmGetContext(m_window);
1118 }
1119
prepareCandidateWindow(HIMC hInputContext)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
resetIME()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
setInputMethodState(bool enabled)1144 void WebView::setInputMethodState(bool enabled)
1145 {
1146 Ime::ImmAssociateContextEx(m_window, 0, enabled ? IACE_DEFAULT : 0);
1147 }
1148
compositionSelectionChanged(bool hasChanged)1149 void WebView::compositionSelectionChanged(bool hasChanged)
1150 {
1151 if (m_page->editorState().hasComposition && !hasChanged)
1152 resetIME();
1153 }
1154
onIMEStartComposition()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
getCompositionString(HIMC hInputContext,DWORD type,String & result)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
compositionToUnderlines(const Vector<DWORD> & clauses,const Vector<BYTE> & attributes,Vector<CompositionUnderline> & underlines)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
imeCompositionArgumentNames(LPARAM lparam)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
imeRequestName(WPARAM wparam)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
onIMEComposition(LPARAM lparam)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
onIMEEndComposition()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
onIMERequestCharPosition(IMECHARPOSITION * charPos)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
onIMERequestReconvertString(RECONVERTSTRING * reconvertString)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
onIMERequest(WPARAM request,LPARAM data)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
onIMESelect(WPARAM wparam,LPARAM lparam)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
onIMESetContext(WPARAM wparam,LPARAM)1366 bool WebView::onIMESetContext(WPARAM wparam, LPARAM)
1367 {
1368 LOG(TextInput, "onIMESetContext %s", wparam ? "active" : "inactive");
1369 return false;
1370 }
1371
doneWithKeyEvent(const NativeWebKeyboardEvent & event,bool wasEventHandled)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
createPopupMenuProxy(WebPageProxy * page)1380 PassRefPtr<WebPopupMenuProxy> WebView::createPopupMenuProxy(WebPageProxy* page)
1381 {
1382 return WebPopupMenuProxyWin::create(this, page);
1383 }
1384
createContextMenuProxy(WebPageProxy * page)1385 PassRefPtr<WebContextMenuProxy> WebView::createContextMenuProxy(WebPageProxy* page)
1386 {
1387 return WebContextMenuProxyWin::create(m_window, page);
1388 }
1389
setFindIndicator(PassRefPtr<FindIndicator> prpFindIndicator,bool fadeOut)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
setFindIndicatorCallback(WKViewFindIndicatorCallback callback,void * context)1430 void WebView::setFindIndicatorCallback(WKViewFindIndicatorCallback callback, void* context)
1431 {
1432 m_findIndicatorCallback = callback;
1433 m_findIndicatorCallbackContext = context;
1434 }
1435
getFindIndicatorCallback(void ** context)1436 WKViewFindIndicatorCallback WebView::getFindIndicatorCallback(void** context)
1437 {
1438 if (context)
1439 *context = m_findIndicatorCallbackContext;
1440
1441 return m_findIndicatorCallback;
1442 }
1443
didCommitLoadForMainFrame(bool useCustomRepresentation)1444 void WebView::didCommitLoadForMainFrame(bool useCustomRepresentation)
1445 {
1446 }
1447
didFinishLoadingDataForCustomRepresentation(const String & suggestedFilename,const CoreIPC::DataReference &)1448 void WebView::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
1449 {
1450 }
1451
customRepresentationZoomFactor()1452 double WebView::customRepresentationZoomFactor()
1453 {
1454 return 1;
1455 }
1456
setCustomRepresentationZoomFactor(double)1457 void WebView::setCustomRepresentationZoomFactor(double)
1458 {
1459 }
1460
didChangeScrollbarsForMainFrame() const1461 void WebView::didChangeScrollbarsForMainFrame() const
1462 {
1463 }
1464
findStringInCustomRepresentation(const String &,FindOptions,unsigned)1465 void WebView::findStringInCustomRepresentation(const String&, FindOptions, unsigned)
1466 {
1467 }
1468
countStringMatchesInCustomRepresentation(const String &,FindOptions,unsigned)1469 void WebView::countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned)
1470 {
1471 }
1472
setIsInWindow(bool isInWindow)1473 void WebView::setIsInWindow(bool isInWindow)
1474 {
1475 m_isInWindow = isInWindow;
1476 m_page->viewStateDidChange(WebPageProxy::ViewIsInWindow);
1477 }
1478
setIsVisible(bool isVisible)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
enterAcceleratedCompositingMode(const LayerTreeContext &)1489 void WebView::enterAcceleratedCompositingMode(const LayerTreeContext&)
1490 {
1491 ASSERT(useNewDrawingArea());
1492 // FIXME: Implement.
1493 ASSERT_NOT_REACHED();
1494 }
1495
exitAcceleratedCompositingMode()1496 void WebView::exitAcceleratedCompositingMode()
1497 {
1498 ASSERT(useNewDrawingArea());
1499 // FIXME: Implement.
1500 ASSERT_NOT_REACHED();
1501 }
1502
1503 #endif // USE(ACCELERATED_COMPOSITING)
1504
nativeWindow()1505 HWND WebView::nativeWindow()
1506 {
1507 return m_window;
1508 }
1509
1510 // WebCore::WindowMessageListener
1511
windowReceivedMessage(HWND,UINT message,WPARAM wParam,LPARAM)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
QueryInterface(REFIID riid,void ** ppvObject)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
AddRef(void)1538 ULONG STDMETHODCALLTYPE WebView::AddRef(void)
1539 {
1540 ref();
1541 return refCount();
1542 }
1543
Release(void)1544 ULONG STDMETHODCALLTYPE WebView::Release(void)
1545 {
1546 deref();
1547 return refCount();
1548 }
1549
dragOperationToDragCursor(DragOperation op)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
keyStateToDragOperation(DWORD grfKeyState) const1564 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
DragEnter(IDataObject * pDataObject,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)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
DragOver(DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)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
DragLeave()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
Drop(IDataObject * pDataObject,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)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