1 /* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. 3 * Copyright (C) 2010 Patrick Gansterer <paroga (at) paroga.com> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "WebView.h" 28 29 #include "ChromeClientWinCE.h" 30 #include "ContextMenuClientWinCE.h" 31 #include "DragClientWinCE.h" 32 #include "EditorClientWinCE.h" 33 #include "FocusController.h" 34 #include "Frame.h" 35 #include "FrameLoader.h" 36 #include "FrameLoaderClientWinCE.h" 37 #include "FrameView.h" 38 #include "GraphicsContext.h" 39 #include "InitializeThreading.h" 40 #include "InspectorClientWinCE.h" 41 #include "IntSize.h" 42 #include "MainThread.h" 43 #include "NotImplemented.h" 44 #include "Page.h" 45 #include "PlatformKeyboardEvent.h" 46 #include "PlatformMouseEvent.h" 47 #include "PlatformStrategiesWinCE.h" 48 #include "PlatformWheelEvent.h" 49 #include "ResourceRequest.h" 50 #include "Settings.h" 51 #include "SharedBuffer.h" 52 #include "WebCoreInstanceHandle.h" 53 54 using namespace WebCore; 55 56 const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass"; 57 58 59 LRESULT CALLBACK WebView::webViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 60 { 61 if (WebView* webView = reinterpret_cast<WebView*>(GetWindowLong(hWnd, 0))) 62 return webView->wndProc(hWnd, message, wParam, lParam); 63 64 return DefWindowProc(hWnd, message, wParam, lParam); 65 } 66 67 PassRefPtr<SharedBuffer> loadResourceIntoBuffer(const char* name) 68 { 69 notImplemented(); 70 return 0; 71 } 72 73 74 WebView::WebView(HWND hwnd, unsigned features) 75 : m_frame(0) 76 , m_page(0) 77 , m_parentWindowHandle(hwnd) 78 , m_enableDoubleBuffer(features & EnableDoubleBuffering) 79 { 80 RECT rcClient; 81 GetClientRect(hwnd, &rcClient); 82 83 m_windowHandle = CreateWindow(kWebViewWindowClassName, 0, WS_CHILD, 84 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hwnd, 0, WebCore::instanceHandle(), 0); 85 86 SetWindowLong(m_windowHandle, 0, reinterpret_cast<LONG>(this)); 87 88 MoveWindow(m_windowHandle, 0, 0, rcClient.right, rcClient.bottom, TRUE); 89 ShowWindow(m_windowHandle, SW_SHOW); 90 91 Page::PageClients pageClients; 92 pageClients.chromeClient = new WebKit::ChromeClientWinCE(this); 93 pageClients.contextMenuClient = new WebKit::ContextMenuClientWinCE(this); 94 pageClients.editorClient = new WebKit::EditorClientWinCE(this); 95 pageClients.dragClient = new WebKit::DragClientWinCE(); 96 pageClients.inspectorClient = new WebKit::InspectorClientWinCE(this); 97 m_page = new Page(pageClients); 98 99 Settings* settings = m_page->settings(); 100 settings->setDefaultFixedFontSize(14); 101 settings->setDefaultFontSize(14); 102 settings->setMinimumFontSize(8); 103 settings->setMinimumLogicalFontSize(8); 104 settings->setJavaScriptEnabled(true); 105 settings->setLoadsImagesAutomatically(true); 106 107 WebKit::FrameLoaderClientWinCE* loaderClient = new WebKit::FrameLoaderClientWinCE(this); 108 RefPtr<Frame> frame = Frame::create(m_page, 0, loaderClient); 109 m_frame = frame.get(); 110 loaderClient->setFrame(m_frame); 111 112 m_page->mainFrame()->init(); 113 114 if (view()) { 115 RECT windowRect; 116 frameRect(&windowRect); 117 view()->resize(IntRect(windowRect).size()); 118 } 119 } 120 121 WebView::~WebView() 122 { 123 delete m_page; 124 DestroyWindow(m_windowHandle); 125 } 126 127 void WebView::initialize(HINSTANCE instanceHandle) 128 { 129 JSC::initializeThreading(); 130 WTF::initializeMainThread(); 131 PlatformStrategiesWinCE::initialize(); 132 133 WebCore::setInstanceHandle(instanceHandle); 134 135 WNDCLASS wc; 136 wc.style = CS_DBLCLKS; 137 wc.lpfnWndProc = WebView::webViewWndProc; 138 wc.cbClsExtra = 0; 139 wc.cbWndExtra = sizeof(void *); 140 wc.hInstance = instanceHandle; 141 wc.hIcon = 0; 142 wc.hCursor = LoadCursor(0, IDC_ARROW); 143 wc.hbrBackground = 0; 144 wc.lpszMenuName = 0; 145 wc.lpszClassName = kWebViewWindowClassName; 146 147 RegisterClass(&wc); 148 } 149 150 void WebView::cleanup() 151 { 152 UnregisterClass(kWebViewWindowClassName, WebCore::instanceHandle()); 153 } 154 155 PassRefPtr<Frame> WebView::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, 156 bool /*allowsScrolling*/, int /*marginWidth*/, int /*marginHeight*/) 157 { 158 Frame* coreFrame = m_frame; 159 160 WebKit::FrameLoaderClientWinCE *loaderClient = new WebKit::FrameLoaderClientWinCE(this); 161 RefPtr<Frame> childFrame = Frame::create(m_page, ownerElement, loaderClient); 162 loaderClient->setFrame(childFrame.get()); 163 164 coreFrame->tree()->appendChild(childFrame); 165 childFrame->tree()->setName(name); 166 childFrame->init(); 167 168 // The creation of the frame may have run arbitrary JavaScript that removed it from the page already. 169 if (!childFrame->page()) 170 return 0; 171 172 coreFrame->loader()->loadURLIntoChildFrame(url, referrer, childFrame.get()); 173 174 // The frame's onload handler may have removed it from the document. 175 if (!childFrame->tree()->parent()) 176 return 0; 177 178 return childFrame.release(); 179 } 180 181 void WebView::runJavaScriptAlert(const String& message) 182 { 183 notImplemented(); 184 } 185 186 bool WebView::runJavaScriptConfirm(const String& message) 187 { 188 notImplemented(); 189 return false; 190 } 191 192 bool WebView::runJavaScriptPrompt(const String& message, const String& defaultValue, String& result) 193 { 194 notImplemented(); 195 return false; 196 } 197 198 void WebView::frameRect(RECT* rect) const 199 { 200 GetWindowRect(m_windowHandle, rect); 201 } 202 203 FrameView* WebView::view() const 204 { 205 return m_frame ? m_frame->view() : 0; 206 } 207 208 void WebView::load(LPCWSTR url) 209 { 210 load(String(url)); 211 } 212 213 void WebView::load(const String &url) 214 { 215 load(WebCore::ResourceRequest(url)); 216 } 217 218 void WebView::load(const WebCore::ResourceRequest &request) 219 { 220 frame()->loader()->load(request, false); 221 } 222 223 void WebView::reload() 224 { 225 frame()->loader()->reload(); 226 } 227 228 void WebView::stop() 229 { 230 frame()->loader()->stopAllLoaders(); 231 } 232 233 void WebView::paint(HDC hDC, const IntRect& clipRect) 234 { 235 FrameView* frameView = view(); 236 if (!frameView) 237 return; 238 239 OwnPtr<HRGN> clipRgn(CreateRectRgn(clipRect.x(), clipRect.y(), clipRect.maxX(), clipRect.maxY())); 240 SelectClipRgn(hDC, clipRgn.get()); 241 242 frameView->updateLayoutAndStyleIfNeededRecursive(); 243 244 GraphicsContext gc(hDC); 245 frameView->paint(&gc, clipRect); 246 } 247 248 bool WebView::handlePaint(HWND hWnd) 249 { 250 RECT updateRect; 251 if (!GetUpdateRect(hWnd, &updateRect, false)) 252 return false; 253 254 PAINTSTRUCT ps; 255 HDC hDC = BeginPaint(m_windowHandle, &ps); 256 257 IntRect clipRect(updateRect); 258 259 if (m_enableDoubleBuffer) { 260 if (!m_doubleBufferDC) { 261 RECT rcClient; 262 GetClientRect(m_windowHandle, &rcClient); 263 264 m_doubleBufferDC = adoptPtr(CreateCompatibleDC(hDC)); 265 m_doubleBufferBitmap = adoptPtr(CreateCompatibleBitmap(hDC, rcClient.right, rcClient.bottom)); 266 SelectObject(m_doubleBufferDC.get(), m_doubleBufferBitmap.get()); 267 } 268 269 paint(m_doubleBufferDC.get(), clipRect); 270 271 BitBlt(hDC, clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height(), m_doubleBufferDC.get(), clipRect.x(), clipRect.y(), SRCCOPY); 272 } else 273 paint(hDC, clipRect); 274 275 EndPaint(m_windowHandle, &ps); 276 return true; 277 } 278 279 bool WebView::handleMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 280 { 281 static LONG globalClickCount; 282 static IntPoint globalPrevPoint; 283 static MouseButton globalPrevButton; 284 static LONG globalPrevMouseDownTime; 285 286 // Create our event. 287 // On WM_MOUSELEAVE we need to create a mouseout event, so we force the position 288 // of the event to be at (MINSHORT, MINSHORT). 289 PlatformMouseEvent mouseEvent(hWnd, message, wParam, lParam); 290 291 bool insideThreshold = abs(globalPrevPoint.x() - mouseEvent.pos().x()) < ::GetSystemMetrics(SM_CXDOUBLECLK) 292 && abs(globalPrevPoint.y() - mouseEvent.pos().y()) < ::GetSystemMetrics(SM_CYDOUBLECLK); 293 LONG messageTime = 0; 294 295 bool handled = false; 296 if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) { 297 // FIXME: I'm not sure if this is the "right" way to do this 298 // but without this call, we never become focused since we don't allow 299 // the default handling of mouse events. 300 SetFocus(m_windowHandle); 301 302 PlatformMouseEvent moveEvent(hWnd, WM_MOUSEMOVE, 0, lParam, false); 303 moveEvent.setClickCount(0); 304 m_page->mainFrame()->eventHandler()->handleMouseMoveEvent(moveEvent); 305 306 // Always start capturing events when the mouse goes down in our HWND. 307 SetCapture(m_windowHandle); 308 309 if (insideThreshold && mouseEvent.button() == globalPrevButton) 310 globalClickCount++; 311 else 312 // Reset the click count. 313 globalClickCount = 1; 314 globalPrevMouseDownTime = messageTime; 315 globalPrevButton = mouseEvent.button(); 316 globalPrevPoint = mouseEvent.pos(); 317 318 mouseEvent.setClickCount(globalClickCount); 319 handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent); 320 } else if (message == WM_LBUTTONDBLCLK || message == WM_MBUTTONDBLCLK || message == WM_RBUTTONDBLCLK) { 321 globalClickCount++; 322 mouseEvent.setClickCount(globalClickCount); 323 handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent); 324 } else if (message == WM_LBUTTONUP || message == WM_MBUTTONUP || message == WM_RBUTTONUP) { 325 // Record the global position and the button of the up. 326 globalPrevButton = mouseEvent.button(); 327 globalPrevPoint = mouseEvent.pos(); 328 mouseEvent.setClickCount(globalClickCount); 329 m_page->mainFrame()->eventHandler()->handleMouseReleaseEvent(mouseEvent); 330 ReleaseCapture(); 331 } else if (message == WM_MOUSEMOVE) { 332 if (!insideThreshold) 333 globalClickCount = 0; 334 mouseEvent.setClickCount(globalClickCount); 335 handled = m_page->mainFrame()->eventHandler()->mouseMoved(mouseEvent); 336 } 337 338 return handled; 339 } 340 341 bool WebView::handleMouseWheel(HWND hWnd, WPARAM wParam, LPARAM lParam, bool isHorizontal) 342 { 343 PlatformWheelEvent wheelEvent(hWnd, wParam, lParam, isHorizontal); 344 return frame()->eventHandler()->handleWheelEvent(wheelEvent); 345 } 346 347 bool WebView::handleKeyDown(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown) 348 { 349 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 350 351 PlatformKeyboardEvent keyEvent(m_windowHandle, virtualKeyCode, keyData, PlatformKeyboardEvent::RawKeyDown, systemKeyDown); 352 bool handled = frame->eventHandler()->keyEvent(keyEvent); 353 354 // These events cannot be canceled, and we have no default handling for them. 355 // FIXME: match IE list more closely, see <http://msdn2.microsoft.com/en-us/library/ms536938.aspx>. 356 if (systemKeyDown && virtualKeyCode != VK_RETURN) 357 return false; 358 359 if (handled) { 360 MSG msg; 361 if (!systemKeyDown) 362 ::PeekMessage(&msg, m_windowHandle, WM_CHAR, WM_CHAR, PM_REMOVE); 363 return true; 364 } 365 366 return handled; 367 } 368 369 bool WebView::handleKeyPress(WPARAM charCode, LPARAM keyData, bool systemKeyDown) 370 { 371 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 372 373 PlatformKeyboardEvent keyEvent(m_windowHandle, charCode, keyData, PlatformKeyboardEvent::Char, systemKeyDown); 374 // IE does not dispatch keypress event for WM_SYSCHAR. 375 if (systemKeyDown) 376 return frame->eventHandler()->handleAccessKey(keyEvent); 377 if (frame->eventHandler()->keyEvent(keyEvent)) 378 return true; 379 380 return false; 381 } 382 383 bool WebView::handleKeyUp(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown) 384 { 385 PlatformKeyboardEvent keyEvent(m_windowHandle, virtualKeyCode, keyData, PlatformKeyboardEvent::KeyUp, systemKeyDown); 386 387 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 388 return frame->eventHandler()->keyEvent(keyEvent); 389 } 390 391 LRESULT WebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 392 { 393 bool handled = false; 394 395 if (view()) { 396 switch (message) { 397 case WM_PAINT: 398 handled = handlePaint(hWnd); 399 break; 400 401 case WM_MOUSEMOVE: 402 case WM_LBUTTONDOWN: 403 case WM_MBUTTONDOWN: 404 case WM_RBUTTONDOWN: 405 case WM_LBUTTONDBLCLK: 406 case WM_MBUTTONDBLCLK: 407 case WM_RBUTTONDBLCLK: 408 case WM_LBUTTONUP: 409 case WM_MBUTTONUP: 410 case WM_RBUTTONUP: 411 if (frame()->eventHandler() && view()->didFirstLayout()) 412 handled = handleMouseEvent(hWnd, message, wParam, lParam); 413 break; 414 415 case WM_MOUSEWHEEL: 416 if (frame()->eventHandler() && view()->didFirstLayout()) 417 handled = handleMouseWheel(hWnd, wParam, lParam, wParam & MK_SHIFT); 418 break; 419 420 case WM_SYSKEYDOWN: 421 handled = handleKeyDown(wParam, lParam, true); 422 break; 423 424 case WM_KEYDOWN: 425 handled = handleKeyDown(wParam, lParam, false); 426 break; 427 428 case WM_SYSKEYUP: 429 handled = handleKeyUp(wParam, lParam, true); 430 break; 431 432 case WM_KEYUP: 433 handled = handleKeyUp(wParam, lParam, false); 434 break; 435 436 case WM_SYSCHAR: 437 handled = handleKeyPress(wParam, lParam, true); 438 break; 439 440 case WM_CHAR: 441 handled = handleKeyPress(wParam, lParam, false); 442 break; 443 444 case WM_CLOSE: 445 PostMessage(m_parentWindowHandle, WM_CLOSE, wParam, lParam); 446 handled = true; 447 break; 448 449 default: 450 break; 451 } 452 } 453 454 if (handled) 455 return 0; 456 457 return DefWindowProc(hWnd, message, wParam, lParam); 458 } 459