0ace2a23b09a80a2245ba7cc544dfdbc1c49c988
[WebKit.git] / WebKit2 / WebProcess / WebPage / WebPage.cpp
1 /*
2  * Copyright (C) 2010 Apple 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 INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "WebPage.h"
27
28 #include "Arguments.h"
29 #include "DrawingArea.h"
30 #include "InjectedBundle.h"
31 #include "MessageID.h"
32 #include "WebBackForwardControllerClient.h"
33 #include "WebBackForwardListProxy.h"
34 #include "WebChromeClient.h"
35 #include "WebContextMenuClient.h"
36 #include "WebCoreArgumentCoders.h"
37 #include "WebDragClient.h"
38 #include "WebEditorClient.h"
39 #include "WebEvent.h"
40 #include "WebEventConversion.h"
41 #include "WebFrame.h"
42 #include "WebInspectorClient.h"
43 #include "WebPageMessageKinds.h"
44 #include "WebPageProxyMessageKinds.h"
45 #include "WebPreferencesStore.h"
46 #include "WebProcess.h"
47 #include <WebCore/BackForwardList.h>
48 #include <WebCore/EventHandler.h>
49 #include <WebCore/FocusController.h>
50 #include <WebCore/Frame.h>
51 #include <WebCore/FrameLoaderTypes.h>
52 #include <WebCore/FrameView.h>
53 #include <WebCore/HistoryItem.h>
54 #include <WebCore/KeyboardEvent.h>
55 #include <WebCore/Page.h>
56 #include <WebCore/PlatformKeyboardEvent.h>
57 #include <WebCore/RenderTreeAsText.h>
58 #include <WebCore/ResourceRequest.h>
59 #include <WebCore/Settings.h>
60 #include <runtime/JSLock.h>
61 #include <runtime/JSValue.h>
62
63 #ifndef NDEBUG
64 #include <wtf/RefCountedLeakCounter.h>
65 #endif
66
67 using namespace JSC;
68 using namespace WebCore;
69
70 namespace WebKit {
71
72 #ifndef NDEBUG
73 static WTF::RefCountedLeakCounter webPageCounter("WebPage");
74 #endif
75
76 PassRefPtr<WebPage> WebPage::create(uint64_t pageID, const IntSize& viewSize, const WebPreferencesStore& store, DrawingArea::Type drawingAreaType)
77 {
78     return adoptRef(new WebPage(pageID, viewSize, store, drawingAreaType));
79 }
80
81 WebPage::WebPage(uint64_t pageID, const IntSize& viewSize, const WebPreferencesStore& store, DrawingArea::Type drawingAreaType)
82     : m_page(new Page(new WebChromeClient(this), new WebContextMenuClient(this), new WebEditorClient(this), new WebDragClient(this), new WebInspectorClient(this), 0, 0, 0, new WebBackForwardControllerClient(this)))
83     , m_viewSize(viewSize)
84     , m_drawingArea(DrawingArea::create(drawingAreaType, this))
85     , m_pageID(pageID)
86 {
87     ASSERT(m_pageID);
88
89     m_page->settings()->setJavaScriptEnabled(store.javaScriptEnabled);
90     m_page->settings()->setLoadsImagesAutomatically(store.loadsImagesAutomatically);
91     m_page->settings()->setPluginsEnabled(store.pluginsEnabled);
92     m_page->settings()->setMinimumFontSize(store.minimumFontSize);
93     m_page->settings()->setMinimumLogicalFontSize(store.minimumLogicalFontSize);
94     m_page->settings()->setDefaultFontSize(store.defaultFontSize);
95     m_page->settings()->setDefaultFixedFontSize(store.defaultFixedFontSize);
96     m_page->settings()->setStandardFontFamily(store.standardFontFamily);
97     m_page->settings()->setCursiveFontFamily(store.cursiveFontFamily);
98     m_page->settings()->setFantasyFontFamily(store.fantasyFontFamily);
99     m_page->settings()->setFixedFontFamily(store.fixedFontFamily);
100     m_page->settings()->setSansSerifFontFamily(store.sansSerifFontFamily);
101     m_page->settings()->setSerifFontFamily(store.serifFontFamily);
102
103     platformInitialize();
104
105     m_mainFrame = WebFrame::createMainFrame(this);
106     WebProcess::shared().connection()->send(WebPageProxyMessage::DidCreateMainFrame, m_pageID, CoreIPC::In(m_mainFrame->frameID()));
107
108     if (WebProcess::shared().injectedBundle())
109         WebProcess::shared().injectedBundle()->didCreatePage(this);
110
111 #ifndef NDEBUG
112     webPageCounter.increment();
113 #endif
114 }
115
116 WebPage::~WebPage()
117 {
118     ASSERT(!m_page);
119 #ifndef NDEBUG
120     webPageCounter.decrement();
121 #endif
122 }
123
124 void WebPage::initializeInjectedBundleLoaderClient(WKBundlePageLoaderClient* client)
125 {
126     m_loaderClient.initialize(client);
127 }
128
129 void WebPage::initializeInjectedBundleUIClient(WKBundlePageUIClient* client)
130 {
131     m_uiClient.initialize(client);
132 }
133
134 String WebPage::renderTreeExternalRepresentation() const
135 {
136     return externalRepresentation(m_mainFrame->coreFrame(), RenderAsTextBehaviorNormal);
137 }
138
139 WebFrame* WebPage::webFrame(uint64_t frameID) const
140 {
141     return m_frameMap.get(frameID);
142 }
143
144 void WebPage::addWebFrame(uint64_t frameID, WebFrame* frame)
145 {
146     m_frameMap.set(frameID, frame);
147 }
148
149 void WebPage::removeWebFrame(uint64_t frameID)
150 {
151     m_frameMap.remove(frameID);
152 }
153
154 void WebPage::close()
155 {
156     if (WebProcess::shared().injectedBundle())
157         WebProcess::shared().injectedBundle()->willDestroyPage(this);
158
159     m_mainFrame->coreFrame()->loader()->detachFromParent();
160
161     delete m_page;
162     m_page = 0;
163
164     WebProcess::shared().removeWebPage(m_pageID);
165 }
166
167 void WebPage::tryClose()
168 {
169     if (!m_mainFrame->coreFrame()->loader()->shouldClose())
170         return;
171
172     WebProcess::shared().connection()->send(WebPageProxyMessage::ClosePage, m_pageID, CoreIPC::In());
173 }
174
175 void WebPage::loadURL(const String& url)
176 {
177     m_mainFrame->coreFrame()->loader()->load(ResourceRequest(KURL(KURL(), url)), false);
178 }
179
180 void WebPage::stopLoading()
181 {
182     m_mainFrame->coreFrame()->loader()->stopForUserCancel();
183 }
184
185 void WebPage::reload(bool reloadFromOrigin)
186 {
187     m_mainFrame->coreFrame()->loader()->reload(reloadFromOrigin);
188 }
189
190 void WebPage::goForward(uint64_t backForwardItemID)
191 {
192     HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID);
193     m_page->goToItem(item, FrameLoadTypeForward);
194 }
195
196 void WebPage::goBack(uint64_t backForwardItemID)
197 {
198     HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID);
199     m_page->goToItem(item, FrameLoadTypeBack);
200 }
201
202 void WebPage::goToBackForwardItem(uint64_t backForwardItemID)
203 {
204     HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID);
205     m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
206 }
207
208 void WebPage::layoutIfNeeded()
209 {
210     if (m_mainFrame->coreFrame()->view())
211         m_mainFrame->coreFrame()->view()->layoutIfNeededRecursive();
212 }
213
214 void WebPage::setSize(const WebCore::IntSize& viewSize)
215 {
216     if (m_viewSize == viewSize)
217         return;
218
219     Frame* frame = m_page->mainFrame();
220     
221     frame->view()->resize(viewSize);
222     frame->view()->setNeedsLayout();
223     m_drawingArea->setNeedsDisplay(IntRect(IntPoint(0, 0), viewSize));
224     
225     m_viewSize = viewSize;
226 }
227
228 void WebPage::drawRect(GraphicsContext& graphicsContext, const IntRect& rect)
229 {
230     graphicsContext.save();
231     graphicsContext.clip(rect);
232     m_mainFrame->coreFrame()->view()->paint(&graphicsContext, rect);
233     graphicsContext.restore();
234 }
235
236 // Events 
237
238 void WebPage::mouseEvent(const PlatformMouseEvent& event)
239 {
240     if (!m_mainFrame->coreFrame()->view())
241         return;
242
243     switch (event.eventType()) {
244         case WebCore::MouseEventPressed:
245             m_mainFrame->coreFrame()->eventHandler()->handleMousePressEvent(event);
246             break;
247         case WebCore::MouseEventReleased:
248             m_mainFrame->coreFrame()->eventHandler()->handleMouseReleaseEvent(event);
249             break;
250         case WebCore::MouseEventMoved:
251             m_mainFrame->coreFrame()->eventHandler()->mouseMoved(event);
252             break;
253         default:
254             ASSERT_NOT_REACHED();
255             break;
256     }
257 }
258
259 void WebPage::wheelEvent(PlatformWheelEvent& event)
260 {
261     if (!m_mainFrame->coreFrame()->view())
262         return;
263
264     m_mainFrame->coreFrame()->eventHandler()->handleWheelEvent(event);
265 }
266
267 void WebPage::keyEvent(const PlatformKeyboardEvent& event)
268 {
269     if (!m_mainFrame->coreFrame()->view())
270         return;
271
272     m_page->focusController()->focusedOrMainFrame()->eventHandler()->keyEvent(event);
273 }
274
275 void WebPage::setActive(bool isActive)
276 {
277     m_page->focusController()->setActive(isActive);
278 }
279
280 void WebPage::setFocused(bool isFocused)
281 {
282     m_page->focusController()->setFocused(isFocused);
283 }
284
285 void WebPage::setIsInWindow(bool isInWindow)
286 {
287     if (!isInWindow) {
288         m_page->setCanStartMedia(false);
289         m_page->willMoveOffscreen();
290     } else {
291         m_page->setCanStartMedia(true);
292         m_page->didMoveOnscreen();
293     }
294 }
295
296 void WebPage::didReceivePolicyDecision(WebFrame* frame, uint64_t listenerID, WebCore::PolicyAction policyAction)
297 {
298     if (!frame)
299         return;
300     frame->didReceivePolicyDecision(listenerID, policyAction);
301 }
302
303 void WebPage::show()
304 {
305     WebProcess::shared().connection()->send(WebPageProxyMessage::ShowPage, m_pageID, CoreIPC::In());
306 }
307
308 void WebPage::runJavaScriptInMainFrame(const WebCore::String& script, uint64_t callbackID)
309 {
310     // NOTE: We need to be careful when running scripts that the objects we depend on don't
311     // disappear during script execution.
312
313     JSLock lock(SilenceAssertionsOnly);
314     JSValue resultValue = m_mainFrame->coreFrame()->script()->executeScript(script, true).jsValue();
315     String resultString = ustringToString(resultValue.toString(m_mainFrame->coreFrame()->script()->globalObject(mainThreadNormalWorld())->globalExec()));
316
317     WebProcess::shared().connection()->send(WebPageProxyMessage::DidRunJavaScriptInMainFrame, m_pageID, CoreIPC::In(resultString, callbackID));
318 }
319
320 void WebPage::getRenderTreeExternalRepresentation(uint64_t callbackID)
321 {
322     String resultString = renderTreeExternalRepresentation();
323     WebProcess::shared().connection()->send(WebPageProxyMessage::DidGetRenderTreeExternalRepresentation, m_pageID, CoreIPC::In(resultString, callbackID));
324 }
325
326 void WebPage::preferencesDidChange(const WebPreferencesStore& store)
327 {
328     m_page->settings()->setJavaScriptEnabled(store.javaScriptEnabled);
329     m_page->settings()->setLoadsImagesAutomatically(store.loadsImagesAutomatically);
330 }
331
332 bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* evt)
333 {
334     Node* node = evt->target()->toNode();
335     ASSERT(node);
336     Frame* frame = node->document()->frame();
337     ASSERT(frame);
338
339     const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
340     if (!keyEvent)
341         return false;
342
343     Editor::Command command = frame->editor()->command(interpretKeyEvent(evt));
344
345     if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
346         // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
347         // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
348         // (e.g. Tab that inserts a Tab character, or Enter).
349         return !command.isTextInsertion() && command.execute(evt);
350     }
351
352      if (command.execute(evt))
353         return true;
354
355     // Don't insert null or control characters as they can result in unexpected behaviour
356     if (evt->charCode() < ' ')
357         return false;
358
359     return frame->editor()->insertText(evt->keyEvent()->text(), evt);
360 }
361
362 void WebPage::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder& arguments)
363 {
364     if (messageID.is<CoreIPC::MessageClassDrawingArea>()) {
365         ASSERT(m_drawingArea);
366         m_drawingArea->didReceiveMessage(connection, messageID, arguments);
367         return;
368     }
369
370     switch (messageID.get<WebPageMessage::Kind>()) {
371         case WebPageMessage::SetActive: {
372             bool active;
373             if (!arguments.decode(active))
374                 return;
375          
376             setActive(active);
377             break;
378         }
379         case WebPageMessage::SetFocused: {
380             bool focused;
381             if (!arguments.decode(focused))
382                 return;
383             
384             setFocused(focused);
385             break;
386         }
387         case WebPageMessage::SetIsInWindow: {
388             bool isInWindow;
389             if (!arguments.decode(isInWindow))
390                 return;
391             
392             setIsInWindow(isInWindow);
393             break;
394         }
395         case WebPageMessage::MouseEvent: {
396             WebMouseEvent event;
397             if (!arguments.decode(event))
398                 return;
399             connection->send(WebPageProxyMessage::DidReceiveEvent, m_pageID, CoreIPC::In((uint32_t)event.type()));
400             PlatformMouseEvent platformEvent = platform(event);
401             mouseEvent(platformEvent);
402             break;
403         }
404         case WebPageMessage::WheelEvent: {
405             WebWheelEvent event;
406             if (!arguments.decode(event))
407                 return;
408             connection->send(WebPageProxyMessage::DidReceiveEvent, m_pageID, CoreIPC::In((uint32_t)event.type()));
409             PlatformWheelEvent platformEvent = platform(event);
410             wheelEvent(platformEvent);
411             break;
412         }
413         case WebPageMessage::KeyEvent: {
414             WebKeyboardEvent event;
415             if (!arguments.decode(event))
416                 return;
417             connection->send(WebPageProxyMessage::DidReceiveEvent, m_pageID, CoreIPC::In((uint32_t)event.type()));
418             PlatformKeyboardEvent platformEvent = platform(event);
419             keyEvent(platformEvent);
420             break;
421         }
422         case WebPageMessage::LoadURL: {
423             String url;
424             if (!arguments.decode(url))
425                 return;
426             
427             loadURL(url);
428             break;
429         }
430         case WebPageMessage::StopLoading:
431             stopLoading();
432             break;
433         case WebPageMessage::Reload: {
434             bool reloadFromOrigin;
435             if (!arguments.decode(CoreIPC::Out(reloadFromOrigin)))
436                 return;
437
438             reload(reloadFromOrigin);
439             break;
440         }
441         case WebPageMessage::GoForward: {
442             uint64_t backForwardItemID;
443             if (!arguments.decode(CoreIPC::Out(backForwardItemID)))
444                 return;
445             goForward(backForwardItemID);
446             break;
447         }
448         case WebPageMessage::GoBack: {
449             uint64_t backForwardItemID;
450             if (!arguments.decode(CoreIPC::Out(backForwardItemID)))
451                 return;
452             goBack(backForwardItemID);
453             break;
454         }
455        case WebPageMessage::GoToBackForwardItem: {
456             uint64_t backForwardItemID;
457             if (!arguments.decode(CoreIPC::Out(backForwardItemID)))
458                 return;
459             goToBackForwardItem(backForwardItemID);
460             break;
461         }
462         case WebPageMessage::DidReceivePolicyDecision: {
463             uint64_t frameID;
464             uint64_t listenerID;
465             uint32_t policyAction;
466             if (!arguments.decode(CoreIPC::Out(frameID, listenerID, policyAction)))
467                 return;
468             didReceivePolicyDecision(webFrame(frameID), listenerID, (WebCore::PolicyAction)policyAction);
469             break;
470         }
471         case WebPageMessage::RunJavaScriptInMainFrame: {
472             String script;
473             uint64_t callbackID;
474             if (!arguments.decode(CoreIPC::Out(script, callbackID)))
475                 return;
476             runJavaScriptInMainFrame(script, callbackID);
477             break;
478         }
479         case WebPageMessage::GetRenderTreeExternalRepresentation: {
480             uint64_t callbackID;
481             if (!arguments.decode(callbackID))
482                 return;
483             getRenderTreeExternalRepresentation(callbackID);
484             break;
485         }
486         case WebPageMessage::Close: {
487             close();
488             break;
489         }
490         case WebPageMessage::TryClose: {
491             tryClose();
492             break;
493         }
494         default:
495             ASSERT_NOT_REACHED();
496             break;
497     }
498 }
499
500 } // namespace WebKit