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 "config.h"
27#include "WebInspector.h"
28
29#if ENABLE(INSPECTOR)
30#include "WebFrame.h"
31#include "WebInspectorFrontendClient.h"
32#include "WebInspectorProxyMessages.h"
33#include "WebPage.h"
34#include "WebPageCreationParameters.h"
35#include "WebProcess.h"
36#include <WebCore/InspectorController.h>
37#include <WebCore/InspectorFrontendClient.h>
38#include <WebCore/MainFrame.h>
39#include <WebCore/Page.h>
40#include <WebCore/ScriptController.h>
41#include <inspector/InspectorAgentBase.h>
42#include <bindings/ScriptValue.h>
43#include <wtf/text/StringConcatenate.h>
44
45using namespace WebCore;
46
47namespace WebKit {
48
49PassRefPtr<WebInspector> WebInspector::create(WebPage* page, InspectorFrontendChannel* frontendChannel)
50{
51    return adoptRef(new WebInspector(page, frontendChannel));
52}
53
54WebInspector::WebInspector(WebPage* page, InspectorFrontendChannel* frontendChannel)
55    : m_page(page)
56    , m_inspectorPage(nullptr)
57    , m_frontendClient(nullptr)
58    , m_frontendChannel(frontendChannel)
59#if PLATFORM(COCOA)
60    , m_hasLocalizedStringsURL(false)
61#endif
62#if ENABLE(INSPECTOR_SERVER)
63    , m_remoteFrontendConnected(false)
64#endif
65{
66}
67
68// Called from WebInspectorClient
69WebPage* WebInspector::createInspectorPage()
70{
71    if (!m_page)
72        return nullptr;
73
74    ASSERT(!m_inspectorPage);
75    ASSERT(!m_frontendClient);
76
77    uint64_t inspectorPageID = 0;
78    WebPageCreationParameters parameters;
79
80    if (!WebProcess::shared().parentProcessConnection()->sendSync(Messages::WebInspectorProxy::CreateInspectorPage(),
81            Messages::WebInspectorProxy::CreateInspectorPage::Reply(inspectorPageID, parameters),
82            m_page->pageID(), std::chrono::milliseconds::max())) {
83        return nullptr;
84    }
85
86    if (!inspectorPageID)
87        return nullptr;
88
89    WebProcess::shared().createWebPage(inspectorPageID, parameters);
90    m_inspectorPage = WebProcess::shared().webPage(inspectorPageID);
91    ASSERT(m_inspectorPage);
92
93    auto frontendClient = std::make_unique<WebInspectorFrontendClient>(m_page, m_inspectorPage);
94    m_frontendClient = frontendClient.get();
95    m_inspectorPage->corePage()->inspectorController().setInspectorFrontendClient(WTF::move(frontendClient));
96    return m_inspectorPage;
97}
98
99WebPage* WebInspector::createInspectorPageForTest()
100{
101    if (!m_page)
102        return nullptr;
103
104    ASSERT(!m_inspectorPage);
105    ASSERT(!m_frontendClient);
106
107    uint64_t inspectorPageID = 0;
108    WebPageCreationParameters parameters;
109
110    if (!WebProcess::shared().parentProcessConnection()->sendSync(Messages::WebInspectorProxy::CreateInspectorPageForTest(),
111            Messages::WebInspectorProxy::CreateInspectorPageForTest::Reply(inspectorPageID, parameters),
112            m_page->pageID(), std::chrono::milliseconds::max())) {
113        return nullptr;
114    }
115
116    if (!inspectorPageID)
117        return nullptr;
118
119    WebProcess::shared().createWebPage(inspectorPageID, parameters);
120    m_inspectorPage = WebProcess::shared().webPage(inspectorPageID);
121    ASSERT(m_inspectorPage);
122
123    auto frontendClient = std::make_unique<WebInspectorFrontendClient>(m_page, m_inspectorPage);
124    m_frontendClient = frontendClient.get();
125    m_inspectorPage->corePage()->inspectorController().setInspectorFrontendClient(WTF::move(frontendClient));
126    return m_inspectorPage;
127}
128
129void WebInspector::destroyInspectorPage()
130{
131    m_inspectorPage = nullptr;
132    m_frontendClient = nullptr;
133    m_frontendChannel = nullptr;
134}
135
136// Called from WebInspectorFrontendClient
137void WebInspector::didClose()
138{
139    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::DidClose(), m_page->pageID());
140    destroyInspectorPage();
141}
142
143void WebInspector::bringToFront()
144{
145    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::BringToFront(), m_page->pageID());
146}
147
148void WebInspector::inspectedURLChanged(const String& urlString)
149{
150    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::InspectedURLChanged(urlString), m_page->pageID());
151}
152
153void WebInspector::save(const String& filename, const String& content, bool base64Encoded, bool forceSaveAs)
154{
155    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::Save(filename, content, base64Encoded, forceSaveAs), m_page->pageID());
156}
157
158void WebInspector::append(const String& filename, const String& content)
159{
160    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::Append(filename, content), m_page->pageID());
161}
162
163void WebInspector::attachBottom()
164{
165    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::AttachBottom(), m_page->pageID());
166}
167
168void WebInspector::attachRight()
169{
170    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::AttachRight(), m_page->pageID());
171}
172
173void WebInspector::detach()
174{
175    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::Detach(), m_page->pageID());
176}
177
178void WebInspector::setAttachedWindowHeight(unsigned height)
179{
180    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::SetAttachedWindowHeight(height), m_page->pageID());
181}
182
183void WebInspector::setAttachedWindowWidth(unsigned width)
184{
185    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::SetAttachedWindowWidth(width), m_page->pageID());
186}
187
188void WebInspector::setToolbarHeight(unsigned height)
189{
190    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::SetToolbarHeight(height), m_page->pageID());
191}
192
193// Called by WebInspector messages
194void WebInspector::show()
195{
196    m_page->corePage()->inspectorController().show();
197}
198
199void WebInspector::close()
200{
201    m_page->corePage()->inspectorController().close();
202}
203
204void WebInspector::didSave(const String& url)
205{
206    ASSERT(m_inspectorPage);
207    m_inspectorPage->corePage()->mainFrame().script().executeScript(makeString("InspectorFrontendAPI.savedURL(\"", url, "\")"));
208}
209
210void WebInspector::didAppend(const String& url)
211{
212    ASSERT(m_inspectorPage);
213    m_inspectorPage->corePage()->mainFrame().script().executeScript(makeString("InspectorFrontendAPI.appendedToURL(\"", url, "\")"));
214}
215
216void WebInspector::attachedBottom()
217{
218    if (m_frontendClient)
219        m_frontendClient->setAttachedWindow(InspectorFrontendClient::DOCKED_TO_BOTTOM);
220}
221
222void WebInspector::attachedRight()
223{
224    if (m_frontendClient)
225        m_frontendClient->setAttachedWindow(InspectorFrontendClient::DOCKED_TO_RIGHT);
226}
227
228void WebInspector::detached()
229{
230    if (m_frontendClient)
231        m_frontendClient->setAttachedWindow(InspectorFrontendClient::UNDOCKED);
232}
233
234void WebInspector::evaluateScriptForTest(const String& script)
235{
236    m_page->corePage()->inspectorController().evaluateForTestInFrontend(script);
237}
238
239void WebInspector::showConsole()
240{
241    m_page->corePage()->inspectorController().show();
242    if (m_frontendClient)
243        m_frontendClient->showConsole();
244}
245
246void WebInspector::showResources()
247{
248    m_page->corePage()->inspectorController().show();
249    if (m_frontendClient)
250        m_frontendClient->showResources();
251}
252
253void WebInspector::showMainResourceForFrame(uint64_t frameID)
254{
255    WebFrame* frame = WebProcess::shared().webFrame(frameID);
256    if (!frame)
257        return;
258
259    m_page->corePage()->inspectorController().show();
260    if (m_frontendClient)
261        m_frontendClient->showMainResourceForFrame(frame->coreFrame());
262}
263
264void WebInspector::startJavaScriptDebugging()
265{
266    m_page->corePage()->inspectorController().show();
267    if (m_frontendClient)
268        m_frontendClient->setDebuggingEnabled(true);
269}
270
271void WebInspector::stopJavaScriptDebugging()
272{
273    m_page->corePage()->inspectorController().show();
274    if (m_frontendClient)
275        m_frontendClient->setDebuggingEnabled(false);
276}
277
278void WebInspector::setJavaScriptProfilingEnabled(bool enabled)
279{
280    // No longer supported.
281}
282
283void WebInspector::startJavaScriptProfiling()
284{
285    // No longer supported.
286}
287
288void WebInspector::stopJavaScriptProfiling()
289{
290    // No longer supported.
291}
292
293void WebInspector::startPageProfiling()
294{
295    m_page->corePage()->inspectorController().show();
296    if (m_frontendClient)
297        m_frontendClient->setTimelineProfilingEnabled(true);
298}
299
300void WebInspector::stopPageProfiling()
301{
302    m_page->corePage()->inspectorController().show();
303    if (m_frontendClient)
304        m_frontendClient->setTimelineProfilingEnabled(false);
305}
306
307void WebInspector::updateDockingAvailability()
308{
309    if (!m_frontendClient)
310        return;
311
312    bool canAttachWindow = m_frontendClient->canAttachWindow();
313    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::AttachAvailabilityChanged(canAttachWindow), m_page->pageID());
314    m_frontendClient->setDockingUnavailable(!canAttachWindow);
315}
316
317#if ENABLE(INSPECTOR_SERVER)
318void WebInspector::sendMessageToRemoteFrontend(const String& message)
319{
320    ASSERT(m_remoteFrontendConnected);
321    WebProcess::shared().parentProcessConnection()->send(Messages::WebInspectorProxy::SendMessageToRemoteFrontend(message), m_page->pageID());
322}
323
324void WebInspector::dispatchMessageFromRemoteFrontend(const String& message)
325{
326    m_page->corePage()->inspectorController().dispatchMessageFromFrontend(message);
327}
328
329void WebInspector::remoteFrontendConnected()
330{
331    ASSERT(!m_remoteFrontendConnected);
332    // Switching between in-process and remote inspectors isn't supported yet.
333    ASSERT(!m_inspectorPage);
334
335    m_page->corePage()->inspectorController().connectFrontend(m_frontendChannel);
336    m_remoteFrontendConnected = true;
337}
338
339void WebInspector::remoteFrontendDisconnected()
340{
341    ASSERT(m_remoteFrontendConnected);
342    m_page->corePage()->inspectorController().disconnectFrontend(Inspector::InspectorDisconnectReason::InspectorDestroyed);
343    m_remoteFrontendConnected = false;
344}
345#endif
346
347} // namespace WebKit
348
349#endif // ENABLE(INSPECTOR)
350