Merge "[CherryPick] [EFL][Qt][WK2] Fixed position elements are not always fixed"...
[framework/web/webkit-efl.git] / Source / WebKit2 / UIProcess / WebInspectorProxy.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Portions Copyright (c) 2011 Motorola Mobility, Inc.  All rights reserved.
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 INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "WebInspectorProxy.h"
29
30 #if ENABLE(INSPECTOR)
31
32 #include "WebFramePolicyListenerProxy.h"
33 #include "WebFrameProxy.h"
34 #include "WebInspectorMessages.h"
35 #include "WebPageCreationParameters.h"
36 #include "WebPageGroup.h"
37 #include "WebPageProxy.h"
38 #include "WebPreferences.h"
39 #include "WebProcessProxy.h"
40 #include "WebURLRequest.h"
41
42 #if ENABLE(INSPECTOR_SERVER)
43 #include "WebInspectorServer.h"
44 #endif
45 #if PLATFORM(WIN)
46 #include "WebView.h"
47 #endif
48
49 using namespace WebCore;
50
51 namespace WebKit {
52
53 static PassRefPtr<WebPageGroup> createInspectorPageGroup()
54 {
55     RefPtr<WebPageGroup> pageGroup = WebPageGroup::create("__WebInspectorPageGroup__", false, false);
56
57 #ifndef NDEBUG
58     // Allow developers to inspect the Web Inspector in debug builds.
59     pageGroup->preferences()->setDeveloperExtrasEnabled(true);
60 #endif
61
62     pageGroup->preferences()->setApplicationChromeModeEnabled(true);
63     pageGroup->preferences()->setSuppressesIncrementalRendering(true);
64
65     return pageGroup.release();
66 }
67
68 WebPageGroup* WebInspectorProxy::inspectorPageGroup()
69 {
70     static WebPageGroup* pageGroup = createInspectorPageGroup().leakRef();
71     return pageGroup;
72 }
73
74 WebInspectorProxy::WebInspectorProxy(WebPageProxy* page)
75     : m_page(page)
76     , m_isVisible(false)
77     , m_isAttached(false)
78     , m_isDebuggingJavaScript(false)
79     , m_isProfilingJavaScript(false)
80     , m_isProfilingPage(false)
81 #if PLATFORM(WIN)
82     , m_inspectorWindow(0)
83 #elif PLATFORM(GTK) || PLATFORM(EFL)
84     , m_inspectorView(0)
85     , m_inspectorWindow(0)
86 #endif
87 #if ENABLE(INSPECTOR_SERVER)
88     , m_remoteInspectionPageId(0)
89 #endif
90 {
91 }
92
93 WebInspectorProxy::~WebInspectorProxy()
94 {
95 }
96
97 void WebInspectorProxy::invalidate()
98 {
99 #if ENABLE(INSPECTOR_SERVER)
100     if (m_remoteInspectionPageId)
101         WebInspectorServer::shared().unregisterPage(m_remoteInspectionPageId);
102 #endif
103
104     m_page->close();
105     didClose();
106
107     m_page = 0;
108
109     m_isVisible = false;
110     m_isDebuggingJavaScript = false;
111     m_isProfilingJavaScript = false;
112     m_isProfilingPage = false;
113 }
114
115 // Public APIs
116 bool WebInspectorProxy::isFront()
117 {
118     if (!m_page)
119         return false;
120
121     return platformIsFront();
122 }
123
124 void WebInspectorProxy::show()
125 {
126     if (!m_page)
127         return;
128
129     m_page->process()->send(Messages::WebInspector::Show(), m_page->pageID());
130 }
131
132 void WebInspectorProxy::close()
133 {
134     if (!m_page)
135         return;
136
137     m_page->process()->send(Messages::WebInspector::Close(), m_page->pageID());
138 }
139
140 void WebInspectorProxy::showConsole()
141 {
142     if (!m_page)
143         return;
144
145     m_page->process()->send(Messages::WebInspector::ShowConsole(), m_page->pageID());
146 }
147
148 void WebInspectorProxy::showResources()
149 {
150     if (!m_page)
151         return;
152
153     m_page->process()->send(Messages::WebInspector::ShowResources(), m_page->pageID());
154 }
155
156 void WebInspectorProxy::showMainResourceForFrame(WebFrameProxy* frame)
157 {
158     if (!m_page)
159         return;
160     
161     m_page->process()->send(Messages::WebInspector::ShowMainResourceForFrame(frame->frameID()), m_page->pageID());
162 }
163
164 void WebInspectorProxy::attach()
165 {
166     if (!canAttach())
167         return;
168
169     m_isAttached = true;
170
171     if (m_isVisible)
172         inspectorPageGroup()->preferences()->setInspectorStartsAttached(true);
173
174     platformAttach();
175 }
176
177 void WebInspectorProxy::detach()
178 {
179     m_isAttached = false;
180     
181     if (m_isVisible)
182         inspectorPageGroup()->preferences()->setInspectorStartsAttached(false);
183
184     platformDetach();
185 }
186
187 void WebInspectorProxy::setAttachedWindowHeight(unsigned height)
188 {
189     inspectorPageGroup()->preferences()->setInspectorAttachedHeight(height);
190     platformSetAttachedWindowHeight(height);
191 }
192
193 void WebInspectorProxy::toggleJavaScriptDebugging()
194 {
195     if (!m_page)
196         return;
197
198     if (m_isDebuggingJavaScript)
199         m_page->process()->send(Messages::WebInspector::StopJavaScriptDebugging(), m_page->pageID());
200     else
201         m_page->process()->send(Messages::WebInspector::StartJavaScriptDebugging(), m_page->pageID());
202
203     // FIXME: have the WebProcess notify us on state changes.
204     m_isDebuggingJavaScript = !m_isDebuggingJavaScript;
205 }
206
207 void WebInspectorProxy::toggleJavaScriptProfiling()
208 {
209     if (!m_page)
210         return;
211
212     if (m_isProfilingJavaScript)
213         m_page->process()->send(Messages::WebInspector::StopJavaScriptProfiling(), m_page->pageID());
214     else
215         m_page->process()->send(Messages::WebInspector::StartJavaScriptProfiling(), m_page->pageID());
216
217     // FIXME: have the WebProcess notify us on state changes.
218     m_isProfilingJavaScript = !m_isProfilingJavaScript;
219 }
220
221 void WebInspectorProxy::togglePageProfiling()
222 {
223     if (!m_page)
224         return;
225
226     if (m_isProfilingPage)
227         m_page->process()->send(Messages::WebInspector::StopPageProfiling(), m_page->pageID());
228     else
229         m_page->process()->send(Messages::WebInspector::StartPageProfiling(), m_page->pageID());
230
231     // FIXME: have the WebProcess notify us on state changes.
232     m_isProfilingPage = !m_isProfilingPage;
233 }
234
235 bool WebInspectorProxy::isInspectorPage(WebPageProxy* page)
236 {
237     return page->pageGroup() == inspectorPageGroup();
238 }
239
240 static void decidePolicyForNavigationAction(WKPageRef, WKFrameRef frameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKURLRequestRef requestRef, WKFramePolicyListenerRef listenerRef, WKTypeRef, const void* clientInfo)
241 {
242     // Allow non-main frames to navigate anywhere.
243     if (!toImpl(frameRef)->isMainFrame()) {
244         toImpl(listenerRef)->use();
245         return;
246     }
247
248     const WebInspectorProxy* webInspectorProxy = static_cast<const WebInspectorProxy*>(clientInfo);
249     ASSERT(webInspectorProxy);
250
251     // Use KURL so we can compare just the fileSystemPaths.
252     KURL inspectorURL(KURL(), webInspectorProxy->inspectorPageURL());
253     KURL requestURL(KURL(), toImpl(requestRef)->url());
254
255     ASSERT(inspectorURL.isLocalFile());
256
257     // Allow loading of the main inspector file.
258     if (requestURL.isLocalFile() && requestURL.fileSystemPath() == inspectorURL.fileSystemPath()) {
259         toImpl(listenerRef)->use();
260         return;
261     }
262
263     // Prevent everything else from loading in the inspector's page.
264     toImpl(listenerRef)->ignore();
265
266     // And instead load it in the inspected page.
267     webInspectorProxy->page()->loadURLRequest(toImpl(requestRef));
268 }
269
270 #if ENABLE(INSPECTOR_SERVER)
271 void WebInspectorProxy::enableRemoteInspection()
272 {
273     if (!m_remoteInspectionPageId)
274         m_remoteInspectionPageId = WebInspectorServer::shared().registerPage(this);
275 }
276
277 void WebInspectorProxy::remoteFrontendConnected()
278 {
279     m_page->process()->send(Messages::WebInspector::RemoteFrontendConnected(), m_page->pageID());
280 }
281
282 void WebInspectorProxy::remoteFrontendDisconnected()
283 {
284     m_page->process()->send(Messages::WebInspector::RemoteFrontendDisconnected(), m_page->pageID());
285 }
286
287 void WebInspectorProxy::dispatchMessageFromRemoteFrontend(const String& message)
288 {
289     m_page->process()->send(Messages::WebInspector::DispatchMessageFromRemoteFrontend(message), m_page->pageID());
290 }
291 #endif
292
293 // Called by WebInspectorProxy messages
294 void WebInspectorProxy::createInspectorPage(uint64_t& inspectorPageID, WebPageCreationParameters& inspectorPageParameters)
295 {
296     inspectorPageID = 0;
297
298     if (!m_page)
299         return;
300
301     m_isAttached = shouldOpenAttached();
302
303     WebPageProxy* inspectorPage = platformCreateInspectorPage();
304     ASSERT(inspectorPage);
305     if (!inspectorPage)
306         return;
307
308     inspectorPageID = inspectorPage->pageID();
309     inspectorPageParameters = inspectorPage->creationParameters();
310
311     WKPagePolicyClient policyClient = {
312         kWKPagePolicyClientCurrentVersion,
313         this, /* clientInfo */
314         decidePolicyForNavigationAction,
315         0, /* decidePolicyForNewWindowAction */
316         0, /* decidePolicyForResponse */
317         0 /* unableToImplementPolicy */
318     };
319
320     inspectorPage->initializePolicyClient(&policyClient);
321
322     String url = inspectorPageURL();
323     if (m_isAttached)
324         url += "?docked=true";
325
326     m_page->process()->assumeReadAccessToBaseURL(inspectorBaseURL());
327
328     inspectorPage->loadURL(url);
329 }
330
331 void WebInspectorProxy::didLoadInspectorPage()
332 {
333     m_isVisible = true;
334
335     // platformOpen is responsible for rendering attached mode depending on m_isAttached.
336     platformOpen();
337 }
338
339 void WebInspectorProxy::didClose()
340 {
341     m_isVisible = false;
342     m_isDebuggingJavaScript = false;
343     m_isProfilingJavaScript = false;
344     m_isProfilingPage = false;
345
346     if (m_isAttached) {
347         // Detach here so we only need to have one code path that is responsible for cleaning up the inspector
348         // state.
349         detach();
350     }
351
352     platformDidClose();
353 }
354
355 void WebInspectorProxy::bringToFront()
356 {
357     platformBringToFront();
358 }
359
360 void WebInspectorProxy::inspectedURLChanged(const String& urlString)
361 {
362     platformInspectedURLChanged(urlString);
363 }
364
365 bool WebInspectorProxy::canAttach()
366 {
367     // Keep this in sync with InspectorFrontendClientLocal::canAttachWindow. There are two implementations
368     // to make life easier in the multi-process world we have. WebInspectorProxy uses canAttach to decide if
369     // we can attach on open (on the UI process side). And InspectorFrontendClientLocal::canAttachWindow is
370     // used to decide if we can attach when the attach button is pressed (on the WebProcess side).
371
372     // Don't allow the attach if the window would be too small to accommodate the minimum inspector height.
373     // Also don't allow attaching to another inspector -- two inspectors in one window is too much!
374     bool isInspectorPage = m_page->pageGroup() == inspectorPageGroup();
375     unsigned inspectedPageHeight = platformInspectedWindowHeight();
376     unsigned maximumAttachedHeight = inspectedPageHeight * 3 / 4;
377     return minimumAttachedHeight <= maximumAttachedHeight && !isInspectorPage;
378 }
379
380 bool WebInspectorProxy::shouldOpenAttached()
381 {
382     return inspectorPageGroup()->preferences()->inspectorStartsAttached() && canAttach();
383 }
384
385 #if ENABLE(INSPECTOR_SERVER)
386 void WebInspectorProxy::sendMessageToRemoteFrontend(const String& message)
387 {
388     ASSERT(m_remoteInspectionPageId);
389     WebInspectorServer::shared().sendMessageOverConnection(m_remoteInspectionPageId, message);
390 }
391 #endif
392
393 } // namespace WebKit
394
395 #endif // ENABLE(INSPECTOR)