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