2006-03-16 Eric Seidel <eseidel@apple.com>
[WebKit-https.git] / WebKitTools / Spinneret / Spinneret / WebView.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "stdafx.h"
27 #include "config.h"
28
29 #include "WebFrame.h"
30
31 #include "WebView.h"
32 #include "KeyEvent.h"
33 #include "Resource.h"
34 #include "FrameView.h"
35 #include "MouseEvent.h"
36 #include "IntRect.h"
37
38 using namespace WebCore;
39
40 namespace WebKit {
41
42 class WebView::WebViewPrivate {
43 public:
44     WebViewPrivate() {}
45     ~WebViewPrivate()
46     {
47         delete mainFrame;
48     }
49
50     WebFrame* mainFrame;
51     HWND windowHandle;
52 };
53
54 const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass";
55
56 LRESULT CALLBACK WebViewWndProc(HWND, UINT, WPARAM, LPARAM);
57
58 static ATOM registerWebViewWithInstance(HINSTANCE hInstance)
59 {
60     static bool haveRegisteredWindowClass = false;
61     if (haveRegisteredWindowClass)
62         return true;
63
64     WNDCLASSEX wcex;
65
66     wcex.cbSize = sizeof(WNDCLASSEX);
67
68     wcex.style          = CS_DBLCLKS;
69     wcex.lpfnWndProc    = WebViewWndProc;
70     wcex.cbClsExtra     = 0;
71     wcex.cbWndExtra     = 4; // 4 bytes for the WebView pointer
72     wcex.hInstance      = hInstance;
73     wcex.hIcon          = 0;
74     wcex.hCursor        = LoadCursor(0, IDC_ARROW);
75     wcex.hbrBackground  = 0;
76     wcex.lpszMenuName   = 0;
77     wcex.lpszClassName  = kWebViewWindowClassName;
78     wcex.hIconSm        = 0;
79
80     return RegisterClassEx(&wcex);
81 }
82
83 // FIXME: This should eventually just use the DLL instance, I think.
84 WebView* WebView::createWebView(HINSTANCE hInstance, HWND parent)
85 {
86     // Save away our instace handle for WebCore to use.
87     Widget::instanceHandle = hInstance;
88
89     registerWebViewWithInstance(hInstance);
90
91     HWND hWnd = CreateWindow(kWebViewWindowClassName, 0, WS_CHILD | WS_HSCROLL | WS_VSCROLL,
92        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, parent, 0, hInstance, 0);
93
94     if (!hWnd)
95         return 0;
96
97     WebView* newWebView = new WebView(hWnd);
98     SetWindowLongPtr(hWnd, 0, (LONG)newWebView);
99     return newWebView;
100 }
101
102 WebView::WebView(HWND hWnd)
103 {
104     d = new WebViewPrivate();
105     d->windowHandle = hWnd;
106     d->mainFrame = new WebFrame("dummy", this);
107     d->mainFrame->loadHTMLString("<p style=\"background-color: #00FF00\">Testing</p><img src=\"http://webkit.opendarwin.org/images/icon-gold.png\" alt=\"Face\"><div style=\"border: solid blue\">div with blue border</div><ul><li>foo<li>bar<li>baz</ul>");
108 }
109
110 WebView::~WebView()
111 {
112     delete d;
113 }
114
115 HWND WebView::windowHandle()
116 {
117     return d->windowHandle;
118 }
119
120 WebFrame* WebView::mainFrame()
121 {
122     return d->mainFrame;
123 }
124
125 void WebView::mouseMoved(WPARAM wParam, LPARAM lParam)
126 {
127     MouseEvent mouseEvent(windowHandle(), wParam, lParam, 0);
128     d->mainFrame->viewImpl()->viewportMouseMoveEvent(&mouseEvent);
129 }
130
131 void WebView::mouseDown(WPARAM wParam, LPARAM lParam)
132 {
133     MouseEvent mouseEvent(windowHandle(), wParam, lParam, 1);
134     d->mainFrame->viewImpl()->viewportMousePressEvent(&mouseEvent);
135 }
136
137 void WebView::mouseUp(WPARAM wParam, LPARAM lParam)
138 {
139     MouseEvent mouseEvent(windowHandle(), wParam, lParam, 1);
140     d->mainFrame->viewImpl()->viewportMouseReleaseEvent(&mouseEvent);
141 }
142
143 void WebView::mouseDoubleClick(WPARAM wParam, LPARAM lParam)
144 {
145     MouseEvent mouseEvent(windowHandle(), wParam, lParam, 2);
146     d->mainFrame->viewImpl()->viewportMouseReleaseEvent(&mouseEvent);
147 }
148
149 bool WebView::keyPress(WPARAM wParam, LPARAM lParam)
150 {
151     KeyEvent keyEvent(windowHandle(), wParam, lParam);
152     return static_cast<FrameWin*>(d->mainFrame->impl())->keyPress(&keyEvent);
153 }
154
155 #define LINE_SCROLL_SIZE 30
156
157 static int calculateScrollDelta(WPARAM wParam, int oldPosition, int pageSize)
158 {
159     switch (LOWORD(wParam)) {
160         case SB_PAGEUP: 
161             return -(pageSize - LINE_SCROLL_SIZE); 
162          case SB_PAGEDOWN: 
163             return (pageSize - LINE_SCROLL_SIZE); 
164         case SB_LINEUP: 
165             return -LINE_SCROLL_SIZE;
166         case SB_LINEDOWN: 
167             return LINE_SCROLL_SIZE;
168         case SB_THUMBPOSITION: 
169             return HIWORD(wParam) - oldPosition; 
170     }
171     return 0;
172 }
173
174 static int scrollMessageForKey(WPARAM keyCode)
175 {
176     switch (keyCode) {
177     case VK_UP:
178         return SB_LINEUP;
179     case VK_PRIOR: 
180         return SB_PAGEUP;
181     case VK_NEXT:
182         return SB_PAGEDOWN;
183     case VK_DOWN:
184         return SB_LINEDOWN;
185     case VK_HOME:
186         return SB_TOP;
187     case VK_END:
188         return SB_BOTTOM;
189     case VK_SPACE:
190         return (GetKeyState(VK_SHIFT) & 0x8000) ? SB_PAGEUP : SB_PAGEDOWN;
191     }
192     return -1;
193 }
194
195 LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
196 {
197     int wmId, wmEvent;
198     WebView* webview = (WebView*)GetWindowLongPtr(hWnd, 0);
199     switch (message)
200     {
201     case WM_PAINT:
202         webview->mainFrame()->paint();
203         break;
204     case WM_DESTROY:
205         // Do nothing?
206         break;
207     case WM_MOUSEMOVE:
208         webview->mouseMoved(wParam, lParam);
209         break;
210     case WM_LBUTTONDOWN:
211         // Make ourselves the focused window before doing anything else
212         // FIXME: I'm not sure if this is the "right" way to do this
213         // but w/o this call, we never become focused since we don't allow
214         // the default handling of mouse events.
215         SetFocus(hWnd);
216     case WM_MBUTTONDOWN:
217     case WM_RBUTTONDOWN:
218         webview->mouseDown(wParam, lParam);
219         break;
220     case WM_LBUTTONUP:
221     case WM_MBUTTONUP:
222     case WM_RBUTTONUP:
223         webview->mouseUp(wParam, lParam);
224         break;
225     case WM_LBUTTONDBLCLK:
226     case WM_MBUTTONDBLCLK:
227     case WM_RBUTTONDBLCLK:
228         webview->mouseDoubleClick(wParam, lParam);
229         break;
230     case WM_HSCROLL: {
231         ScrollView* view = webview->mainFrame()->impl()->view();
232         view->scrollBy(calculateScrollDelta(wParam, view->contentsX(), view->visibleWidth()), 0);
233         webview->mainFrame()->impl()->sendScrollEvent();
234         break;
235     }
236     case WM_VSCROLL: {
237         ScrollView* view = webview->mainFrame()->impl()->view();
238         view->scrollBy(0, calculateScrollDelta(wParam, view->contentsY(), view->visibleHeight()));
239         webview->mainFrame()->impl()->sendScrollEvent();
240         break;
241     }
242     case WM_KEYDOWN: {
243         // FIXME: First we should send key events up through the DOM
244         // to form controls, etc.  If they are not handled, we fall
245         // through to the top level webview and do things like scrolling
246         if (webview->keyPress(wParam, lParam))
247             break;
248
249         WORD wScrollNotify = scrollMessageForKey(wParam);
250         if (wScrollNotify != -1)
251             SendMessage(hWnd, WM_VSCROLL, MAKELONG(wScrollNotify, 0), 0L);
252     }
253     case WM_KEYUP: {
254         webview->keyPress(wParam, lParam);
255         break;
256     }
257     case WM_SIZE:
258         if (!webview)
259             break;
260         webview->mainFrame()->impl()->sendResizeEvent();
261         break;
262     case WM_SETFOCUS:
263         webview->mainFrame()->impl()->setWindowHasFocus(true);
264         webview->mainFrame()->impl()->setDisplaysWithFocusAttributes(true);
265         break;
266     case WM_KILLFOCUS:
267         webview->mainFrame()->impl()->setWindowHasFocus(false);
268         webview->mainFrame()->impl()->setDisplaysWithFocusAttributes(false);
269         break;
270     default:
271         return DefWindowProc(hWnd, message, wParam, lParam);
272     }
273     return 0;
274 }
275
276
277 };