[PAL] Move Sound into PAL
[WebKit-https.git] / Source / WebCore / inspector / InspectorFrontendHost.cpp
1 /*
2  * Copyright (C) 2007-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.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  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "InspectorFrontendHost.h"
32
33 #include "ContextMenu.h"
34 #include "ContextMenuController.h"
35 #include "ContextMenuItem.h"
36 #include "ContextMenuProvider.h"
37 #include "DOMWrapperWorld.h"
38 #include "Document.h"
39 #include "Editor.h"
40 #include "Event.h"
41 #include "FocusController.h"
42 #include "HitTestResult.h"
43 #include "InspectorFrontendClient.h"
44 #include "JSMainThreadExecState.h"
45 #include "MainFrame.h"
46 #include "MouseEvent.h"
47 #include "Node.h"
48 #include "Page.h"
49 #include "Pasteboard.h"
50 #include "ScriptGlobalObject.h"
51 #include "ScriptState.h"
52 #include "UserGestureIndicator.h"
53 #include <bindings/ScriptFunctionCall.h>
54 #include <pal/system/Sound.h>
55 #include <wtf/StdLibExtras.h>
56
57 using namespace Inspector;
58
59 namespace WebCore {
60
61 #if ENABLE(CONTEXT_MENUS)
62 class FrontendMenuProvider : public ContextMenuProvider {
63 public:
64     static Ref<FrontendMenuProvider> create(InspectorFrontendHost* frontendHost, Deprecated::ScriptObject frontendApiObject, const Vector<ContextMenuItem>& items)
65     {
66         return adoptRef(*new FrontendMenuProvider(frontendHost, frontendApiObject, items));
67     }
68     
69     void disconnect()
70     {
71         m_frontendApiObject = { };
72         m_frontendHost = nullptr;
73     }
74     
75 private:
76     FrontendMenuProvider(InspectorFrontendHost* frontendHost, Deprecated::ScriptObject frontendApiObject, const Vector<ContextMenuItem>& items)
77         : m_frontendHost(frontendHost)
78         , m_frontendApiObject(frontendApiObject)
79         , m_items(items)
80     {
81     }
82
83     virtual ~FrontendMenuProvider()
84     {
85         contextMenuCleared();
86     }
87     
88     void populateContextMenu(ContextMenu* menu) override
89     {
90         for (auto& item : m_items)
91             menu->appendItem(item);
92     }
93     
94     void contextMenuItemSelected(ContextMenuAction action, const String&) override
95     {
96         if (m_frontendHost) {
97             UserGestureIndicator gestureIndicator(ProcessingUserGesture);
98             int itemNumber = action - ContextMenuItemBaseCustomTag;
99
100             Deprecated::ScriptFunctionCall function(m_frontendApiObject, "contextMenuItemSelected", WebCore::functionCallHandlerFromAnyThread);
101             function.appendArgument(itemNumber);
102             function.call();
103         }
104     }
105     
106     void contextMenuCleared() override
107     {
108         if (m_frontendHost) {
109             Deprecated::ScriptFunctionCall function(m_frontendApiObject, "contextMenuCleared", WebCore::functionCallHandlerFromAnyThread);
110             function.call();
111
112             m_frontendHost->m_menuProvider = nullptr;
113         }
114         m_items.clear();
115     }
116
117     InspectorFrontendHost* m_frontendHost;
118     Deprecated::ScriptObject m_frontendApiObject;
119     Vector<ContextMenuItem> m_items;
120 };
121 #endif
122
123 InspectorFrontendHost::InspectorFrontendHost(InspectorFrontendClient* client, Page* frontendPage)
124     : m_client(client)
125     , m_frontendPage(frontendPage)
126 #if ENABLE(CONTEXT_MENUS)
127     , m_menuProvider(nullptr)
128 #endif
129 {
130 }
131
132 InspectorFrontendHost::~InspectorFrontendHost()
133 {
134     ASSERT(!m_client);
135 }
136
137 void InspectorFrontendHost::disconnectClient()
138 {
139     m_client = nullptr;
140 #if ENABLE(CONTEXT_MENUS)
141     if (m_menuProvider)
142         m_menuProvider->disconnect();
143 #endif
144     m_frontendPage = nullptr;
145 }
146
147 void InspectorFrontendHost::loaded()
148 {
149     if (m_client)
150         m_client->frontendLoaded();
151 }
152
153 void InspectorFrontendHost::requestSetDockSide(const String& side)
154 {
155     if (!m_client)
156         return;
157     if (side == "undocked")
158         m_client->requestSetDockSide(InspectorFrontendClient::DockSide::Undocked);
159     else if (side == "right")
160         m_client->requestSetDockSide(InspectorFrontendClient::DockSide::Right);
161     else if (side == "left")
162         m_client->requestSetDockSide(InspectorFrontendClient::DockSide::Left);
163     else if (side == "bottom")
164         m_client->requestSetDockSide(InspectorFrontendClient::DockSide::Bottom);
165 }
166
167 void InspectorFrontendHost::closeWindow()
168 {
169     if (m_client) {
170         m_client->closeWindow();
171         disconnectClient(); // Disconnect from client.
172     }
173 }
174
175 void InspectorFrontendHost::bringToFront()
176 {
177     if (m_client)
178         m_client->bringToFront();
179 }
180
181 void InspectorFrontendHost::inspectedURLChanged(const String& newURL)
182 {
183     if (m_client)
184         m_client->inspectedURLChanged(newURL);
185 }
186
187 void InspectorFrontendHost::setZoomFactor(float zoom)
188 {
189     if (m_frontendPage)
190         m_frontendPage->mainFrame().setPageAndTextZoomFactors(zoom, 1);
191 }
192
193 float InspectorFrontendHost::zoomFactor()
194 {
195     if (m_frontendPage)
196         return m_frontendPage->mainFrame().pageZoomFactor();
197
198     return 1.0;
199 }
200
201 String InspectorFrontendHost::userInterfaceLayoutDirection()
202 {
203     if (m_client && m_client->userInterfaceLayoutDirection() == UserInterfaceLayoutDirection::RTL)
204         return ASCIILiteral("rtl");
205
206     return ASCIILiteral("ltr");
207 }
208
209 void InspectorFrontendHost::setAttachedWindowHeight(unsigned height)
210 {
211     if (m_client)
212         m_client->changeAttachedWindowHeight(height);
213 }
214
215 void InspectorFrontendHost::setAttachedWindowWidth(unsigned width)
216 {
217     if (m_client)
218         m_client->changeAttachedWindowWidth(width);
219 }
220
221 void InspectorFrontendHost::startWindowDrag()
222 {
223     if (m_client)
224         m_client->startWindowDrag();
225 }
226
227 void InspectorFrontendHost::moveWindowBy(float x, float y) const
228 {
229     if (m_client)
230         m_client->moveWindowBy(x, y);
231 }
232
233 String InspectorFrontendHost::localizedStringsURL()
234 {
235     return m_client ? m_client->localizedStringsURL() : String();
236 }
237
238 String InspectorFrontendHost::backendCommandsURL()
239 {
240     return m_client ? m_client->backendCommandsURL() : String();
241 }
242
243 String InspectorFrontendHost::debuggableType()
244 {
245     return m_client ? m_client->debuggableType() : String();
246 }
247
248 unsigned InspectorFrontendHost::inspectionLevel()
249 {
250     return m_client ? m_client->inspectionLevel() : 1;
251 }
252
253 String InspectorFrontendHost::platform()
254 {
255 #if PLATFORM(MAC) || PLATFORM(IOS)
256     return ASCIILiteral("mac");
257 #elif OS(WINDOWS)
258     return ASCIILiteral("windows");
259 #elif OS(LINUX)
260     return ASCIILiteral("linux");
261 #elif OS(FREEBSD)
262     return ASCIILiteral("freebsd");
263 #elif OS(OPENBSD)
264     return ASCIILiteral("openbsd");
265 #elif OS(SOLARIS)
266     return ASCIILiteral("solaris");
267 #else
268     return ASCIILiteral("unknown");
269 #endif
270 }
271
272 String InspectorFrontendHost::port()
273 {
274 #if PLATFORM(GTK)
275     return ASCIILiteral("gtk");
276 #else
277     return ASCIILiteral("unknown");
278 #endif
279 }
280
281 void InspectorFrontendHost::copyText(const String& text)
282 {
283     Pasteboard::createForCopyAndPaste()->writePlainText(text, Pasteboard::CannotSmartReplace);
284 }
285
286 void InspectorFrontendHost::killText(const String& text, bool shouldPrependToKillRing, bool shouldStartNewSequence)
287 {
288     if (!m_frontendPage)
289         return;
290
291     Editor& editor = m_frontendPage->focusController().focusedOrMainFrame().editor();
292     editor.setStartNewKillRingSequence(shouldStartNewSequence);
293     Editor::KillRingInsertionMode insertionMode = shouldPrependToKillRing ? Editor::KillRingInsertionMode::PrependText : Editor::KillRingInsertionMode::AppendText;
294     editor.addTextToKillRing(text, insertionMode);
295 }
296
297 void InspectorFrontendHost::openInNewTab(const String& url)
298 {
299     if (WebCore::protocolIsJavaScript(url))
300         return;
301
302     if (m_client)
303         m_client->openInNewTab(url);
304 }
305
306 bool InspectorFrontendHost::canSave()
307 {
308     if (m_client)
309         return m_client->canSave();
310     return false;
311 }
312
313 void InspectorFrontendHost::save(const String& url, const String& content, bool base64Encoded, bool forceSaveAs)
314 {
315     if (m_client)
316         m_client->save(url, content, base64Encoded, forceSaveAs);
317 }
318
319 void InspectorFrontendHost::append(const String& url, const String& content)
320 {
321     if (m_client)
322         m_client->append(url, content);
323 }
324
325 void InspectorFrontendHost::close(const String&)
326 {
327 }
328
329 void InspectorFrontendHost::sendMessageToBackend(const String& message)
330 {
331     if (m_client)
332         m_client->sendMessageToBackend(message);
333 }
334
335 #if ENABLE(CONTEXT_MENUS)
336
337 void InspectorFrontendHost::showContextMenu(Event* event, const Vector<ContextMenuItem>& items)
338 {
339     if (!event)
340         return;
341
342     ASSERT(m_frontendPage);
343     auto& state = *execStateFromPage(debuggerWorld(), m_frontendPage);
344     JSC::JSObject* frontendApiObject;
345     if (!ScriptGlobalObject::get(state, "InspectorFrontendAPI", frontendApiObject)) {
346         ASSERT_NOT_REACHED();
347         return;
348     }
349     auto menuProvider = FrontendMenuProvider::create(this, { &state, frontendApiObject }, items);
350     m_menuProvider = menuProvider.ptr();
351     m_frontendPage->contextMenuController().showContextMenu(*event, menuProvider);
352 }
353
354 #endif
355
356 void InspectorFrontendHost::dispatchEventAsContextMenuEvent(Event* event)
357 {
358 #if ENABLE(CONTEXT_MENUS) && USE(ACCESSIBILITY_CONTEXT_MENUS)
359     if (!is<MouseEvent>(event))
360         return;
361
362     Frame* frame = event->target()->toNode()->document().frame();
363     MouseEvent& mouseEvent = downcast<MouseEvent>(*event);
364     IntPoint mousePoint = IntPoint(mouseEvent.clientX(), mouseEvent.clientY());
365
366     m_frontendPage->contextMenuController().showContextMenuAt(*frame, mousePoint);
367 #else
368     UNUSED_PARAM(event);
369 #endif
370 }
371
372 bool InspectorFrontendHost::isUnderTest()
373 {
374     return m_client && m_client->isUnderTest();
375 }
376
377 void InspectorFrontendHost::unbufferedLog(const String& message)
378 {
379     // This is used only for debugging inspector tests.
380     WTFLogAlways("%s", message.utf8().data());
381 }
382
383 void InspectorFrontendHost::beep()
384 {
385     PAL::systemBeep();
386 }
387
388 } // namespace WebCore