ContextMenuController::contextMenuItemSelected only needs the action and title, not...
[WebKit-https.git] / Source / WebCore / inspector / InspectorFrontendHost.cpp
1 /*
2  * Copyright (C) 2007, 2008 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 "Event.h"
40 #include "HitTestResult.h"
41 #include "InspectorFrontendClient.h"
42 #include "JSMainThreadExecState.h"
43 #include "MainFrame.h"
44 #include "MouseEvent.h"
45 #include "Node.h"
46 #include "Page.h"
47 #include "Pasteboard.h"
48 #include "ScriptGlobalObject.h"
49 #include "ScriptState.h"
50 #include "Sound.h"
51 #include "UserGestureIndicator.h"
52 #include <bindings/ScriptFunctionCall.h>
53 #include <wtf/StdLibExtras.h>
54
55 using namespace Inspector;
56
57 namespace WebCore {
58
59 #if ENABLE(CONTEXT_MENUS)
60 class FrontendMenuProvider : public ContextMenuProvider {
61 public:
62     static Ref<FrontendMenuProvider> create(InspectorFrontendHost* frontendHost, Deprecated::ScriptObject frontendApiObject, const Vector<ContextMenuItem>& items)
63     {
64         return adoptRef(*new FrontendMenuProvider(frontendHost, frontendApiObject, items));
65     }
66     
67     void disconnect()
68     {
69         m_frontendApiObject = Deprecated::ScriptObject();
70         m_frontendHost = nullptr;
71     }
72     
73 private:
74     FrontendMenuProvider(InspectorFrontendHost* frontendHost, Deprecated::ScriptObject frontendApiObject, const Vector<ContextMenuItem>& items)
75         : m_frontendHost(frontendHost)
76         , m_frontendApiObject(frontendApiObject)
77         , m_items(items)
78     {
79     }
80
81     virtual ~FrontendMenuProvider()
82     {
83         contextMenuCleared();
84     }
85     
86     virtual void populateContextMenu(ContextMenu* menu) override
87     {
88         for (auto& item : m_items)
89             menu->appendItem(item);
90     }
91     
92     virtual void contextMenuItemSelected(ContextMenuAction action, const String&) override
93     {
94         if (m_frontendHost) {
95             UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
96             int itemNumber = action - ContextMenuItemBaseCustomTag;
97
98             Deprecated::ScriptFunctionCall function(m_frontendApiObject, "contextMenuItemSelected", WebCore::functionCallHandlerFromAnyThread);
99             function.appendArgument(itemNumber);
100             function.call();
101         }
102     }
103     
104     virtual void contextMenuCleared() override
105     {
106         if (m_frontendHost) {
107             Deprecated::ScriptFunctionCall function(m_frontendApiObject, "contextMenuCleared", WebCore::functionCallHandlerFromAnyThread);
108             function.call();
109
110             m_frontendHost->m_menuProvider = nullptr;
111         }
112         m_items.clear();
113     }
114
115     InspectorFrontendHost* m_frontendHost;
116     Deprecated::ScriptObject m_frontendApiObject;
117     Vector<ContextMenuItem> m_items;
118 };
119 #endif
120
121 InspectorFrontendHost::InspectorFrontendHost(InspectorFrontendClient* client, Page* frontendPage)
122     : m_client(client)
123     , m_frontendPage(frontendPage)
124 #if ENABLE(CONTEXT_MENUS)
125     , m_menuProvider(nullptr)
126 #endif
127 {
128 }
129
130 InspectorFrontendHost::~InspectorFrontendHost()
131 {
132     ASSERT(!m_client);
133 }
134
135 void InspectorFrontendHost::disconnectClient()
136 {
137     m_client = nullptr;
138 #if ENABLE(CONTEXT_MENUS)
139     if (m_menuProvider)
140         m_menuProvider->disconnect();
141 #endif
142     m_frontendPage = nullptr;
143 }
144
145 void InspectorFrontendHost::loaded()
146 {
147     if (m_client)
148         m_client->frontendLoaded();
149 }
150
151 void InspectorFrontendHost::requestSetDockSide(const String& side)
152 {
153     if (!m_client)
154         return;
155     if (side == "undocked")
156         m_client->requestSetDockSide(InspectorFrontendClient::DockSide::Undocked);
157     else if (side == "right")
158         m_client->requestSetDockSide(InspectorFrontendClient::DockSide::Right);
159     else if (side == "bottom")
160         m_client->requestSetDockSide(InspectorFrontendClient::DockSide::Bottom);
161 }
162
163 void InspectorFrontendHost::closeWindow()
164 {
165     if (m_client) {
166         m_client->closeWindow();
167         disconnectClient(); // Disconnect from client.
168     }
169 }
170
171 void InspectorFrontendHost::bringToFront()
172 {
173     if (m_client)
174         m_client->bringToFront();
175 }
176
177 void InspectorFrontendHost::inspectedURLChanged(const String& newURL)
178 {
179     if (m_client)
180         m_client->inspectedURLChanged(newURL);
181 }
182
183 void InspectorFrontendHost::setZoomFactor(float zoom)
184 {
185     m_frontendPage->mainFrame().setPageAndTextZoomFactors(zoom, 1);
186 }
187
188 float InspectorFrontendHost::zoomFactor()
189 {
190     return m_frontendPage->mainFrame().pageZoomFactor();
191 }
192
193 void InspectorFrontendHost::setAttachedWindowHeight(unsigned height)
194 {
195     if (m_client)
196         m_client->changeAttachedWindowHeight(height);
197 }
198
199 void InspectorFrontendHost::setAttachedWindowWidth(unsigned width)
200 {
201     if (m_client)
202         m_client->changeAttachedWindowWidth(width);
203 }
204
205 void InspectorFrontendHost::setToolbarHeight(unsigned height)
206 {
207     if (m_client)
208         m_client->setToolbarHeight(height);
209 }
210
211 void InspectorFrontendHost::startWindowDrag()
212 {
213     if (m_client)
214         m_client->startWindowDrag();
215 }
216
217 void InspectorFrontendHost::moveWindowBy(float x, float y) const
218 {
219     if (m_client)
220         m_client->moveWindowBy(x, y);
221 }
222
223 String InspectorFrontendHost::localizedStringsURL()
224 {
225     return m_client ? m_client->localizedStringsURL() : "";
226 }
227
228 String InspectorFrontendHost::debuggableType()
229 {
230     return ASCIILiteral("web");
231 }
232
233 String InspectorFrontendHost::platform()
234 {
235 #if PLATFORM(MAC) || PLATFORM(IOS)
236     return ASCIILiteral("mac");
237 #elif OS(WINDOWS)
238     return ASCIILiteral("windows");
239 #elif OS(LINUX)
240     return ASCIILiteral("linux");
241 #elif OS(FREEBSD)
242     return ASCIILiteral("freebsd");
243 #elif OS(OPENBSD)
244     return ASCIILiteral("openbsd");
245 #elif OS(SOLARIS)
246     return ASCIILiteral("solaris");
247 #else
248     return ASCIILiteral("unknown");
249 #endif
250 }
251
252 String InspectorFrontendHost::port()
253 {
254 #if PLATFORM(GTK)
255     return ASCIILiteral("gtk");
256 #elif PLATFORM(EFL)
257     return ASCIILiteral("efl");
258 #else
259     return ASCIILiteral("unknown");
260 #endif
261 }
262
263 void InspectorFrontendHost::copyText(const String& text)
264 {
265     Pasteboard::createForCopyAndPaste()->writePlainText(text, Pasteboard::CannotSmartReplace);
266 }
267
268 void InspectorFrontendHost::openInNewTab(const String& url)
269 {
270     if (m_client)
271         m_client->openInNewTab(url);
272 }
273
274 bool InspectorFrontendHost::canSave()
275 {
276     if (m_client)
277         return m_client->canSave();
278     return false;
279 }
280
281 void InspectorFrontendHost::save(const String& url, const String& content, bool base64Encoded, bool forceSaveAs)
282 {
283     if (m_client)
284         m_client->save(url, content, base64Encoded, forceSaveAs);
285 }
286
287 void InspectorFrontendHost::append(const String& url, const String& content)
288 {
289     if (m_client)
290         m_client->append(url, content);
291 }
292
293 void InspectorFrontendHost::close(const String&)
294 {
295 }
296
297 void InspectorFrontendHost::sendMessageToBackend(const String& message)
298 {
299     if (m_client)
300         m_client->sendMessageToBackend(message);
301 }
302
303 #if ENABLE(CONTEXT_MENUS)
304 void InspectorFrontendHost::showContextMenu(Event* event, const Vector<ContextMenuItem>& items)
305 {
306     if (!event)
307         return;
308
309     ASSERT(m_frontendPage);
310     JSC::ExecState* frontendExecState = execStateFromPage(debuggerWorld(), m_frontendPage);
311     Deprecated::ScriptObject frontendApiObject;
312     if (!ScriptGlobalObject::get(frontendExecState, "InspectorFrontendAPI", frontendApiObject)) {
313         ASSERT_NOT_REACHED();
314         return;
315     }
316     RefPtr<FrontendMenuProvider> menuProvider = FrontendMenuProvider::create(this, frontendApiObject, items);
317     m_frontendPage->contextMenuController().showContextMenu(event, menuProvider);
318     m_menuProvider = menuProvider.get();
319 }
320 #endif
321
322 void InspectorFrontendHost::dispatchEventAsContextMenuEvent(Event* event)
323 {
324 #if ENABLE(CONTEXT_MENUS) && USE(ACCESSIBILITY_CONTEXT_MENUS)
325     if (!is<MouseEvent>(event))
326         return;
327
328     Frame* frame = event->target()->toNode()->document().frame();
329     MouseEvent& mouseEvent = downcast<MouseEvent>(*event);
330     IntPoint mousePoint = IntPoint(mouseEvent.clientX(), mouseEvent.clientY());
331
332     m_frontendPage->contextMenuController().showContextMenuAt(frame, mousePoint);
333 #else
334     UNUSED_PARAM(event);
335 #endif
336 }
337
338 bool InspectorFrontendHost::isUnderTest()
339 {
340     return m_client && m_client->isUnderTest();
341 }
342
343 void InspectorFrontendHost::unbufferedLog(const String& message)
344 {
345     // This is used only for debugging inspector tests.
346     WTFLogAlways("%s", message.utf8().data());
347 }
348
349 void InspectorFrontendHost::beep()
350 {
351     systemBeep();
352 }
353
354 } // namespace WebCore