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