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