[WTF] Rename String::format to String::deprecatedFormat
[WebKit-https.git] / Source / WebKit / UIProcess / gtk / WebInspectorProxyGtk.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4  * Copyright (C) 2012 Igalia S.L.
5  * Copyright (C) 2013 Gustavo Noronha Silva <gns@gnome.org>.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "WebInspectorProxy.h"
31
32 #include "APINavigation.h"
33 #include "APINavigationAction.h"
34 #include "WKArray.h"
35 #include "WKContextMenuItem.h"
36 #include "WKMutableArray.h"
37 #include "WebFramePolicyListenerProxy.h"
38 #include "WebInspectorProxyClient.h"
39 #include "WebKitInspectorWindow.h"
40 #include "WebKitWebViewBasePrivate.h"
41 #include "WebPageGroup.h"
42 #include "WebProcessPool.h"
43 #include "WebProcessProxy.h"
44 #include <WebCore/FileSystem.h>
45 #include <WebCore/GtkUtilities.h>
46 #include <WebCore/NotImplemented.h>
47 #include <wtf/text/CString.h>
48 #include <wtf/text/WTFString.h>
49
50 namespace WebKit {
51
52 static void inspectorViewDestroyed(GtkWidget*, gpointer userData)
53 {
54     WebInspectorProxy* inspectorProxy = static_cast<WebInspectorProxy*>(userData);
55
56     // Inform WebProcess about webinspector closure. Not doing so,
57     // results in failure of subsequent invocation of webinspector.
58     inspectorProxy->close();
59 }
60
61 void WebInspectorProxy::setClient(std::unique_ptr<WebInspectorProxyClient>&& client)
62 {
63     m_client = WTFMove(client);
64 }
65
66 void WebInspectorProxy::updateInspectorWindowTitle() const
67 {
68     ASSERT(m_inspectorWindow);
69     webkitInspectorWindowSetSubtitle(WEBKIT_INSPECTOR_WINDOW(m_inspectorWindow), !m_inspectedURLString.isEmpty() ? m_inspectedURLString.utf8().data() : nullptr);
70 }
71
72 static unsigned long long exceededDatabaseQuota(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKStringRef, WKStringRef, unsigned long long, unsigned long long, unsigned long long currentDatabaseUsage, unsigned long long expectedUsage, const void*)
73 {
74     return std::max<unsigned long long>(expectedUsage, currentDatabaseUsage * 1.25);
75 }
76
77 static void webProcessDidCrash(WKPageRef, const void* clientInfo)
78 {
79     WebInspectorProxy* webInspectorProxy = static_cast<WebInspectorProxy*>(const_cast<void*>(clientInfo));
80     ASSERT(webInspectorProxy);
81     webInspectorProxy->closeForCrash();
82 }
83
84 static void decidePolicyForNavigationAction(WKPageRef pageRef, WKNavigationActionRef navigationActionRef, WKFramePolicyListenerRef listenerRef, WKTypeRef, const void* clientInfo)
85 {
86     // Allow non-main frames to navigate anywhere.
87     API::FrameInfo* sourceFrame = toImpl(navigationActionRef)->sourceFrame();
88     if (sourceFrame && !sourceFrame->isMainFrame()) {
89         toImpl(listenerRef)->use({ });
90         return;
91     }
92
93     const WebInspectorProxy* webInspectorProxy = static_cast<const WebInspectorProxy*>(clientInfo);
94     ASSERT(webInspectorProxy);
95
96     WebCore::ResourceRequest request = toImpl(navigationActionRef)->request();
97
98     // Allow loading of the main inspector file.
99     if (WebInspectorProxy::isMainOrTestInspectorPage(request.url())) {
100         toImpl(listenerRef)->use({ });
101         return;
102     }
103
104     // Prevent everything else from loading in the inspector's page.
105     toImpl(listenerRef)->ignore();
106
107     // And instead load it in the inspected page.
108     webInspectorProxy->inspectedPage()->loadRequest(WTFMove(request));
109 }
110
111 static void getContextMenuFromProposedMenu(WKPageRef pageRef, WKArrayRef proposedMenuRef, WKArrayRef* newMenuRef, WKHitTestResultRef, WKTypeRef, const void*)
112 {
113     WKMutableArrayRef menuItems = WKMutableArrayCreate();
114
115     size_t count = WKArrayGetSize(proposedMenuRef);
116     for (size_t i = 0; i < count; ++i) {
117         WKContextMenuItemRef contextMenuItem = static_cast<WKContextMenuItemRef>(WKArrayGetItemAtIndex(proposedMenuRef, i));
118         switch (WKContextMenuItemGetTag(contextMenuItem)) {
119         case kWKContextMenuItemTagOpenLinkInNewWindow:
120         case kWKContextMenuItemTagOpenImageInNewWindow:
121         case kWKContextMenuItemTagOpenFrameInNewWindow:
122         case kWKContextMenuItemTagOpenMediaInNewWindow:
123         case kWKContextMenuItemTagDownloadLinkToDisk:
124         case kWKContextMenuItemTagDownloadImageToDisk:
125             break;
126         default:
127             WKArrayAppendItem(menuItems, contextMenuItem);
128             break;
129         }
130     }
131
132     *newMenuRef = menuItems;
133 }
134
135 WebPageProxy* WebInspectorProxy::platformCreateFrontendPage()
136 {
137     ASSERT(inspectedPage());
138     ASSERT(!m_inspectorView);
139
140     RefPtr<WebPreferences> preferences = WebPreferences::create(String(), "WebKit2.", "WebKit2.");
141 #if ENABLE(DEVELOPER_MODE)
142     // Allow developers to inspect the Web Inspector in debug builds without changing settings.
143     preferences->setDeveloperExtrasEnabled(true);
144     preferences->setLogsPageMessagesToSystemConsoleEnabled(true);
145 #endif
146     preferences->setJavaScriptRuntimeFlags({
147     });
148     RefPtr<WebPageGroup> pageGroup = WebPageGroup::create(inspectorPageGroupIdentifierForPage(inspectedPage()), false, false);
149
150     auto pageConfiguration = API::PageConfiguration::create();
151     pageConfiguration->setProcessPool(&inspectorProcessPool(inspectionLevel()));
152     pageConfiguration->setPreferences(preferences.get());
153     pageConfiguration->setPageGroup(pageGroup.get());
154     m_inspectorView = GTK_WIDGET(webkitWebViewBaseCreate(*pageConfiguration.ptr()));
155     g_object_add_weak_pointer(G_OBJECT(m_inspectorView), reinterpret_cast<void**>(&m_inspectorView));
156     g_signal_connect(m_inspectorView, "destroy", G_CALLBACK(inspectorViewDestroyed), this);
157
158     WKPageUIClientV2 uiClient = {
159         { 2, this },
160         nullptr, // createNewPage_deprecatedForUseWithV0
161         nullptr, // showPage
162         nullptr, // closePage
163         nullptr, // takeFocus
164         nullptr, // focus
165         nullptr, // unfocus
166         nullptr, // runJavaScriptAlert
167         nullptr, // runJavaScriptConfirm
168         nullptr, // runJavaScriptPrompt
169         nullptr, // setStatusText
170         nullptr, // mouseDidMoveOverElement_deprecatedForUseWithV0
171         nullptr, // missingPluginButtonClicked_deprecatedForUseWithV0
172         nullptr, // didNotHandleKeyEvent
173         nullptr, // didNotHandleWheelEvent
174         nullptr, // areToolbarsVisible
175         nullptr, // setToolbarsVisible
176         nullptr, // isMenuBarVisible
177         nullptr, // setMenuBarVisible
178         nullptr, // isStatusBarVisible
179         nullptr, // setStatusBarVisible
180         nullptr, // isResizable
181         nullptr, // setResizable
182         nullptr, // getWindowFrame,
183         nullptr, // setWindowFrame,
184         nullptr, // runBeforeUnloadConfirmPanel
185         nullptr, // didDraw
186         nullptr, // pageDidScroll
187         exceededDatabaseQuota,
188         nullptr, // runOpenPanel,
189         nullptr, // decidePolicyForGeolocationPermissionRequest
190         nullptr, // headerHeight
191         nullptr, // footerHeight
192         nullptr, // drawHeader
193         nullptr, // drawFooter
194         nullptr, // printFrame
195         nullptr, // runModal
196         nullptr, // unused
197         nullptr, // saveDataToFileInDownloadsFolder
198         nullptr, // shouldInterruptJavaScript
199         nullptr, // createPage
200         nullptr, // mouseDidMoveOverElement
201         nullptr, // decidePolicyForNotificationPermissionRequest
202         nullptr, // unavailablePluginButtonClicked_deprecatedForUseWithV1
203         nullptr, // showColorPicker
204         nullptr, // hideColorPicker
205         nullptr, // unavailablePluginButtonClicked
206     };
207
208     WKPageNavigationClientV0 navigationClient = {
209         { 0, this },
210         decidePolicyForNavigationAction,
211         nullptr, // decidePolicyForNavigationResponse
212         nullptr, // decidePolicyForPluginLoad
213         nullptr, // didStartProvisionalNavigation
214         nullptr, // didReceiveServerRedirectForProvisionalNavigation
215         nullptr, // didFailProvisionalNavigation
216         nullptr, // didCommitNavigation
217         nullptr, // didFinishNavigation
218         nullptr, // didFailNavigation
219         nullptr, // didFailProvisionalLoadInSubframe
220         nullptr, // didFinishDocumentLoad
221         nullptr, // didSameDocumentNavigation
222         nullptr, // renderingProgressDidChange
223         nullptr, // canAuthenticateAgainstProtectionSpace
224         nullptr, // didReceiveAuthenticationChallenge
225         webProcessDidCrash,
226         nullptr, // copyWebCryptoMasterKey
227
228         nullptr, // didBeginNavigationGesture
229         nullptr, // willEndNavigationGesture
230         nullptr, // didEndNavigationGesture
231         nullptr, // didRemoveNavigationGestureSnapshot
232     };
233
234     WKPageContextMenuClientV3 contextMenuClient = {
235         { 3, this },
236         nullptr, // getContextMenuFromProposedMenu_deprecatedForUseWithV0
237         nullptr, // customContextMenuItemSelected
238         nullptr, // contextMenuDismissed
239         getContextMenuFromProposedMenu,
240         nullptr, // showContextMenu
241         nullptr, // hideContextMenu
242     };
243
244     WebPageProxy* inspectorPage = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_inspectorView));
245     ASSERT(inspectorPage);
246
247     WKPageSetPageUIClient(toAPI(inspectorPage), &uiClient.base);
248     WKPageSetPageNavigationClient(toAPI(inspectorPage), &navigationClient.base);
249     WKPageSetPageContextMenuClient(toAPI(inspectorPage), &contextMenuClient.base);
250
251     return inspectorPage;
252 }
253
254 void WebInspectorProxy::platformCreateFrontendWindow()
255 {
256     if (m_client && m_client->openWindow(*this))
257         return;
258
259     GtkWidget* inspectedViewParent = gtk_widget_get_toplevel(inspectedPage()->viewWidget());
260     if (!WebCore::widgetIsOnscreenToplevelWindow(inspectedViewParent))
261         inspectedViewParent = nullptr;
262
263     ASSERT(!m_inspectorWindow);
264     m_inspectorWindow = webkitInspectorWindowNew(inspectedViewParent ? GTK_WINDOW(inspectedViewParent) : nullptr);
265     gtk_container_add(GTK_CONTAINER(m_inspectorWindow), m_inspectorView);
266     gtk_widget_show(m_inspectorView);
267
268     if (!m_inspectedURLString.isEmpty())
269         updateInspectorWindowTitle();
270
271     g_object_add_weak_pointer(G_OBJECT(m_inspectorWindow), reinterpret_cast<void**>(&m_inspectorWindow));
272     gtk_window_present(GTK_WINDOW(m_inspectorWindow));
273 }
274
275 void WebInspectorProxy::platformCloseFrontendPageAndWindow()
276 {
277     if (m_inspectorView) {
278         g_signal_handlers_disconnect_by_func(m_inspectorView, reinterpret_cast<void*>(inspectorViewDestroyed), this);
279         m_inspectorView = nullptr;
280     }
281
282     if (m_client)
283         m_client->didClose(*this);
284
285     if (m_inspectorWindow) {
286         gtk_widget_destroy(m_inspectorWindow);
287         m_inspectorWindow = nullptr;
288     }
289 }
290
291 void WebInspectorProxy::platformDidCloseForCrash()
292 {
293 }
294
295 void WebInspectorProxy::platformInvalidate()
296 {
297 }
298
299 void WebInspectorProxy::platformHide()
300 {
301     notImplemented();
302 }
303
304 void WebInspectorProxy::platformBringToFront()
305 {
306     if (m_isOpening)
307         return;
308
309     if (m_client && m_client->bringToFront(*this))
310         return;
311
312     GtkWidget* parent = gtk_widget_get_toplevel(m_inspectorView);
313     if (WebCore::widgetIsOnscreenToplevelWindow(parent))
314         gtk_window_present(GTK_WINDOW(parent));
315 }
316
317 void WebInspectorProxy::platformBringInspectedPageToFront()
318 {
319     notImplemented();
320 }
321
322 bool WebInspectorProxy::platformIsFront()
323 {
324     GtkWidget* parent = gtk_widget_get_toplevel(m_inspectorView);
325     if (WebCore::widgetIsOnscreenToplevelWindow(parent))
326         return m_isVisible && gtk_window_is_active(GTK_WINDOW(parent));
327     return false;
328 }
329
330 void WebInspectorProxy::platformInspectedURLChanged(const String& url)
331 {
332     m_inspectedURLString = url;
333     if (m_client)
334         m_client->inspectedURLChanged(*this, url);
335
336     if (m_inspectorWindow)
337         updateInspectorWindowTitle();
338 }
339
340 String WebInspectorProxy::inspectorPageURL()
341 {
342     return String("resource:///org/webkit/inspector/UserInterface/Main.html");
343 }
344
345 String WebInspectorProxy::inspectorTestPageURL()
346 {
347     return String("resource:///org/webkit/inspector/UserInterface/Test.html");
348 }
349
350 String WebInspectorProxy::inspectorBaseURL()
351 {
352     return String("resource:///org/webkit/inspector/UserInterface/");
353 }
354
355 unsigned WebInspectorProxy::platformInspectedWindowHeight()
356 {
357     return gtk_widget_get_allocated_height(inspectedPage()->viewWidget());
358 }
359
360 unsigned WebInspectorProxy::platformInspectedWindowWidth()
361 {
362     return gtk_widget_get_allocated_width(inspectedPage()->viewWidget());
363 }
364
365 void WebInspectorProxy::platformAttach()
366 {
367     GRefPtr<GtkWidget> inspectorView = m_inspectorView;
368     if (m_inspectorWindow) {
369         gtk_container_remove(GTK_CONTAINER(m_inspectorWindow), m_inspectorView);
370         gtk_widget_destroy(m_inspectorWindow);
371         m_inspectorWindow = 0;
372     }
373
374     // Set a default sizes based on InspectorFrontendClientLocal.
375     static const unsigned defaultAttachedSize = 300;
376     static const unsigned minimumAttachedWidth = 750;
377     static const unsigned minimumAttachedHeight = 250;
378
379     if (m_attachmentSide == AttachmentSide::Bottom) {
380         unsigned maximumAttachedHeight = platformInspectedWindowHeight() * 3 / 4;
381         platformSetAttachedWindowHeight(std::max(minimumAttachedHeight, std::min(defaultAttachedSize, maximumAttachedHeight)));
382     } else {
383         unsigned maximumAttachedWidth = platformInspectedWindowWidth() * 3 / 4;
384         platformSetAttachedWindowWidth(std::max(minimumAttachedWidth, std::min(defaultAttachedSize, maximumAttachedWidth)));
385     }
386
387     if (m_client && m_client->attach(*this))
388         return;
389
390     webkitWebViewBaseAddWebInspector(WEBKIT_WEB_VIEW_BASE(inspectedPage()->viewWidget()), m_inspectorView, m_attachmentSide);
391     gtk_widget_show(m_inspectorView);
392 }
393
394 void WebInspectorProxy::platformDetach()
395 {
396     if (!inspectedPage()->isValid())
397         return;
398
399     GRefPtr<GtkWidget> inspectorView = m_inspectorView;
400     if (!m_client || !m_client->detach(*this)) {
401         // Detach is called when m_isAttached is true, but it could called before
402         // the inspector is opened if the inspector is shown/closed quickly. So,
403         // we might not have a parent yet.
404         if (GtkWidget* parent = gtk_widget_get_parent(m_inspectorView))
405             gtk_container_remove(GTK_CONTAINER(parent), m_inspectorView);
406     }
407
408     // Return early if we are not visible. This means the inspector was closed while attached
409     // and we should not create and show the inspector window.
410     if (!m_isVisible) {
411         // The inspector view will be destroyed, but we don't need to notify the web process to close the
412         // inspector in this case, since it's already closed.
413         g_signal_handlers_disconnect_by_func(m_inspectorView, reinterpret_cast<void*>(inspectorViewDestroyed), this);
414         m_inspectorView = nullptr;
415         return;
416     }
417
418     open();
419 }
420
421 void WebInspectorProxy::platformSetAttachedWindowHeight(unsigned height)
422 {
423     if (!m_isAttached)
424         return;
425
426     if (m_client)
427         m_client->didChangeAttachedHeight(*this, height);
428     webkitWebViewBaseSetInspectorViewSize(WEBKIT_WEB_VIEW_BASE(inspectedPage()->viewWidget()), height);
429 }
430
431 void WebInspectorProxy::platformSetAttachedWindowWidth(unsigned width)
432 {
433     if (!m_isAttached)
434         return;
435
436     if (m_client)
437         m_client->didChangeAttachedWidth(*this, width);
438     webkitWebViewBaseSetInspectorViewSize(WEBKIT_WEB_VIEW_BASE(inspectedPage()->viewWidget()), width);
439 }
440
441 void WebInspectorProxy::platformStartWindowDrag()
442 {
443     notImplemented();
444 }
445
446 void WebInspectorProxy::platformSave(const String&, const String&, bool, bool)
447 {
448     notImplemented();
449 }
450
451 void WebInspectorProxy::platformAppend(const String&, const String&)
452 {
453     notImplemented();
454 }
455
456 void WebInspectorProxy::platformAttachAvailabilityChanged(bool available)
457 {
458     if (m_client)
459         m_client->didChangeAttachAvailability(*this, available);
460 }
461
462 } // namespace WebKit