ef5711c097da74fbecca45e8c1de1dd5b5a2a8b8
[WebKit-https.git] / Source / WebKit / UIProcess / mac / RemoteWebInspectorProxyMac.mm
1 /*
2  * Copyright (C) 2010-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "RemoteWebInspectorProxy.h"
28
29 #if PLATFORM(MAC) && WK_API_ENABLED
30
31 #import "RemoteWebInspectorProxyMessages.h"
32 #import "RemoteWebInspectorUIMessages.h"
33 #import "WKFrameInfo.h"
34 #import "WKNavigationAction.h"
35 #import "WKNavigationDelegate.h"
36 #import "WKWebInspectorWKWebView.h"
37 #import "WKWebViewInternal.h"
38 #import "WebInspectorProxy.h"
39 #import "WebPageGroup.h"
40 #import "WebPageProxy.h"
41 #import <wtf/text/Base64.h>
42
43 using namespace WebKit;
44
45 @interface WKRemoteWebInspectorProxyObjCAdapter : NSObject <WKNavigationDelegate> {
46     RemoteWebInspectorProxy* _inspectorProxy;
47 }
48 - (instancetype)initWithRemoteWebInspectorProxy:(RemoteWebInspectorProxy*)inspectorProxy;
49 @end
50
51 @implementation WKRemoteWebInspectorProxyObjCAdapter
52
53 - (instancetype)initWithRemoteWebInspectorProxy:(RemoteWebInspectorProxy*)inspectorProxy
54 {
55     if (!(self = [super init]))
56         return nil;
57
58     _inspectorProxy = inspectorProxy;
59
60     return self;
61 }
62
63 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
64 {
65     _inspectorProxy->closeFromCrash();
66 }
67
68 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
69 {
70     // Allow non-main frames to navigate anywhere.
71     if (!navigationAction.targetFrame.isMainFrame) {
72         decisionHandler(WKNavigationActionPolicyAllow);
73         return;
74     }
75
76     // Allow loading of the main inspector file.
77     if (WebInspectorProxy::isMainOrTestInspectorPage(navigationAction.request.URL)) {
78         decisionHandler(WKNavigationActionPolicyAllow);
79         return;
80     }
81
82     // Prevent everything else.
83     decisionHandler(WKNavigationActionPolicyCancel);
84 }
85
86 @end
87
88 namespace WebKit {
89
90 WebPageProxy* RemoteWebInspectorProxy::platformCreateFrontendPageAndWindow()
91 {
92     NSRect initialFrame = NSMakeRect(0, 0, WebInspectorProxy::initialWindowWidth, WebInspectorProxy::initialWindowHeight);
93     auto configuration = WebInspectorProxy::createFrontendConfiguration(nullptr, false);
94
95     m_objCAdapter = adoptNS([[WKRemoteWebInspectorProxyObjCAdapter alloc] initWithRemoteWebInspectorProxy:this]);
96
97     m_webView = adoptNS([[WKWebInspectorWKWebView alloc] initWithFrame:initialFrame configuration:configuration.get()]);
98     [m_webView setNavigationDelegate:m_objCAdapter.get()];
99
100     m_window = WebInspectorProxy::createFrontendWindow(NSZeroRect);
101
102     NSView *contentView = [m_window contentView];
103     [m_webView setFrame:[contentView bounds]];
104     [m_webView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
105     [contentView addSubview:m_webView.get()];
106
107     return m_webView->_page.get();
108 }
109
110 void RemoteWebInspectorProxy::platformCloseFrontendPageAndWindow()
111 {
112     if (m_window) {
113         [m_window setDelegate:nil];
114         [m_window close];
115         m_window = nil;
116     }
117
118     if (m_webView) {
119         WebPageProxy* inspectorPage = m_webView->_page.get();
120         inspectorPage->close();
121         [m_webView setNavigationDelegate:nil];
122         m_webView = nil;
123     }
124
125     if (m_objCAdapter)
126         m_objCAdapter = nil;
127 }
128
129
130 void RemoteWebInspectorProxy::platformBringToFront()
131 {
132     [m_window makeKeyAndOrderFront:nil];
133     [m_window makeFirstResponder:m_webView.get()];
134 }
135
136 void RemoteWebInspectorProxy::platformSave(const String& suggestedURL, const String& content, bool base64Encoded, bool forceSaveDialog)
137 {
138     // FIXME: Share with WebInspectorProxyMac.
139
140     ASSERT(!suggestedURL.isEmpty());
141     
142     NSURL *platformURL = m_suggestedToActualURLMap.get(suggestedURL).get();
143     if (!platformURL) {
144         platformURL = [NSURL URLWithString:suggestedURL];
145         // The user must confirm new filenames before we can save to them.
146         forceSaveDialog = true;
147     }
148     
149     ASSERT(platformURL);
150     if (!platformURL)
151         return;
152
153     // Necessary for the block below.
154     String suggestedURLCopy = suggestedURL;
155     String contentCopy = content;
156
157     auto saveToURL = ^(NSURL *actualURL) {
158         ASSERT(actualURL);
159
160         m_suggestedToActualURLMap.set(suggestedURLCopy, actualURL);
161
162         if (base64Encoded) {
163             Vector<char> out;
164             if (!base64Decode(contentCopy, out, Base64ValidatePadding))
165                 return;
166             RetainPtr<NSData> dataContent = adoptNS([[NSData alloc] initWithBytes:out.data() length:out.size()]);
167             [dataContent writeToURL:actualURL atomically:YES];
168         } else
169             [contentCopy writeToURL:actualURL atomically:YES encoding:NSUTF8StringEncoding error:NULL];
170
171         WebPageProxy* inspectorPage = m_webView->_page.get();
172         inspectorPage->process().send(Messages::RemoteWebInspectorUI::DidSave([actualURL absoluteString]), inspectorPage->pageID());
173     };
174
175     if (!forceSaveDialog) {
176         saveToURL(platformURL);
177         return;
178     }
179
180     NSSavePanel *panel = [NSSavePanel savePanel];
181     panel.nameFieldStringValue = platformURL.lastPathComponent;
182
183     // If we have a file URL we've already saved this file to a path and
184     // can provide a good directory to show. Otherwise, use the system's
185     // default behavior for the initial directory to show in the dialog.
186     if (platformURL.isFileURL)
187         panel.directoryURL = [platformURL URLByDeletingLastPathComponent];
188
189     auto completionHandler = ^(NSInteger result) {
190         if (result == NSModalResponseCancel)
191             return;
192         ASSERT(result == NSModalResponseOK);
193         saveToURL(panel.URL);
194     };
195
196     if (m_window)
197         [panel beginSheetModalForWindow:m_window.get() completionHandler:completionHandler];
198     else
199         completionHandler([panel runModal]);
200 }
201
202 void RemoteWebInspectorProxy::platformAppend(const String& suggestedURL, const String& content)
203 {
204     // FIXME: Share with WebInspectorProxyMac.
205
206     ASSERT(!suggestedURL.isEmpty());
207     
208     RetainPtr<NSURL> actualURL = m_suggestedToActualURLMap.get(suggestedURL);
209     // Do not append unless the user has already confirmed this filename in save().
210     if (!actualURL)
211         return;
212
213     NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:actualURL.get() error:NULL];
214     [handle seekToEndOfFile];
215     [handle writeData:[content dataUsingEncoding:NSUTF8StringEncoding]];
216     [handle closeFile];
217
218     WebPageProxy* inspectorPage = m_webView->_page.get();
219     inspectorPage->process().send(Messages::RemoteWebInspectorUI::DidAppend([actualURL absoluteString]), inspectorPage->pageID());
220 }
221
222 void RemoteWebInspectorProxy::platformStartWindowDrag()
223 {
224     m_webView->_page->startWindowDrag();
225 }
226
227 void RemoteWebInspectorProxy::platformOpenInNewTab(const String& url)
228 {
229     [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]];
230 }
231
232 } // namespace WebKit
233
234 #endif