Replace OptionSet |= and -= operators with add() and remove() functions
[WebKit-https.git] / Source / WebKit / UIProcess / mac / WKInspectorViewController.mm
1 /*
2  * Copyright (C) 2017 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 "WKInspectorViewController.h"
28
29 #if PLATFORM(MAC) && WK_API_ENABLED
30
31 #import "APINavigation.h"
32 #import "VersionChecks.h"
33 #import "WKFrameInfo.h"
34 #import "WKInspectorWKWebView.h"
35 #import "WKNavigationAction.h"
36 #import "WKNavigationDelegate.h"
37 #import "WKOpenPanelParameters.h"
38 #import "WKPreferencesPrivate.h"
39 #import "WKProcessPoolInternal.h"
40 #import "WKUIDelegatePrivate.h"
41 #import "WKWebViewConfigurationPrivate.h"
42 #import "WKWebViewPrivate.h"
43 #import "WebInspectorProxy.h"
44 #import "WebInspectorUtilities.h"
45 #import "WebPageProxy.h"
46 #import <wtf/WeakObjCPtr.h>
47
48 @interface WKInspectorViewController () <WKUIDelegate, WKNavigationDelegate, WKInspectorWKWebViewDelegate>
49 @end
50
51 @implementation WKInspectorViewController {
52     WebKit::WebPageProxy* _inspectedPage;
53     RetainPtr<WKInspectorWKWebView> _webView;
54     WeakObjCPtr<id <WKInspectorViewControllerDelegate>> _delegate;
55 }
56
57 - (instancetype)initWithInspectedPage:(WebKit::WebPageProxy*)inspectedPage
58 {
59     if (!(self = [super init]))
60         return nil;
61
62     // The (local) inspected page is nil if the controller is hosting a Remote Web Inspector view.
63     _inspectedPage = inspectedPage;
64
65     return self;
66 }
67
68 - (void)dealloc
69 {
70     if (_webView) {
71         [_webView setUIDelegate:nil];
72         [_webView setNavigationDelegate:nil];
73         [_webView setInspectorWKWebViewDelegate:nil];
74         _webView = nil;
75     }
76
77     [super dealloc];
78 }
79
80 - (id <WKInspectorViewControllerDelegate>)delegate
81 {
82     return _delegate.getAutoreleased();
83 }
84
85 - (WKWebView *)webView
86 {
87     // Construct lazily so the client can set the delegate before the WebView is created.
88     if (!_webView) {
89         NSRect initialFrame = NSMakeRect(0, 0, WebKit::WebInspectorProxy::initialWindowWidth, WebKit::WebInspectorProxy::initialWindowHeight);
90         _webView = adoptNS([[WKInspectorWKWebView alloc] initWithFrame:initialFrame configuration:[self configuration]]);
91         [_webView setUIDelegate:self];
92         [_webView setNavigationDelegate:self];
93         [_webView setInspectorWKWebViewDelegate:self];
94         [_webView _setAutomaticallyAdjustsContentInsets:NO];
95         [_webView _setUseSystemAppearance:YES];
96         [_webView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
97     }
98
99     return _webView.get();
100 }
101
102 - (void)setDelegate:(id <WKInspectorViewControllerDelegate>)delegate
103 {
104     _delegate = delegate;
105 }
106
107 - (WKWebViewConfiguration *)configuration
108 {
109     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
110
111     WKPreferences *preferences = configuration.get().preferences;
112     preferences._allowFileAccessFromFileURLs = YES;
113     [configuration _setAllowUniversalAccessFromFileURLs:YES];
114     preferences._storageBlockingPolicy = _WKStorageBlockingPolicyAllowAll;
115     preferences._javaScriptRuntimeFlags = 0;
116
117 #ifndef NDEBUG
118     // Allow developers to inspect the Web Inspector in debug builds without changing settings.
119     preferences._developerExtrasEnabled = YES;
120     preferences._logsPageMessagesToSystemConsoleEnabled = YES;
121 #endif
122
123     if (!!_delegate && [_delegate respondsToSelector:@selector(inspectorViewControllerInspectorIsUnderTest:)]) {
124         if ([_delegate inspectorViewControllerInspectorIsUnderTest:self]) {
125             preferences._hiddenPageDOMTimerThrottlingEnabled = NO;
126             preferences._pageVisibilityBasedProcessSuppressionEnabled = NO;
127         }
128     }
129
130     [configuration setProcessPool:wrapper(WebKit::inspectorProcessPool(WebKit::inspectorLevelForPage(_inspectedPage)))];
131     [configuration _setGroupIdentifier:WebKit::inspectorPageGroupIdentifierForPage(_inspectedPage)];
132
133     return configuration.autorelease();
134 }
135
136 + (BOOL)viewIsInspectorWebView:(NSView *)view
137 {
138     return [view isKindOfClass:[WKInspectorWKWebView class]];
139 }
140
141 // MARK: WKUIDelegate methods
142
143 - (void)_webView:(WKWebView *)webView getWindowFrameWithCompletionHandler:(void (^)(CGRect))completionHandler
144 {
145     if (!_webView.get().window)
146         completionHandler(CGRectZero);
147     else
148         completionHandler(NSRectToCGRect([webView frame]));
149 }
150
151 - (void)_webView:(WKWebView *)webView setWindowFrame:(CGRect)frame
152 {
153     if (!_webView.get().window)
154         return;
155
156     [_webView.get().window setFrame:NSRectFromCGRect(frame) display:YES];
157 }
158
159 - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> *URLs))completionHandler
160 {
161     NSOpenPanel *openPanel = [NSOpenPanel openPanel];
162     openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection;
163
164     auto reportSelectedFiles = ^(NSInteger result) {
165         if (result == NSModalResponseOK)
166             completionHandler(openPanel.URLs);
167         else
168             completionHandler(nil);
169     };
170
171     if (_webView.get().window)
172         [openPanel beginSheetModalForWindow:_webView.get().window completionHandler:reportSelectedFiles];
173     else
174         reportSelectedFiles([openPanel runModal]);
175 }
176
177 - (void)_webView:(WKWebView *)webView decideDatabaseQuotaForSecurityOrigin:(WKSecurityOrigin *)securityOrigin currentQuota:(unsigned long long)currentQuota currentOriginUsage:(unsigned long long)currentOriginUsage currentDatabaseUsage:(unsigned long long)currentUsage expectedUsage:(unsigned long long)expectedUsage decisionHandler:(void (^)(unsigned long long newQuota))decisionHandler
178 {
179     decisionHandler(std::max<unsigned long long>(expectedUsage, currentUsage * 1.25));
180 }
181
182 - (NSMenu *)_webView:(WKWebView *)webView contextMenu:(NSMenu *)menu forElement:(_WKContextMenuElementInfo *)element
183 {
184     for (NSInteger i = menu.numberOfItems - 1; i >= 0; --i) {
185         NSMenuItem *item = [menu itemAtIndex:i];
186         switch (item.tag) {
187         case kWKContextMenuItemTagOpenLinkInNewWindow:
188         case kWKContextMenuItemTagOpenImageInNewWindow:
189         case kWKContextMenuItemTagOpenFrameInNewWindow:
190         case kWKContextMenuItemTagOpenMediaInNewWindow:
191         case kWKContextMenuItemTagCopyImageUrlToClipboard:
192         case kWKContextMenuItemTagCopyImageToClipboard:
193         case kWKContextMenuItemTagDownloadLinkToDisk:
194         case kWKContextMenuItemTagDownloadImageToDisk:
195             [menu removeItemAtIndex:i];
196             break;
197         }
198     }
199
200     return menu;
201 }
202
203 // MARK: WKNavigationDelegate methods
204
205 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
206 {
207     if (!!_delegate && [_delegate respondsToSelector:@selector(inspectorViewControllerInspectorDidCrash:)])
208         [_delegate inspectorViewControllerInspectorDidCrash:self];
209 }
210
211 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
212 {
213     // Allow non-main frames to navigate anywhere.
214     if (!navigationAction.targetFrame.isMainFrame) {
215         decisionHandler(WKNavigationActionPolicyAllow);
216         return;
217     }
218
219     // Allow loading of the main inspector file.
220     if (WebKit::WebInspectorProxy::isMainOrTestInspectorPage(navigationAction.request.URL)) {
221         decisionHandler(WKNavigationActionPolicyAllow);
222         return;
223     }
224
225     // Prevent everything else.
226     decisionHandler(WKNavigationActionPolicyCancel);
227     
228     // And instead load it in the inspected page.
229     _inspectedPage->loadRequest(navigationAction.request);
230 }
231
232 // MARK: WKInspectorWKWebViewDelegate methods
233
234 - (void)inspectorWKWebViewReload:(WKInspectorWKWebView *)webView
235 {
236     if (!_inspectedPage)
237         return;
238
239     OptionSet<WebCore::ReloadOption> reloadOptions;
240     if (WebKit::linkedOnOrAfter(WebKit::SDKVersion::FirstWithExpiredOnlyReloadBehavior))
241         reloadOptions.add(WebCore::ReloadOption::ExpiredOnly);
242
243     _inspectedPage->reload(reloadOptions);
244 }
245
246 - (void)inspectorWKWebViewReloadFromOrigin:(WKInspectorWKWebView *)webView
247 {
248     if (!_inspectedPage)
249         return;
250
251     _inspectedPage->reload(WebCore::ReloadOption::FromOrigin);
252 }
253
254 @end
255
256 #endif // PLATFORM(MAC) && WK_API_ENABLED