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