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