| /* |
| * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. |
| * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "WebView.h" |
| |
| #include "ChromeClientWinCE.h" |
| #include "ContextMenuClientWinCE.h" |
| #include "DragClientWinCE.h" |
| #include "EditorClientWinCE.h" |
| #include "FocusController.h" |
| #include "Frame.h" |
| #include "FrameLoader.h" |
| #include "FrameLoaderClientWinCE.h" |
| #include "FrameView.h" |
| #include "GraphicsContext.h" |
| #include "InitializeThreading.h" |
| #include "InspectorClientWinCE.h" |
| #include "IntSize.h" |
| #include "MainThread.h" |
| #include "NotImplemented.h" |
| #include "Page.h" |
| #include "PlatformKeyboardEvent.h" |
| #include "PlatformMouseEvent.h" |
| #include "PlatformStrategiesWinCE.h" |
| #include "PlatformWheelEvent.h" |
| #include "ResourceRequest.h" |
| #include "Settings.h" |
| #include "SharedBuffer.h" |
| #include "WebCoreInstanceHandle.h" |
| |
| using namespace WebCore; |
| |
| const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass"; |
| |
| |
| LRESULT CALLBACK WebView::webViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| if (WebView* webView = reinterpret_cast<WebView*>(GetWindowLong(hWnd, 0))) |
| return webView->wndProc(hWnd, message, wParam, lParam); |
| |
| return DefWindowProc(hWnd, message, wParam, lParam); |
| } |
| |
| PassRefPtr<SharedBuffer> loadResourceIntoBuffer(const char* name) |
| { |
| notImplemented(); |
| return 0; |
| } |
| |
| |
| WebView::WebView(HWND hwnd, unsigned features) |
| : m_frame(0) |
| , m_page(0) |
| , m_parentWindowHandle(hwnd) |
| , m_enableDoubleBuffer(features & EnableDoubleBuffering) |
| { |
| RECT rcClient; |
| GetClientRect(hwnd, &rcClient); |
| |
| m_windowHandle = CreateWindow(kWebViewWindowClassName, 0, WS_CHILD, |
| CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hwnd, 0, WebCore::instanceHandle(), 0); |
| |
| SetWindowLong(m_windowHandle, 0, reinterpret_cast<LONG>(this)); |
| |
| MoveWindow(m_windowHandle, 0, 0, rcClient.right, rcClient.bottom, TRUE); |
| ShowWindow(m_windowHandle, SW_SHOW); |
| |
| Page::PageClients pageClients; |
| pageClients.chromeClient = new WebKit::ChromeClientWinCE(this); |
| pageClients.contextMenuClient = new WebKit::ContextMenuClientWinCE(this); |
| pageClients.editorClient = new WebKit::EditorClientWinCE(this); |
| pageClients.dragClient = new WebKit::DragClientWinCE(); |
| pageClients.inspectorClient = new WebKit::InspectorClientWinCE(this); |
| m_page = new Page(pageClients); |
| |
| Settings* settings = m_page->settings(); |
| settings->setDefaultFixedFontSize(14); |
| settings->setDefaultFontSize(14); |
| settings->setMinimumFontSize(8); |
| settings->setMinimumLogicalFontSize(8); |
| settings->setJavaScriptEnabled(true); |
| settings->setLoadsImagesAutomatically(true); |
| |
| WebKit::FrameLoaderClientWinCE* loaderClient = new WebKit::FrameLoaderClientWinCE(this); |
| RefPtr<Frame> frame = Frame::create(m_page, 0, loaderClient); |
| m_frame = frame.get(); |
| loaderClient->setFrame(m_frame); |
| |
| m_page->mainFrame()->init(); |
| |
| if (view()) { |
| RECT windowRect; |
| frameRect(&windowRect); |
| view()->resize(IntRect(windowRect).size()); |
| } |
| } |
| |
| WebView::~WebView() |
| { |
| delete m_page; |
| DestroyWindow(m_windowHandle); |
| } |
| |
| void WebView::initialize(HINSTANCE instanceHandle) |
| { |
| JSC::initializeThreading(); |
| WTF::initializeMainThread(); |
| PlatformStrategiesWinCE::initialize(); |
| |
| WebCore::setInstanceHandle(instanceHandle); |
| |
| WNDCLASS wc; |
| wc.style = CS_DBLCLKS; |
| wc.lpfnWndProc = WebView::webViewWndProc; |
| wc.cbClsExtra = 0; |
| wc.cbWndExtra = sizeof(void *); |
| wc.hInstance = instanceHandle; |
| wc.hIcon = 0; |
| wc.hCursor = LoadCursor(0, IDC_ARROW); |
| wc.hbrBackground = 0; |
| wc.lpszMenuName = 0; |
| wc.lpszClassName = kWebViewWindowClassName; |
| |
| RegisterClass(&wc); |
| } |
| |
| void WebView::cleanup() |
| { |
| UnregisterClass(kWebViewWindowClassName, WebCore::instanceHandle()); |
| } |
| |
| PassRefPtr<Frame> WebView::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, |
| bool /*allowsScrolling*/, int /*marginWidth*/, int /*marginHeight*/) |
| { |
| Frame* coreFrame = m_frame; |
| |
| WebKit::FrameLoaderClientWinCE *loaderClient = new WebKit::FrameLoaderClientWinCE(this); |
| RefPtr<Frame> childFrame = Frame::create(m_page, ownerElement, loaderClient); |
| loaderClient->setFrame(childFrame.get()); |
| |
| coreFrame->tree()->appendChild(childFrame); |
| childFrame->tree()->setName(name); |
| childFrame->init(); |
| |
| // The creation of the frame may have run arbitrary JavaScript that removed it from the page already. |
| if (!childFrame->page()) |
| return 0; |
| |
| coreFrame->loader()->loadURLIntoChildFrame(url, referrer, childFrame.get()); |
| |
| // The frame's onload handler may have removed it from the document. |
| if (!childFrame->tree()->parent()) |
| return 0; |
| |
| return childFrame.release(); |
| } |
| |
| void WebView::runJavaScriptAlert(const String& message) |
| { |
| notImplemented(); |
| } |
| |
| bool WebView::runJavaScriptConfirm(const String& message) |
| { |
| notImplemented(); |
| return false; |
| } |
| |
| bool WebView::runJavaScriptPrompt(const String& message, const String& defaultValue, String& result) |
| { |
| notImplemented(); |
| return false; |
| } |
| |
| void WebView::frameRect(RECT* rect) const |
| { |
| GetWindowRect(m_windowHandle, rect); |
| } |
| |
| FrameView* WebView::view() const |
| { |
| return m_frame ? m_frame->view() : 0; |
| } |
| |
| void WebView::load(LPCWSTR url) |
| { |
| load(String(url)); |
| } |
| |
| void WebView::load(const String &url) |
| { |
| load(WebCore::ResourceRequest(url)); |
| } |
| |
| void WebView::load(const WebCore::ResourceRequest &request) |
| { |
| frame()->loader()->load(request, false); |
| } |
| |
| void WebView::reload() |
| { |
| frame()->loader()->reload(); |
| } |
| |
| void WebView::stop() |
| { |
| frame()->loader()->stopAllLoaders(); |
| } |
| |
| void WebView::paint(HDC hDC, const IntRect& clipRect) |
| { |
| FrameView* frameView = view(); |
| if (!frameView) |
| return; |
| |
| OwnPtr<HRGN> clipRgn(CreateRectRgn(clipRect.x(), clipRect.y(), clipRect.maxX(), clipRect.maxY())); |
| SelectClipRgn(hDC, clipRgn.get()); |
| |
| frameView->updateLayoutAndStyleIfNeededRecursive(); |
| |
| GraphicsContext gc(hDC); |
| frameView->paint(&gc, clipRect); |
| } |
| |
| bool WebView::handlePaint(HWND hWnd) |
| { |
| RECT updateRect; |
| if (!GetUpdateRect(hWnd, &updateRect, false)) |
| return false; |
| |
| PAINTSTRUCT ps; |
| HDC hDC = BeginPaint(m_windowHandle, &ps); |
| |
| IntRect clipRect(updateRect); |
| |
| if (m_enableDoubleBuffer) { |
| if (!m_doubleBufferDC) { |
| RECT rcClient; |
| GetClientRect(m_windowHandle, &rcClient); |
| |
| m_doubleBufferDC = adoptPtr(CreateCompatibleDC(hDC)); |
| m_doubleBufferBitmap = adoptPtr(CreateCompatibleBitmap(hDC, rcClient.right, rcClient.bottom)); |
| SelectObject(m_doubleBufferDC.get(), m_doubleBufferBitmap.get()); |
| } |
| |
| paint(m_doubleBufferDC.get(), clipRect); |
| |
| BitBlt(hDC, clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height(), m_doubleBufferDC.get(), clipRect.x(), clipRect.y(), SRCCOPY); |
| } else |
| paint(hDC, clipRect); |
| |
| EndPaint(m_windowHandle, &ps); |
| return true; |
| } |
| |
| bool WebView::handleMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| static LONG globalClickCount; |
| static IntPoint globalPrevPoint; |
| static MouseButton globalPrevButton; |
| static LONG globalPrevMouseDownTime; |
| |
| // Create our event. |
| // On WM_MOUSELEAVE we need to create a mouseout event, so we force the position |
| // of the event to be at (MINSHORT, MINSHORT). |
| PlatformMouseEvent mouseEvent(hWnd, message, wParam, lParam); |
| |
| bool insideThreshold = abs(globalPrevPoint.x() - mouseEvent.pos().x()) < ::GetSystemMetrics(SM_CXDOUBLECLK) |
| && abs(globalPrevPoint.y() - mouseEvent.pos().y()) < ::GetSystemMetrics(SM_CYDOUBLECLK); |
| LONG messageTime = 0; |
| |
| bool handled = false; |
| if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) { |
| // FIXME: I'm not sure if this is the "right" way to do this |
| // but without this call, we never become focused since we don't allow |
| // the default handling of mouse events. |
| SetFocus(m_windowHandle); |
| |
| PlatformMouseEvent moveEvent(hWnd, WM_MOUSEMOVE, 0, lParam, false); |
| moveEvent.setClickCount(0); |
| m_page->mainFrame()->eventHandler()->handleMouseMoveEvent(moveEvent); |
| |
| // Always start capturing events when the mouse goes down in our HWND. |
| SetCapture(m_windowHandle); |
| |
| if (insideThreshold && mouseEvent.button() == globalPrevButton) |
| globalClickCount++; |
| else |
| // Reset the click count. |
| globalClickCount = 1; |
| globalPrevMouseDownTime = messageTime; |
| globalPrevButton = mouseEvent.button(); |
| globalPrevPoint = mouseEvent.pos(); |
| |
| mouseEvent.setClickCount(globalClickCount); |
| handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent); |
| } else if (message == WM_LBUTTONDBLCLK || message == WM_MBUTTONDBLCLK || message == WM_RBUTTONDBLCLK) { |
| globalClickCount++; |
| mouseEvent.setClickCount(globalClickCount); |
| handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent); |
| } else if (message == WM_LBUTTONUP || message == WM_MBUTTONUP || message == WM_RBUTTONUP) { |
| // Record the global position and the button of the up. |
| globalPrevButton = mouseEvent.button(); |
| globalPrevPoint = mouseEvent.pos(); |
| mouseEvent.setClickCount(globalClickCount); |
| m_page->mainFrame()->eventHandler()->handleMouseReleaseEvent(mouseEvent); |
| ReleaseCapture(); |
| } else if (message == WM_MOUSEMOVE) { |
| if (!insideThreshold) |
| globalClickCount = 0; |
| mouseEvent.setClickCount(globalClickCount); |
| handled = m_page->mainFrame()->eventHandler()->mouseMoved(mouseEvent); |
| } |
| |
| return handled; |
| } |
| |
| bool WebView::handleMouseWheel(HWND hWnd, WPARAM wParam, LPARAM lParam, bool isHorizontal) |
| { |
| PlatformWheelEvent wheelEvent(hWnd, wParam, lParam, isHorizontal); |
| return frame()->eventHandler()->handleWheelEvent(wheelEvent); |
| } |
| |
| bool WebView::handleKeyDown(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown) |
| { |
| Frame* frame = m_page->focusController()->focusedOrMainFrame(); |
| |
| PlatformKeyboardEvent keyEvent(m_windowHandle, virtualKeyCode, keyData, PlatformKeyboardEvent::RawKeyDown, systemKeyDown); |
| bool handled = frame->eventHandler()->keyEvent(keyEvent); |
| |
| // These events cannot be canceled, and we have no default handling for them. |
| // FIXME: match IE list more closely, see <http://msdn2.microsoft.com/en-us/library/ms536938.aspx>. |
| if (systemKeyDown && virtualKeyCode != VK_RETURN) |
| return false; |
| |
| if (handled) { |
| MSG msg; |
| if (!systemKeyDown) |
| ::PeekMessage(&msg, m_windowHandle, WM_CHAR, WM_CHAR, PM_REMOVE); |
| return true; |
| } |
| |
| return handled; |
| } |
| |
| bool WebView::handleKeyPress(WPARAM charCode, LPARAM keyData, bool systemKeyDown) |
| { |
| Frame* frame = m_page->focusController()->focusedOrMainFrame(); |
| |
| PlatformKeyboardEvent keyEvent(m_windowHandle, charCode, keyData, PlatformKeyboardEvent::Char, systemKeyDown); |
| // IE does not dispatch keypress event for WM_SYSCHAR. |
| if (systemKeyDown) |
| return frame->eventHandler()->handleAccessKey(keyEvent); |
| if (frame->eventHandler()->keyEvent(keyEvent)) |
| return true; |
| |
| return false; |
| } |
| |
| bool WebView::handleKeyUp(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown) |
| { |
| PlatformKeyboardEvent keyEvent(m_windowHandle, virtualKeyCode, keyData, PlatformKeyboardEvent::KeyUp, systemKeyDown); |
| |
| Frame* frame = m_page->focusController()->focusedOrMainFrame(); |
| return frame->eventHandler()->keyEvent(keyEvent); |
| } |
| |
| LRESULT WebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| { |
| bool handled = false; |
| |
| if (view()) { |
| switch (message) { |
| case WM_PAINT: |
| handled = handlePaint(hWnd); |
| break; |
| |
| case WM_MOUSEMOVE: |
| case WM_LBUTTONDOWN: |
| case WM_MBUTTONDOWN: |
| case WM_RBUTTONDOWN: |
| case WM_LBUTTONDBLCLK: |
| case WM_MBUTTONDBLCLK: |
| case WM_RBUTTONDBLCLK: |
| case WM_LBUTTONUP: |
| case WM_MBUTTONUP: |
| case WM_RBUTTONUP: |
| if (frame()->eventHandler() && view()->didFirstLayout()) |
| handled = handleMouseEvent(hWnd, message, wParam, lParam); |
| break; |
| |
| case WM_MOUSEWHEEL: |
| if (frame()->eventHandler() && view()->didFirstLayout()) |
| handled = handleMouseWheel(hWnd, wParam, lParam, wParam & MK_SHIFT); |
| break; |
| |
| case WM_SYSKEYDOWN: |
| handled = handleKeyDown(wParam, lParam, true); |
| break; |
| |
| case WM_KEYDOWN: |
| handled = handleKeyDown(wParam, lParam, false); |
| break; |
| |
| case WM_SYSKEYUP: |
| handled = handleKeyUp(wParam, lParam, true); |
| break; |
| |
| case WM_KEYUP: |
| handled = handleKeyUp(wParam, lParam, false); |
| break; |
| |
| case WM_SYSCHAR: |
| handled = handleKeyPress(wParam, lParam, true); |
| break; |
| |
| case WM_CHAR: |
| handled = handleKeyPress(wParam, lParam, false); |
| break; |
| |
| case WM_CLOSE: |
| PostMessage(m_parentWindowHandle, WM_CLOSE, wParam, lParam); |
| handled = true; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| if (handled) |
| return 0; |
| |
| return DefWindowProc(hWnd, message, wParam, lParam); |
| } |