Implement live scrolling on Win32.
[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 "Document.h"
32 #include "FrameView.h"
33 #include "IntRect.h"
34 #include "PlatformKeyboardEvent.h"
35 #include "PlatformMouseEvent.h"
36 #include "Resource.h"
37 #include "SelectionController.h"
38 #include "TypingCommand.h"
39 #include "WebView.h"
40
41 using namespace WebCore;
42
43 namespace WebKit {
44
45 class WebView::WebViewPrivate {
46 public:
47     WebViewPrivate() {}
48     ~WebViewPrivate()
49     {
50         delete mainFrame;
51     }
52
53     WebFrame* mainFrame;
54     HWND windowHandle;
55 };
56
57 const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass";
58
59 LRESULT CALLBACK WebViewWndProc(HWND, UINT, WPARAM, LPARAM);
60
61 static ATOM registerWebViewWithInstance(HINSTANCE hInstance)
62 {
63     static bool haveRegisteredWindowClass = false;
64     if (haveRegisteredWindowClass)
65         return true;
66
67     WNDCLASSEX wcex;
68
69     wcex.cbSize = sizeof(WNDCLASSEX);
70
71     wcex.style          = CS_DBLCLKS;
72     wcex.lpfnWndProc    = WebViewWndProc;
73     wcex.cbClsExtra     = 0;
74     wcex.cbWndExtra     = 4; // 4 bytes for the WebView pointer
75     wcex.hInstance      = hInstance;
76     wcex.hIcon          = 0;
77     wcex.hCursor        = LoadCursor(0, IDC_ARROW);
78     wcex.hbrBackground  = 0;
79     wcex.lpszMenuName   = 0;
80     wcex.lpszClassName  = kWebViewWindowClassName;
81     wcex.hIconSm        = 0;
82
83     return RegisterClassEx(&wcex);
84 }
85
86 // FIXME: This should eventually just use the DLL instance, I think.
87 WebView* WebView::createWebView(HINSTANCE hInstance, HWND parent)
88 {
89     // Save away our instace handle for WebCore to use.
90     Widget::instanceHandle = hInstance;
91
92     registerWebViewWithInstance(hInstance);
93
94     HWND hWnd = CreateWindow(kWebViewWindowClassName, 0, WS_CHILD | WS_HSCROLL | WS_VSCROLL,
95        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, parent, 0, hInstance, 0);
96
97     if (!hWnd)
98         return 0;
99
100     WebView* newWebView = new WebView(hWnd);
101     SetWindowLongPtr(hWnd, 0, (LONG)newWebView);
102     return newWebView;
103 }
104
105 WebView::WebView(HWND hWnd)
106 {
107     d = new WebViewPrivate();
108     d->windowHandle = hWnd;
109     d->mainFrame = new WebFrame("dummy", this);
110     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\" contenteditable=\"true\">div with blue border</div><ul><li>foo<li>bar<li>baz</ul>");
111 }
112
113 WebView::~WebView()
114 {
115     delete d;
116 }
117
118 HWND WebView::windowHandle()
119 {
120     return d->windowHandle;
121 }
122
123 WebFrame* WebView::mainFrame()
124 {
125     return d->mainFrame;
126 }
127
128 void WebView::mouseMoved(WPARAM wParam, LPARAM lParam)
129 {
130     PlatformMouseEvent mouseEvent(windowHandle(), wParam, lParam, 0);
131     d->mainFrame->viewImpl()->handleMouseMoveEvent(mouseEvent);
132 }
133
134 void WebView::mouseDown(WPARAM wParam, LPARAM lParam)
135 {
136     PlatformMouseEvent mouseEvent(windowHandle(), wParam, lParam, 1);
137     d->mainFrame->viewImpl()->handleMousePressEvent(mouseEvent);
138 }
139
140 void WebView::mouseUp(WPARAM wParam, LPARAM lParam)
141 {
142     PlatformMouseEvent mouseEvent(windowHandle(), wParam, lParam, 1);
143     d->mainFrame->viewImpl()->handleMouseReleaseEvent(mouseEvent);
144 }
145
146 void WebView::mouseDoubleClick(WPARAM wParam, LPARAM lParam)
147 {
148     PlatformMouseEvent mouseEvent(windowHandle(), wParam, lParam, 2);
149     d->mainFrame->viewImpl()->handleMouseReleaseEvent(mouseEvent);
150 }
151
152 bool WebView::keyPress(WPARAM wParam, LPARAM lParam)
153 {
154     PlatformKeyboardEvent keyEvent(windowHandle(), wParam, lParam);
155
156     FrameWin* frame = static_cast<FrameWin*>(d->mainFrame->impl());
157     bool handled = frame->keyPress(keyEvent);
158     if (!handled && !keyEvent.isKeyUp()) {
159         Node* start = frame->selection().start().node();
160         if (start && start->isContentEditable()) {
161             switch(keyEvent.WindowsKeyCode()) {
162             case VK_BACK:
163                 TypingCommand::deleteKeyPressed(frame->document());
164                 break;
165             case VK_DELETE:
166                 TypingCommand::forwardDeleteKeyPressed(frame->document());
167                 break;
168             case VK_LEFT:
169                 frame->selection().modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity);
170                 break;
171             case VK_RIGHT:
172                 frame->selection().modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity);
173                 break;
174             case VK_UP:
175                 frame->selection().modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphGranularity);
176                 break;
177             case VK_DOWN:
178                 frame->selection().modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphGranularity);
179                 break;
180             default:
181                 TypingCommand::insertText(frame->document(), keyEvent.text(), false);
182             }
183             handled = true;
184         }
185     }
186     return handled;
187 }
188
189 #define LINE_SCROLL_SIZE 30
190
191 static int calculateScrollDelta(WPARAM wParam, int oldPosition, int pageSize)
192 {
193     switch (LOWORD(wParam)) {
194         case SB_PAGEUP: 
195             return -(pageSize - LINE_SCROLL_SIZE); 
196          case SB_PAGEDOWN: 
197             return (pageSize - LINE_SCROLL_SIZE); 
198         case SB_LINEUP: 
199             return -LINE_SCROLL_SIZE;
200         case SB_LINEDOWN: 
201             return LINE_SCROLL_SIZE;
202         case SB_THUMBPOSITION: 
203         case SB_THUMBTRACK:
204             return HIWORD(wParam) - oldPosition; 
205     }
206     return 0;
207 }
208
209 static int scrollMessageForKey(WPARAM keyCode)
210 {
211     switch (keyCode) {
212     case VK_UP:
213         return SB_LINEUP;
214     case VK_PRIOR: 
215         return SB_PAGEUP;
216     case VK_NEXT:
217         return SB_PAGEDOWN;
218     case VK_DOWN:
219         return SB_LINEDOWN;
220     case VK_HOME:
221         return SB_TOP;
222     case VK_END:
223         return SB_BOTTOM;
224     case VK_SPACE:
225         return (GetKeyState(VK_SHIFT) & 0x8000) ? SB_PAGEUP : SB_PAGEDOWN;
226     }
227     return -1;
228 }
229
230 LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
231 {
232     int wmId, wmEvent;
233     WebView* webview = (WebView*)GetWindowLongPtr(hWnd, 0);
234     switch (message)
235     {
236     case WM_PAINT:
237         webview->mainFrame()->paint();
238         break;
239     case WM_DESTROY:
240         // Do nothing?
241         break;
242     case WM_MOUSEMOVE:
243         webview->mouseMoved(wParam, lParam);
244         break;
245     case WM_LBUTTONDOWN:
246         // Make ourselves the focused window before doing anything else
247         // FIXME: I'm not sure if this is the "right" way to do this
248         // but w/o this call, we never become focused since we don't allow
249         // the default handling of mouse events.
250         SetFocus(hWnd);
251     case WM_MBUTTONDOWN:
252     case WM_RBUTTONDOWN:
253         webview->mouseDown(wParam, lParam);
254         break;
255     case WM_LBUTTONUP:
256     case WM_MBUTTONUP:
257     case WM_RBUTTONUP:
258         webview->mouseUp(wParam, lParam);
259         break;
260     case WM_LBUTTONDBLCLK:
261     case WM_MBUTTONDBLCLK:
262     case WM_RBUTTONDBLCLK:
263         webview->mouseDoubleClick(wParam, lParam);
264         break;
265     case WM_HSCROLL: {
266         ScrollView* view = webview->mainFrame()->viewImpl();
267         view->scrollBy(calculateScrollDelta(wParam, view->contentsX(), view->visibleWidth()), 0);
268         webview->mainFrame()->impl()->sendScrollEvent();
269         break;
270     }
271     case WM_VSCROLL: {
272         ScrollView* view = webview->mainFrame()->viewImpl();
273         view->scrollBy(0, calculateScrollDelta(wParam, view->contentsY(), view->visibleHeight()));
274         webview->mainFrame()->impl()->sendScrollEvent();
275         break;
276     }
277     case WM_KEYDOWN: {
278         // FIXME: First we should send key events up through the DOM
279         // to form controls, etc.  If they are not handled, we fall
280         // through to the top level webview and do things like scrolling
281         if (webview->keyPress(wParam, lParam))
282             break;
283
284         WORD wScrollNotify = scrollMessageForKey(wParam);
285         if (wScrollNotify != -1)
286             SendMessage(hWnd, WM_VSCROLL, MAKELONG(wScrollNotify, 0), 0L);
287     }
288     case WM_KEYUP: {
289         webview->keyPress(wParam, lParam);
290         break;
291     }
292     case WM_SIZE:
293         if (!webview)
294             break;
295         webview->mainFrame()->impl()->sendResizeEvent();
296         break;
297     case WM_SETFOCUS:
298         webview->mainFrame()->impl()->setWindowHasFocus(true);
299         webview->mainFrame()->impl()->setDisplaysWithFocusAttributes(true);
300         break;
301     case WM_KILLFOCUS:
302         webview->mainFrame()->impl()->setWindowHasFocus(false);
303         webview->mainFrame()->impl()->setDisplaysWithFocusAttributes(false);
304         break;
305     default:
306         return DefWindowProc(hWnd, message, wParam, lParam);
307     }
308     return 0;
309 }
310
311
312 };