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
54 using namespace WebCore;
55
56 const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass";
57
58
webViewWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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
loadResourceIntoBuffer(const char * name)67 PassRefPtr<SharedBuffer> loadResourceIntoBuffer(const char* name)
68 {
69 notImplemented();
70 return 0;
71 }
72
73
WebView(HWND hwnd,unsigned features)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
~WebView()121 WebView::~WebView()
122 {
123 delete m_page;
124 DestroyWindow(m_windowHandle);
125 }
126
initialize(HINSTANCE instanceHandle)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
cleanup()150 void WebView::cleanup()
151 {
152 UnregisterClass(kWebViewWindowClassName, WebCore::instanceHandle());
153 }
154
createFrame(const KURL & url,const String & name,HTMLFrameOwnerElement * ownerElement,const String & referrer,bool,int,int)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
runJavaScriptAlert(const String & message)181 void WebView::runJavaScriptAlert(const String& message)
182 {
183 notImplemented();
184 }
185
runJavaScriptConfirm(const String & message)186 bool WebView::runJavaScriptConfirm(const String& message)
187 {
188 notImplemented();
189 return false;
190 }
191
runJavaScriptPrompt(const String & message,const String & defaultValue,String & result)192 bool WebView::runJavaScriptPrompt(const String& message, const String& defaultValue, String& result)
193 {
194 notImplemented();
195 return false;
196 }
197
frameRect(RECT * rect) const198 void WebView::frameRect(RECT* rect) const
199 {
200 GetWindowRect(m_windowHandle, rect);
201 }
202
view() const203 FrameView* WebView::view() const
204 {
205 return m_frame ? m_frame->view() : 0;
206 }
207
load(LPCWSTR url)208 void WebView::load(LPCWSTR url)
209 {
210 load(String(url));
211 }
212
load(const String & url)213 void WebView::load(const String &url)
214 {
215 load(WebCore::ResourceRequest(url));
216 }
217
load(const WebCore::ResourceRequest & request)218 void WebView::load(const WebCore::ResourceRequest &request)
219 {
220 frame()->loader()->load(request, false);
221 }
222
reload()223 void WebView::reload()
224 {
225 frame()->loader()->reload();
226 }
227
stop()228 void WebView::stop()
229 {
230 frame()->loader()->stopAllLoaders();
231 }
232
paint(HDC hDC,const IntRect & clipRect)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
handlePaint(HWND hWnd)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
handleMouseEvent(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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
handleMouseWheel(HWND hWnd,WPARAM wParam,LPARAM lParam,bool isHorizontal)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
handleKeyDown(WPARAM virtualKeyCode,LPARAM keyData,bool systemKeyDown)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
handleKeyPress(WPARAM charCode,LPARAM keyData,bool systemKeyDown)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
handleKeyUp(WPARAM virtualKeyCode,LPARAM keyData,bool systemKeyDown)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
wndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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