REGRESSION(r223773): [GTK] WebKitWebInspector bring-to-front signal is emitted right...
[WebKit-https.git] / Source / WebKit / UIProcess / WebInspectorProxy.cpp
1 /*
2  * Copyright (C) 2010-2017 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 #include "APIProcessPoolConfiguration.h"
31 #include "WebAutomationSession.h"
32 #include "WebFrameProxy.h"
33 #include "WebInspectorInterruptDispatcherMessages.h"
34 #include "WebInspectorMessages.h"
35 #include "WebInspectorProxyMessages.h"
36 #include "WebInspectorUIMessages.h"
37 #include "WebPageGroup.h"
38 #include "WebPageProxy.h"
39 #include "WebPreferences.h"
40 #include "WebProcessPool.h"
41 #include "WebProcessProxy.h"
42 #include <WebCore/NotImplemented.h>
43 #include <wtf/SetForScope.h>
44
45 #if PLATFORM(GTK)
46 #include "WebInspectorProxyClient.h"
47 #endif
48
49 using namespace WebCore;
50
51 namespace WebKit {
52
53 const unsigned WebInspectorProxy::minimumWindowWidth = 500;
54 const unsigned WebInspectorProxy::minimumWindowHeight = 400;
55
56 const unsigned WebInspectorProxy::initialWindowWidth = 1000;
57 const unsigned WebInspectorProxy::initialWindowHeight = 650;
58
59 WebInspectorProxy::WebInspectorProxy(WebPageProxy* inspectedPage)
60     : m_inspectedPage(inspectedPage)
61 #if PLATFORM(MAC) && WK_API_ENABLED
62     , m_closeFrontendAfterInactivityTimer(RunLoop::main(), this, &WebInspectorProxy::closeFrontendAfterInactivityTimerFired)
63 #endif
64 {
65     m_inspectedPage->process().addMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID(), *this);
66 }
67
68 WebInspectorProxy::~WebInspectorProxy()
69 {
70 }
71
72 unsigned WebInspectorProxy::inspectionLevel() const
73 {
74     return inspectorLevelForPage(inspectedPage());
75 }
76
77 WebPreferences& WebInspectorProxy::inspectorPagePreferences() const
78 {
79     ASSERT(m_inspectorPage);
80     return m_inspectorPage->pageGroup().preferences();
81 }
82
83 void WebInspectorProxy::invalidate()
84 {
85     m_inspectedPage->process().removeMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID());
86
87     closeFrontendPageAndWindow();
88     platformInvalidate();
89
90     m_inspectedPage = nullptr;
91 }
92
93 // Public APIs
94 bool WebInspectorProxy::isFront()
95 {
96     if (!m_inspectedPage)
97         return false;
98
99     return platformIsFront();
100 }
101
102 void WebInspectorProxy::connect()
103 {
104     if (!m_inspectedPage)
105         return;
106
107     if (m_showMessageSent)
108         return;
109
110     m_showMessageSent = true;
111     m_ignoreFirstBringToFront = true;
112
113     createFrontendPage();
114
115     m_inspectedPage->process().send(Messages::WebInspectorInterruptDispatcher::NotifyNeedDebuggerBreak(), 0);
116     m_inspectedPage->process().send(Messages::WebInspector::Show(), m_inspectedPage->pageID());
117 }
118
119 void WebInspectorProxy::show()
120 {
121     if (!m_inspectedPage)
122         return;
123
124     if (isConnected()) {
125         bringToFront();
126         return;
127     }
128
129     connect();
130
131     // Don't ignore the first bringToFront so it opens the Inspector.
132     m_ignoreFirstBringToFront = false;
133 }
134
135 void WebInspectorProxy::hide()
136 {
137     if (!m_inspectedPage)
138         return;
139
140     m_isVisible = false;
141
142     platformHide();
143 }
144
145 void WebInspectorProxy::close()
146 {
147     if (!m_inspectedPage)
148         return;
149
150     m_inspectedPage->process().send(Messages::WebInspector::Close(), m_inspectedPage->pageID());
151
152     closeFrontendPageAndWindow();
153 }
154
155 void WebInspectorProxy::closeForCrash()
156 {
157     close();
158
159     platformDidCloseForCrash();
160 }
161
162 void WebInspectorProxy::showConsole()
163 {
164     if (!m_inspectedPage)
165         return;
166
167     createFrontendPage();
168
169     m_inspectedPage->process().send(Messages::WebInspector::ShowConsole(), m_inspectedPage->pageID());
170 }
171
172 void WebInspectorProxy::showResources()
173 {
174     if (!m_inspectedPage)
175         return;
176
177     createFrontendPage();
178
179     m_inspectedPage->process().send(Messages::WebInspector::ShowResources(), m_inspectedPage->pageID());
180 }
181
182 void WebInspectorProxy::showTimelines()
183 {
184     if (!m_inspectedPage)
185         return;
186
187     createFrontendPage();
188
189     m_inspectedPage->process().send(Messages::WebInspector::ShowTimelines(), m_inspectedPage->pageID());
190 }
191
192 void WebInspectorProxy::showMainResourceForFrame(WebFrameProxy* frame)
193 {
194     if (!m_inspectedPage)
195         return;
196
197     createFrontendPage();
198
199     m_inspectedPage->process().send(Messages::WebInspector::ShowMainResourceForFrame(frame->frameID()), m_inspectedPage->pageID());
200 }
201
202 void WebInspectorProxy::attachBottom()
203 {
204     attach(AttachmentSide::Bottom);
205 }
206
207 void WebInspectorProxy::attachRight()
208 {
209     attach(AttachmentSide::Right);
210 }
211
212 void WebInspectorProxy::attachLeft()
213 {
214     attach(AttachmentSide::Left);
215 }
216
217 void WebInspectorProxy::attach(AttachmentSide side)
218 {
219     if (!m_inspectedPage || !canAttach())
220         return;
221
222     m_isAttached = true;
223     m_attachmentSide = side;
224
225     inspectorPagePreferences().setInspectorAttachmentSide(static_cast<uint32_t>(side));
226
227     if (m_isVisible)
228         inspectorPagePreferences().setInspectorStartsAttached(true);
229
230     m_inspectedPage->process().send(Messages::WebInspector::SetAttached(true), m_inspectedPage->pageID());
231
232     switch (m_attachmentSide) {
233     case AttachmentSide::Bottom:
234         m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedBottom(), m_inspectorPage->pageID());
235         break;
236
237     case AttachmentSide::Right:
238         m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedRight(), m_inspectorPage->pageID());
239         break;
240
241     case AttachmentSide::Left:
242         m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedLeft(), m_inspectorPage->pageID());
243         break;
244     }
245
246     platformAttach();
247 }
248
249 void WebInspectorProxy::detach()
250 {
251     if (!m_inspectedPage)
252         return;
253
254     m_isAttached = false;
255
256     if (m_isVisible)
257         inspectorPagePreferences().setInspectorStartsAttached(false);
258
259     m_inspectedPage->process().send(Messages::WebInspector::SetAttached(false), m_inspectedPage->pageID());
260     m_inspectorPage->process().send(Messages::WebInspectorUI::Detached(), m_inspectorPage->pageID());
261
262     platformDetach();
263 }
264
265 void WebInspectorProxy::setAttachedWindowHeight(unsigned height)
266 {
267     inspectorPagePreferences().setInspectorAttachedHeight(height);
268     platformSetAttachedWindowHeight(height);
269 }
270
271 void WebInspectorProxy::setAttachedWindowWidth(unsigned width)
272 {
273     inspectorPagePreferences().setInspectorAttachedWidth(width);
274     platformSetAttachedWindowWidth(width);
275 }
276
277 void WebInspectorProxy::startWindowDrag()
278 {
279     platformStartWindowDrag();
280 }
281
282 void WebInspectorProxy::togglePageProfiling()
283 {
284     if (!m_inspectedPage)
285         return;
286
287     if (m_isProfilingPage)
288         m_inspectedPage->process().send(Messages::WebInspector::StopPageProfiling(), m_inspectedPage->pageID());
289     else
290         m_inspectedPage->process().send(Messages::WebInspector::StartPageProfiling(), m_inspectedPage->pageID());
291
292     // FIXME: have the WebProcess notify us on state changes.
293     m_isProfilingPage = !m_isProfilingPage;
294 }
295
296 void WebInspectorProxy::toggleElementSelection()
297 {
298     if (!m_inspectedPage)
299         return;
300
301     if (m_elementSelectionActive) {
302         m_ignoreElementSelectionChange = true;
303         m_inspectedPage->process().send(Messages::WebInspector::StopElementSelection(), m_inspectedPage->pageID());
304     } else {
305         connect();
306         m_inspectedPage->process().send(Messages::WebInspector::StartElementSelection(), m_inspectedPage->pageID());
307     }
308 }
309
310 bool WebInspectorProxy::isMainOrTestInspectorPage(const URL& url)
311 {
312     // Use URL so we can compare the paths and protocols.
313     URL mainPageURL(URL(), WebInspectorProxy::inspectorPageURL());
314     if (url.protocol() == mainPageURL.protocol() && decodeURLEscapeSequences(url.path()) == decodeURLEscapeSequences(mainPageURL.path()))
315         return true;
316
317     // We might not have a Test URL in Production builds.
318     String testPageURLString = WebInspectorProxy::inspectorTestPageURL();
319     if (testPageURLString.isNull())
320         return false;
321
322     URL testPageURL(URL(), testPageURLString);
323     return url.protocol() == testPageURL.protocol() && decodeURLEscapeSequences(url.path()) == decodeURLEscapeSequences(testPageURL.path());
324 }
325
326 void WebInspectorProxy::createFrontendPage()
327 {
328     if (m_inspectorPage)
329         return;
330
331     m_inspectorPage = platformCreateFrontendPage();
332     ASSERT(m_inspectorPage);
333     if (!m_inspectorPage)
334         return;
335
336     trackInspectorPage(m_inspectorPage);
337
338     m_inspectorPage->process().addMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID(), *this);
339     m_inspectorPage->process().assumeReadAccessToBaseURL(WebInspectorProxy::inspectorBaseURL());
340 }
341
342 // Called by WebInspectorProxy messages
343 void WebInspectorProxy::createInspectorPage(IPC::Attachment connectionIdentifier, bool canAttach, bool underTest)
344 {
345     if (!m_inspectedPage)
346         return;
347
348     m_underTest = underTest;
349     createFrontendPage();
350
351     ASSERT(m_inspectorPage);
352     if (!m_inspectorPage)
353         return;
354
355     m_connectionIdentifier = WTFMove(connectionIdentifier);
356
357     m_inspectorPage->process().send(Messages::WebInspectorUI::EstablishConnection(m_connectionIdentifier, m_inspectedPage->pageID(), m_underTest, inspectionLevel()), m_inspectorPage->pageID());
358
359     if (!m_underTest) {
360         m_canAttach = platformCanAttach(canAttach);
361         m_isAttached = shouldOpenAttached();
362         m_attachmentSide = static_cast<AttachmentSide>(inspectorPagePreferences().inspectorAttachmentSide());
363
364         m_inspectedPage->process().send(Messages::WebInspector::SetAttached(m_isAttached), m_inspectedPage->pageID());
365
366         if (m_isAttached) {
367             switch (m_attachmentSide) {
368             case AttachmentSide::Bottom:
369                 m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedBottom(), m_inspectorPage->pageID());
370                 break;
371
372             case AttachmentSide::Right:
373                 m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedRight(), m_inspectorPage->pageID());
374                 break;
375
376             case AttachmentSide::Left:
377                 m_inspectorPage->process().send(Messages::WebInspectorUI::AttachedLeft(), m_inspectorPage->pageID());
378                 break;
379             }
380         } else
381             m_inspectorPage->process().send(Messages::WebInspectorUI::Detached(), m_inspectorPage->pageID());
382
383         m_inspectorPage->process().send(Messages::WebInspectorUI::SetDockingUnavailable(!m_canAttach), m_inspectorPage->pageID());
384     }
385
386     m_inspectorPage->loadRequest(URL(URL(), m_underTest ? WebInspectorProxy::inspectorTestPageURL() : WebInspectorProxy::inspectorPageURL()));
387 }
388
389 void WebInspectorProxy::open()
390 {
391     if (m_underTest)
392         return;
393
394     if (!m_inspectorPage)
395         return;
396
397     SetForScope<bool> isOpening(m_isOpening, true);
398     m_isVisible = true;
399     m_inspectorPage->process().send(Messages::WebInspectorUI::SetIsVisible(m_isVisible), m_inspectorPage->pageID());
400
401     if (m_isAttached)
402         platformAttach();
403     else
404         platformCreateFrontendWindow();
405
406     platformBringToFront();
407 }
408
409 void WebInspectorProxy::didClose()
410 {
411     closeFrontendPageAndWindow();
412 }
413
414 void WebInspectorProxy::closeFrontendPageAndWindow()
415 {
416     if (!m_inspectorPage)
417         return;
418
419     m_isVisible = false;
420     m_isProfilingPage = false;
421     m_showMessageSent = false;
422     m_ignoreFirstBringToFront = false;
423
424     untrackInspectorPage(m_inspectorPage);
425
426     m_inspectorPage->process().send(Messages::WebInspectorUI::SetIsVisible(m_isVisible), m_inspectorPage->pageID());
427     m_inspectorPage->process().removeMessageReceiver(Messages::WebInspectorProxy::messageReceiverName(), m_inspectedPage->pageID());
428
429     if (m_isAttached)
430         platformDetach();
431
432     // Null out m_inspectorPage after platformDetach(), so the views can be cleaned up correctly.
433     m_inspectorPage = nullptr;
434
435     m_isAttached = false;
436     m_canAttach = false;
437     m_underTest = false;
438
439     m_connectionIdentifier = IPC::Attachment();
440
441     platformCloseFrontendPageAndWindow();
442 }
443
444 void WebInspectorProxy::frontendLoaded()
445 {
446     if (auto* automationSession = m_inspectedPage->process().processPool().automationSession())
447         automationSession->inspectorFrontendLoaded(*m_inspectedPage);
448 }
449
450 void WebInspectorProxy::bringToFront()
451 {
452     // WebCore::InspectorFrontendClientLocal tells us to do this on load. We want to
453     // ignore it once if we only wanted to connect. This allows the Inspector to later
454     // request to be brought to the front when a breakpoint is hit or some other action.
455     if (m_ignoreFirstBringToFront) {
456         m_ignoreFirstBringToFront = false;
457         return;
458     }
459
460     if (m_isVisible)
461         platformBringToFront();
462     else
463         open();
464 }
465
466 void WebInspectorProxy::attachAvailabilityChanged(bool available)
467 {
468     bool previousCanAttach = m_canAttach;
469
470     m_canAttach = platformCanAttach(available);
471
472     if (previousCanAttach == m_canAttach)
473         return;
474
475     if (m_inspectorPage && !m_underTest)
476         m_inspectorPage->process().send(Messages::WebInspectorUI::SetDockingUnavailable(!m_canAttach), m_inspectorPage->pageID());
477
478     platformAttachAvailabilityChanged(m_canAttach);
479 }
480
481 void WebInspectorProxy::inspectedURLChanged(const String& urlString)
482 {
483     platformInspectedURLChanged(urlString);
484 }
485
486 void WebInspectorProxy::elementSelectionChanged(bool active)
487 {
488     m_elementSelectionActive = active;
489
490     if (m_ignoreElementSelectionChange) {
491         m_ignoreElementSelectionChange = false;
492         if (!m_isVisible)
493             close();
494         return;
495     }
496
497     if (active)
498         platformBringInspectedPageToFront();
499     else if (isConnected())
500         bringToFront();
501 }
502
503 void WebInspectorProxy::save(const String& filename, const String& content, bool base64Encoded, bool forceSaveAs)
504 {
505     platformSave(filename, content, base64Encoded, forceSaveAs);
506 }
507
508 void WebInspectorProxy::append(const String& filename, const String& content)
509 {
510     platformAppend(filename, content);
511 }
512
513 bool WebInspectorProxy::shouldOpenAttached()
514 {
515     return inspectorPagePreferences().inspectorStartsAttached() && canAttach();
516 }
517
518 // Unsupported configurations can use the stubs provided here.
519
520 #if PLATFORM(IOS) || (PLATFORM(MAC) && !WK_API_ENABLED)
521
522 WebPageProxy* WebInspectorProxy::platformCreateFrontendPage()
523 {
524     notImplemented();
525     return nullptr;
526 }
527
528 void WebInspectorProxy::platformCreateFrontendWindow()
529 {
530     notImplemented();
531 }
532
533 void WebInspectorProxy::platformCloseFrontendPageAndWindow()
534 {
535     notImplemented();
536 }
537
538 void WebInspectorProxy::platformDidCloseForCrash()
539 {
540     notImplemented();
541 }
542
543 void WebInspectorProxy::platformInvalidate()
544 {
545     notImplemented();
546 }
547
548 void WebInspectorProxy::platformBringToFront()
549 {
550     notImplemented();
551 }
552
553 void WebInspectorProxy::platformBringInspectedPageToFront()
554 {
555     notImplemented();
556 }
557
558 void WebInspectorProxy::platformHide()
559 {
560     notImplemented();
561 }
562
563 bool WebInspectorProxy::platformIsFront()
564 {
565     notImplemented();
566     return false;
567 }
568
569 void WebInspectorProxy::platformInspectedURLChanged(const String&)
570 {
571     notImplemented();
572 }
573
574 void WebInspectorProxy::platformSave(const String& suggestedURL, const String& content, bool base64Encoded, bool forceSaveDialog)
575 {
576     notImplemented();
577 }
578
579 void WebInspectorProxy::platformAppend(const String& suggestedURL, const String& content)
580 {
581     notImplemented();
582 }
583
584 unsigned WebInspectorProxy::platformInspectedWindowHeight()
585 {
586     notImplemented();
587     return 0;
588 }
589
590 unsigned WebInspectorProxy::platformInspectedWindowWidth()
591 {
592     notImplemented();
593     return 0;
594 }
595
596 void WebInspectorProxy::platformAttach()
597 {
598     notImplemented();
599 }
600
601 void WebInspectorProxy::platformDetach()
602 {
603     notImplemented();
604 }
605
606 void WebInspectorProxy::platformSetAttachedWindowHeight(unsigned)
607 {
608     notImplemented();
609 }
610
611 void WebInspectorProxy::platformStartWindowDrag()
612 {
613     notImplemented();
614 }
615
616 String WebInspectorProxy::inspectorPageURL()
617 {
618     notImplemented();
619     return String();
620 }
621
622 String WebInspectorProxy::inspectorTestPageURL()
623 {
624     notImplemented();
625     return String();
626 }
627
628 String WebInspectorProxy::inspectorBaseURL()
629 {
630     notImplemented();
631     return String();
632 }
633
634 void WebInspectorProxy::platformSetAttachedWindowWidth(unsigned)
635 {
636     notImplemented();
637 }
638
639 void WebInspectorProxy::platformAttachAvailabilityChanged(bool)
640 {
641     notImplemented();
642 }
643
644 #endif // PLATFORM(IOS) || (PLATFORM(MAC) && !WK_API_ENABLED)
645
646 } // namespace WebKit