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