| /* |
| * Copyright (C) 2017 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #import "config.h" |
| #import "WKInspectorViewController.h" |
| |
| #if PLATFORM(MAC) |
| |
| #import "APINavigation.h" |
| #import "VersionChecks.h" |
| #import "WKFrameInfo.h" |
| #import "WKInspectorWKWebView.h" |
| #import "WKNavigationAction.h" |
| #import "WKNavigationDelegate.h" |
| #import "WKOpenPanelParameters.h" |
| #import "WKPreferencesPrivate.h" |
| #import "WKProcessPoolInternal.h" |
| #import "WKUIDelegatePrivate.h" |
| #import "WKWebViewConfigurationPrivate.h" |
| #import "WKWebViewPrivate.h" |
| #import "WebInspectorProxy.h" |
| #import "WebInspectorUtilities.h" |
| #import "WebPageProxy.h" |
| #import <wtf/WeakObjCPtr.h> |
| |
| @interface WKInspectorViewController () <WKUIDelegate, WKNavigationDelegate, WKInspectorWKWebViewDelegate> |
| @end |
| |
| @implementation WKInspectorViewController { |
| WebKit::WebPageProxy* _inspectedPage; |
| RetainPtr<WKInspectorWKWebView> _webView; |
| WeakObjCPtr<id <WKInspectorViewControllerDelegate>> _delegate; |
| } |
| |
| - (instancetype)initWithInspectedPage:(WebKit::WebPageProxy*)inspectedPage |
| { |
| if (!(self = [super init])) |
| return nil; |
| |
| // The (local) inspected page is nil if the controller is hosting a Remote Web Inspector view. |
| _inspectedPage = inspectedPage; |
| |
| return self; |
| } |
| |
| - (void)dealloc |
| { |
| if (_webView) { |
| [_webView setUIDelegate:nil]; |
| [_webView setNavigationDelegate:nil]; |
| [_webView setInspectorWKWebViewDelegate:nil]; |
| _webView = nil; |
| } |
| |
| [super dealloc]; |
| } |
| |
| - (id <WKInspectorViewControllerDelegate>)delegate |
| { |
| return _delegate.getAutoreleased(); |
| } |
| |
| - (WKWebView *)webView |
| { |
| // Construct lazily so the client can set the delegate before the WebView is created. |
| if (!_webView) { |
| NSRect initialFrame = NSMakeRect(0, 0, WebKit::WebInspectorProxy::initialWindowWidth, WebKit::WebInspectorProxy::initialWindowHeight); |
| _webView = adoptNS([[WKInspectorWKWebView alloc] initWithFrame:initialFrame configuration:[self configuration]]); |
| [_webView setUIDelegate:self]; |
| [_webView setNavigationDelegate:self]; |
| [_webView setInspectorWKWebViewDelegate:self]; |
| [_webView _setAutomaticallyAdjustsContentInsets:NO]; |
| [_webView _setUseSystemAppearance:YES]; |
| [_webView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; |
| } |
| |
| return _webView.get(); |
| } |
| |
| - (void)setDelegate:(id <WKInspectorViewControllerDelegate>)delegate |
| { |
| _delegate = delegate; |
| } |
| |
| - (WKWebViewConfiguration *)configuration |
| { |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| |
| WKPreferences *preferences = configuration.get().preferences; |
| preferences._allowFileAccessFromFileURLs = YES; |
| [configuration _setAllowUniversalAccessFromFileURLs:YES]; |
| preferences._storageBlockingPolicy = _WKStorageBlockingPolicyAllowAll; |
| preferences._javaScriptRuntimeFlags = 0; |
| |
| #ifndef NDEBUG |
| // Allow developers to inspect the Web Inspector in debug builds without changing settings. |
| preferences._developerExtrasEnabled = YES; |
| preferences._logsPageMessagesToSystemConsoleEnabled = YES; |
| #endif |
| |
| if (!!_delegate && [_delegate respondsToSelector:@selector(inspectorViewControllerInspectorIsUnderTest:)]) { |
| if ([_delegate inspectorViewControllerInspectorIsUnderTest:self]) { |
| preferences._hiddenPageDOMTimerThrottlingEnabled = NO; |
| preferences._pageVisibilityBasedProcessSuppressionEnabled = NO; |
| } |
| } |
| |
| [configuration setProcessPool:wrapper(WebKit::inspectorProcessPool(WebKit::inspectorLevelForPage(_inspectedPage)))]; |
| [configuration _setGroupIdentifier:WebKit::inspectorPageGroupIdentifierForPage(_inspectedPage)]; |
| |
| return configuration.autorelease(); |
| } |
| |
| + (BOOL)viewIsInspectorWebView:(NSView *)view |
| { |
| return [view isKindOfClass:[WKInspectorWKWebView class]]; |
| } |
| |
| // MARK: WKUIDelegate methods |
| |
| - (void)_webView:(WKWebView *)webView getWindowFrameWithCompletionHandler:(void (^)(CGRect))completionHandler |
| { |
| if (!_webView.get().window) |
| completionHandler(CGRectZero); |
| else |
| completionHandler(NSRectToCGRect([webView frame])); |
| } |
| |
| - (void)_webView:(WKWebView *)webView setWindowFrame:(CGRect)frame |
| { |
| if (!_webView.get().window) |
| return; |
| |
| [_webView.get().window setFrame:NSRectFromCGRect(frame) display:YES]; |
| } |
| |
| - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> *URLs))completionHandler |
| { |
| NSOpenPanel *openPanel = [NSOpenPanel openPanel]; |
| openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection; |
| |
| auto reportSelectedFiles = ^(NSInteger result) { |
| if (result == NSModalResponseOK) |
| completionHandler(openPanel.URLs); |
| else |
| completionHandler(nil); |
| }; |
| |
| if (_webView.get().window) |
| [openPanel beginSheetModalForWindow:_webView.get().window completionHandler:reportSelectedFiles]; |
| else |
| reportSelectedFiles([openPanel runModal]); |
| } |
| |
| - (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 |
| { |
| decisionHandler(std::max<unsigned long long>(expectedUsage, currentUsage * 1.25)); |
| } |
| |
| - (NSMenu *)_webView:(WKWebView *)webView contextMenu:(NSMenu *)menu forElement:(_WKContextMenuElementInfo *)element |
| { |
| for (NSInteger i = menu.numberOfItems - 1; i >= 0; --i) { |
| NSMenuItem *item = [menu itemAtIndex:i]; |
| switch (item.tag) { |
| case kWKContextMenuItemTagOpenLinkInNewWindow: |
| case kWKContextMenuItemTagOpenImageInNewWindow: |
| case kWKContextMenuItemTagOpenFrameInNewWindow: |
| case kWKContextMenuItemTagOpenMediaInNewWindow: |
| case kWKContextMenuItemTagCopyImageUrlToClipboard: |
| case kWKContextMenuItemTagCopyImageToClipboard: |
| case kWKContextMenuItemTagDownloadLinkToDisk: |
| case kWKContextMenuItemTagDownloadImageToDisk: |
| [menu removeItemAtIndex:i]; |
| break; |
| } |
| } |
| |
| return menu; |
| } |
| |
| // MARK: WKNavigationDelegate methods |
| |
| - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView |
| { |
| if (!!_delegate && [_delegate respondsToSelector:@selector(inspectorViewControllerInspectorDidCrash:)]) |
| [_delegate inspectorViewControllerInspectorDidCrash:self]; |
| } |
| |
| - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler |
| { |
| // Allow non-main frames to navigate anywhere. |
| if (!navigationAction.targetFrame.isMainFrame) { |
| decisionHandler(WKNavigationActionPolicyAllow); |
| return; |
| } |
| |
| // Allow loading of the main inspector file. |
| if (WebKit::WebInspectorProxy::isMainOrTestInspectorPage(navigationAction.request.URL)) { |
| decisionHandler(WKNavigationActionPolicyAllow); |
| return; |
| } |
| |
| // Prevent everything else. |
| decisionHandler(WKNavigationActionPolicyCancel); |
| |
| // And instead load it in the inspected page. |
| if (_inspectedPage) |
| _inspectedPage->loadRequest(navigationAction.request); |
| } |
| |
| // MARK: WKInspectorWKWebViewDelegate methods |
| |
| - (void)inspectorWKWebViewReload:(WKInspectorWKWebView *)webView |
| { |
| if (!_inspectedPage) |
| return; |
| |
| OptionSet<WebCore::ReloadOption> reloadOptions; |
| if (WebKit::linkedOnOrAfter(WebKit::SDKVersion::FirstWithExpiredOnlyReloadBehavior)) |
| reloadOptions.add(WebCore::ReloadOption::ExpiredOnly); |
| |
| _inspectedPage->reload(reloadOptions); |
| } |
| |
| - (void)inspectorWKWebViewReloadFromOrigin:(WKInspectorWKWebView *)webView |
| { |
| if (!_inspectedPage) |
| return; |
| |
| _inspectedPage->reload(WebCore::ReloadOption::FromOrigin); |
| } |
| |
| - (void)inspectorWKWebView:(WKInspectorWKWebView *)webView willMoveToWindow:(NSWindow *)newWindow |
| { |
| if (!!_delegate && [_delegate respondsToSelector:@selector(inspectorViewController:willMoveToWindow:)]) |
| [_delegate inspectorViewController:self willMoveToWindow:newWindow]; |
| } |
| |
| - (void)inspectorWKWebViewDidMoveToWindow:(WKInspectorWKWebView *)webView |
| { |
| if (!!_delegate && [_delegate respondsToSelector:@selector(inspectorViewControllerDidMoveToWindow:)]) |
| [_delegate inspectorViewControllerDidMoveToWindow:self]; |
| } |
| |
| @end |
| |
| #endif // PLATFORM(MAC) |