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