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 "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 54using namespace WebCore; 55 56const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass"; 57 58 59LRESULT 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 67PassRefPtr<SharedBuffer> loadResourceIntoBuffer(const char* name) 68{ 69 notImplemented(); 70 return 0; 71} 72 73 74WebView::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 121WebView::~WebView() 122{ 123 delete m_page; 124 DestroyWindow(m_windowHandle); 125} 126 127void 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 150void WebView::cleanup() 151{ 152 UnregisterClass(kWebViewWindowClassName, WebCore::instanceHandle()); 153} 154 155PassRefPtr<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 181void WebView::runJavaScriptAlert(const String& message) 182{ 183 notImplemented(); 184} 185 186bool WebView::runJavaScriptConfirm(const String& message) 187{ 188 notImplemented(); 189 return false; 190} 191 192bool WebView::runJavaScriptPrompt(const String& message, const String& defaultValue, String& result) 193{ 194 notImplemented(); 195 return false; 196} 197 198void WebView::frameRect(RECT* rect) const 199{ 200 GetWindowRect(m_windowHandle, rect); 201} 202 203FrameView* WebView::view() const 204{ 205 return m_frame ? m_frame->view() : 0; 206} 207 208void WebView::load(LPCWSTR url) 209{ 210 load(String(url)); 211} 212 213void WebView::load(const String &url) 214{ 215 load(WebCore::ResourceRequest(url)); 216} 217 218void WebView::load(const WebCore::ResourceRequest &request) 219{ 220 frame()->loader()->load(request, false); 221} 222 223void WebView::reload() 224{ 225 frame()->loader()->reload(); 226} 227 228void WebView::stop() 229{ 230 frame()->loader()->stopAllLoaders(); 231} 232 233void 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 248bool 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 279bool 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 341bool 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 347bool 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 369bool 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 383bool 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 391LRESULT 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