Home | History | Annotate | Download | only in wince
      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