Commit 63df54ea authored by Mike Dougherty's avatar Mike Dougherty Committed by Commit Bot

Cleanup CRWContextMenuController

CRWContextMenuController was previously used with WKWebViews which were
not associated with a WebState. This added complexity to the context
menu feature which is no longer necessary.

Bug: None
Change-Id: I8c07675da49dd0a9cf07b14e9b14ce73d14c9ebd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2523754
Commit-Queue: Mike Dougherty <michaeldo@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827849}
parent c8615ee9
......@@ -8,7 +8,6 @@
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
@protocol CRWContextMenuDelegate;
@class WKWebView;
namespace web {
......@@ -35,19 +34,6 @@ WKWebView* BuildWKWebView(CGRect frame, BrowserState* browser_state);
//
WKWebView* BuildWKWebViewForQueries(BrowserState* browser_state);
// Returns a new WKWebView for displaying regular web content.
// The returned WKWebView is equivalent to the one created by |BuildWKWebView|
// but a context menu recognizer is attached to it.
// On a long press, context_menu_delegate webView:handleContextMenu:| is called.
// The custom context menu involves gesture recognizers on every touch and
// JavaScript. It can have impact on performances.
// Calling |BuildWKWebViewWithCustomContextMenu| with a |context_menu_delegate|
// nil is equivalent to |BuildWKWebView|.
WKWebView* BuildWKWebViewWithCustomContextMenu(
CGRect frame,
BrowserState* browser_state,
id<CRWContextMenuDelegate> context_menu_delegate);
} // web
#endif // IOS_WEB_COMMON_WEB_VIEW_CREATION_UTIL_H_
......@@ -16,29 +16,21 @@
namespace web {
WKWebView* BuildWKWebView(CGRect frame, BrowserState* browser_state) {
return BuildWKWebViewWithCustomContextMenu(frame, browser_state, nil);
}
WKWebView* BuildWKWebViewForQueries(BrowserState* browser_state) {
DCHECK(browser_state);
WKWebViewConfigurationProvider& config_provider =
WKWebViewConfigurationProvider::FromBrowserState(browser_state);
return BuildWKWebViewForQueries(config_provider.GetWebViewConfiguration(),
browser_state);
return BuildWKWebView(frame, config_provider.GetWebViewConfiguration(),
browser_state, UserAgentType::MOBILE);
}
WKWebView* BuildWKWebViewWithCustomContextMenu(
CGRect frame,
BrowserState* browser_state,
id<CRWContextMenuDelegate> context_menu_delegate) {
WKWebView* BuildWKWebViewForQueries(BrowserState* browser_state) {
DCHECK(browser_state);
WKWebViewConfigurationProvider& config_provider =
WKWebViewConfigurationProvider::FromBrowserState(browser_state);
return BuildWKWebView(frame, config_provider.GetWebViewConfiguration(),
browser_state, UserAgentType::MOBILE,
context_menu_delegate);
return BuildWKWebViewForQueries(config_provider.GetWebViewConfiguration(),
browser_state);
}
} // namespace web
......@@ -96,16 +96,15 @@ source_set("crw_context_menu_controller") {
"//base",
"//ios/web/js_messaging",
"//ios/web/public",
"//ios/web/public/deprecated",
"//ios/web/public/js_messaging",
"//ios/web/web_state:context_menu",
"//ios/web/web_state:web_state_impl_header",
"//ios/web/web_state/ui:wk_web_view_configuration_provider",
"//ui/base",
]
sources = [
"crw_context_menu_controller.h",
"crw_context_menu_controller.mm",
"crw_context_menu_delegate.h",
"html_element_fetch_request.h",
"html_element_fetch_request.mm",
]
......
......@@ -9,12 +9,9 @@
#import <WebKit/WebKit.h>
namespace web {
class BrowserState;
class WebState;
class WebStateImpl;
} // namespace web
@protocol CRWContextMenuDelegate;
// A controller that will recognise context menu gesture on |webView|. This
// controller will rely on a long press gesture recognizer and JavaScript to
// determine the element on which context menu is triggered.
......@@ -28,18 +25,11 @@ class WebState;
// - This class will perform gesture recognition and JavaScript on every touch
// event on |webView| and can have performance impact.
- (instancetype)initWithWebView:(WKWebView*)webView
browserState:(web::BrowserState*)browserState
delegate:(id<CRWContextMenuDelegate>)delegate
webState:(web::WebStateImpl*)webState
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// WebState associated with this controller.
// When the |webState| is set, the WKWebView default context menu gesture
// recognizer is overridden after each navigation. If it is never set, the
// default gesture recognizer is only overridden in this object -init method.
@property(nonatomic, assign) web::WebState* webState;
// By default, this controller "hooks" long touches to suppress the system
// default behavior (which shows the system context menu) and show its own
// context menu instead. This method disables the hook for the current on-going
......
......@@ -13,7 +13,10 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/sys_string_conversions.h"
#include "base/unguessable_token.h"
#include "base/values.h"
#import "ios/web/js_messaging/crw_wk_script_message_router.h"
#import "ios/web/public/js_messaging/web_frame.h"
#import "ios/web/public/js_messaging/web_frame_util.h"
#import "ios/web/public/navigation/navigation_context.h"
#import "ios/web/public/ui/context_menu_params.h"
#include "ios/web/public/web_client.h"
......@@ -21,10 +24,9 @@
#import "ios/web/public/web_state_observer_bridge.h"
#import "ios/web/web_state/context_menu_constants.h"
#import "ios/web/web_state/context_menu_params_utils.h"
#import "ios/web/web_state/ui/crw_context_menu_delegate.h"
#import "ios/web/web_state/ui/html_element_fetch_request.h"
#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
#include "ui/base/device_form_factor.h"
#import "ios/web/web_state/web_state_impl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -52,6 +54,9 @@ void CancelTouches(UIGestureRecognizer* gesture_recognizer) {
}
}
// Javascript function name to obtain element details at a point.
const char kFindElementAtPointFunctionName[] = "findElementAtPoint";
// JavaScript message handler name installed in WKWebView for found element
// response.
NSString* const kFindElementResultHandlerName = @"FindElementResultHandler";
......@@ -172,10 +177,10 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
// The |webView|.
@property(nonatomic, readonly, weak) WKWebView* webView;
// The scroll view of |webView|.
@property(nonatomic, readonly, weak) id<CRWContextMenuDelegate> delegate;
// Returns the x, y offset the content has been scrolled.
@property(nonatomic, readonly) CGPoint scrollPosition;
// WebState associated with this controller.
@property(nonatomic, assign) web::WebStateImpl* webState;
// Called when the |_contextMenuRecognizer| finishes recognizing a long press.
- (void)longPressDetectedByGestureRecognizer:
......@@ -203,10 +208,6 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
// Cancels the display of the context menu and clears associated element fetch
// request state.
- (void)cancelContextMenuDisplay;
// Forwards the execution of |script| to |javaScriptDelegate| and if it is nil,
// to |webView|.
- (void)executeJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler;
@end
@implementation CRWContextMenuController {
......@@ -234,19 +235,20 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
NSMutableDictionary* _pendingElementFetchRequests;
}
@synthesize delegate = _delegate;
@synthesize webView = _webView;
- (instancetype)initWithWebView:(WKWebView*)webView
browserState:(web::BrowserState*)browserState
delegate:(id<CRWContextMenuDelegate>)delegate {
webState:(web::WebStateImpl*)webState {
DCHECK(webView);
self = [super init];
if (self) {
_webView = webView;
_delegate = delegate;
_pendingElementFetchRequests = [[NSMutableDictionary alloc] init];
_webState = webState;
_observer = std::make_unique<web::WebStateObserverBridge>(self);
webState->AddObserver(_observer.get());
// If system context menu is enabled, the recognizer below will not be
// triggered.
_systemContextMenuEnabled =
......@@ -274,7 +276,8 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
// Listen for fetched element response.
web::WKWebViewConfigurationProvider& configurationProvider =
web::WKWebViewConfigurationProvider::FromBrowserState(browserState);
web::WKWebViewConfigurationProvider::FromBrowserState(
webState->GetBrowserState());
CRWWKScriptMessageRouter* messageRouter =
configurationProvider.GetScriptMessageRouter();
__weak CRWContextMenuController* weakSelf = self;
......@@ -288,21 +291,8 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
}
- (void)dealloc {
if (_webState)
_webState->RemoveObserver(_observer.get());
}
- (void)setWebState:(web::WebState*)webState {
if (_webState)
_webState->RemoveObserver(_observer.get());
_webState = webState;
_observer.reset();
if (webState) {
_observer = std::make_unique<web::WebStateObserverBridge>(self);
webState->AddObserver(_observer.get());
}
if (self.webState)
self.webState->RemoveObserver(_observer.get());
}
- (void)allowSystemUIForCurrentGesture {
......@@ -320,19 +310,6 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
return self.webScrollView.contentOffset;
}
- (void)executeJavaScript:(NSString*)script
completionHandler:(void (^)(id, NSError*))completionHandler {
if ([_delegate respondsToSelector:@selector
(webView:executeJavaScript:completionHandler:)]) {
[_delegate webView:self.webView
executeJavaScript:script
completionHandler:completionHandler];
} else {
[self.webView evaluateJavaScript:script
completionHandler:completionHandler];
}
}
- (void)longPressDetectedByGestureRecognizer:
(UIGestureRecognizer*)gestureRecognizer {
switch (gestureRecognizer.state) {
......@@ -396,14 +373,16 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
// intentionally suppress system context menu UI.
[self cancelAllTouches];
if ([_delegate respondsToSelector:@selector(webView:handleContextMenu:)]) {
_contextMenuInfoForLastTouch.location =
[_contextMenuRecognizer locationInView:_webView];
[self showContextMenu];
}
_contextMenuInfoForLastTouch.location =
[_contextMenuRecognizer locationInView:_webView];
[self showContextMenu];
}
- (void)showContextMenu {
if (!self.webState) {
return;
}
// Log if the element is in the main frame or a child frame.
UMA_HISTOGRAM_ENUMERATION("ContextMenu.DOMElementFrame",
(_contextMenuInfoForLastTouch.is_main_frame
......@@ -416,7 +395,8 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
params.view = _webView;
params.location = _contextMenuInfoForLastTouch.location;
params.is_main_frame = _contextMenuInfoForLastTouch.is_main_frame;
[_delegate webView:_webView handleContextMenu:params];
self.webState->HandleContextMenu(params);
}
- (void)cancelAllTouches {
......@@ -536,32 +516,39 @@ void OverrideGestureRecognizers(UIGestureRecognizer* contextMenuRecognizer,
- (void)fetchDOMElementAtPoint:(CGPoint)point
completionHandler:(void (^)(NSDictionary*))handler {
if (!self.webState) {
return;
}
web::WebFrame* frame = GetMainFrame(self.webState);
if (!frame) {
// A WebFrame may not exist for certain types of content, like PDFs.
return;
}
DCHECK(handler);
CGPoint scrollOffset = self.scrollPosition;
CGSize webViewContentSize = self.webScrollView.contentSize;
CGFloat webViewContentWidth = webViewContentSize.width;
CGFloat webViewContentHeight = webViewContentSize.height;
NSString* requestID =
base::SysUTF8ToNSString(base::UnguessableToken::Create().ToString());
std::string requestID = base::UnguessableToken::Create().ToString();
HTMLElementFetchRequest* fetchRequest =
[[HTMLElementFetchRequest alloc] initWithFoundElementHandler:handler];
_pendingElementFetchRequests[requestID] = fetchRequest;
NSString* formatString = [NSString
stringWithFormat:
@"__gCrWeb.findElementAtPoint('%@', %%g, %%g, %%g, %%g);", requestID];
NSString* getElementScript =
[NSString stringWithFormat:formatString, point.x + scrollOffset.x,
point.y + scrollOffset.y, webViewContentWidth,
webViewContentHeight];
[self executeJavaScript:getElementScript completionHandler:nil];
_pendingElementFetchRequests[base::SysUTF8ToNSString(requestID)] =
fetchRequest;
CGSize webViewContentSize = self.webScrollView.contentSize;
std::vector<base::Value> args;
args.push_back(base::Value(requestID));
args.push_back(base::Value(point.x + self.scrollPosition.x));
args.push_back(base::Value(point.y + self.scrollPosition.y));
args.push_back(base::Value(webViewContentSize.width));
args.push_back(base::Value(webViewContentSize.height));
frame->CallJavaScriptFunction(std::string(kFindElementAtPointFunctionName),
args);
}
#pragma mark - CRWWebStateObserver
- (void)webStateDestroyed:(web::WebState*)webState {
if (self.webState)
self.webState->RemoveObserver(_observer.get());
self.webState = nullptr;
}
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_WEB_WEB_STATE_UI_CRW_CONTEXT_MENU_DELEGATE_H_
#define IOS_WEB_WEB_STATE_UI_CRW_CONTEXT_MENU_DELEGATE_H_
#import <WebKit/WebKit.h>
#import "ios/web/public/ui/context_menu_params.h"
// Implement this protocol to listen to the custom context menu trigger from
// WKWebView.
@protocol CRWContextMenuDelegate <NSObject>
// Called when the custom Context menu recognizer triggers on |webView| by a
// long press gesture. The system context menu will be suppressed.
- (void)webView:(WKWebView*)webView
handleContextMenu:(const web::ContextMenuParams&)params;
@optional
// Called to execute JavaScript in |webView|. The |completionHandler| must be
// called with the result of executing |javaScript|. The JavaScript will be
// executed directly on |webView| if this method is not implemented.
- (void)webView:(WKWebView*)webView
executeJavaScript:(NSString*)javaScript
completionHandler:(void (^)(id, NSError*))completionHandler;
@end
#endif // IOS_WEB_WEB_STATE_UI_CRW_CONTEXT_MENU_DELEGATE_H_
......@@ -45,7 +45,6 @@
#import "ios/web/web_state/page_viewport_state.h"
#import "ios/web/web_state/ui/cookie_blocking_error_logger.h"
#import "ios/web/web_state/ui/crw_context_menu_controller.h"
#import "ios/web/web_state/ui/crw_context_menu_delegate.h"
#import "ios/web/web_state/ui/crw_swipe_recognizer_provider.h"
#import "ios/web/web_state/ui/crw_web_controller_container_view.h"
#import "ios/web/web_state/ui/crw_web_request_controller.h"
......@@ -93,7 +92,6 @@ NSString* const kSessionRestoreScriptMessageName = @"session_restore";
} // namespace
@interface CRWWebController () <CRWWKNavigationHandlerDelegate,
CRWContextMenuDelegate,
CRWJSInjectorDelegate,
CRWSSLStatusUpdaterDataSource,
CRWSSLStatusUpdaterDelegate,
......@@ -1532,12 +1530,9 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
requireGestureRecognizerToFail:swipeRecognizer];
}
web::BrowserState* browserState = self.webStateImpl->GetBrowserState();
self.UIHandler.contextMenuController =
[[CRWContextMenuController alloc] initWithWebView:self.webView
browserState:browserState
delegate:self];
self.UIHandler.contextMenuController.webState = self.webStateImpl;
webState:self.webStateImpl];
// WKWebViews with invalid or empty frames have exhibited rendering bugs, so
// resize the view to match the container view upon creation.
......@@ -1665,24 +1660,6 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
self.webStateImpl->DidChangeVisibleSecurityState();
}
#pragma mark - CRWContextMenuDelegate methods
- (void)webView:(WKWebView*)webView
handleContextMenu:(const web::ContextMenuParams&)params {
DCHECK(webView == self.webView);
if (_isBeingDestroyed) {
return;
}
self.webStateImpl->HandleContextMenu(params);
}
- (void)webView:(WKWebView*)webView
executeJavaScript:(NSString*)javaScript
completionHandler:(void (^)(id, NSError*))completionHandler {
[_jsInjector executeJavaScript:javaScript
completionHandler:completionHandler];
}
#pragma mark - CRWJSInjectorDelegate methods
- (GURL)lastCommittedURLForJSInjector:(CRWJSInjector*)injector {
......
......@@ -10,8 +10,6 @@
#include "ios/web/common/user_agent.h"
@protocol CRWContextMenuDelegate;
// This file is a collection of functions that vend web views.
namespace web {
class BrowserState;
......@@ -27,21 +25,6 @@ class BrowserState;
WKWebView* BuildWKWebViewForQueries(WKWebViewConfiguration* configuration,
BrowserState* browser_state);
// Creates a new WKWebView for displaying regular web content and registers a
// user agent for it.
//
// Preconditions for creation of a WKWebView:
// 1) |browser_state|, |configuration| are not null.
// 2) web::BrowsingDataPartition is synchronized.
// 3) The WKProcessPool of the configuration is the same as the WKProcessPool
// of the WKWebViewConfiguration associated with |browser_state|.
//
WKWebView* BuildWKWebView(CGRect frame,
WKWebViewConfiguration* configuration,
BrowserState* browser_state,
UserAgentType user_agent_type,
id<CRWContextMenuDelegate> context_menu_delegate);
// Creates and returns a new WKWebView for displaying regular web content.
// The preconditions for the creation of a WKWebView are the same as the
// previous method.
......
......@@ -4,8 +4,6 @@
#import "ios/web/web_state/web_view_internal_creation_util.h"
#import <objc/runtime.h>
#include "base/check_op.h"
#include "base/strings/sys_string_conversions.h"
#import "ios/web/public/web_client.h"
......@@ -46,8 +44,7 @@ WKWebView* BuildWKWebViewForQueries(WKWebViewConfiguration* configuration,
WKWebView* BuildWKWebView(CGRect frame,
WKWebViewConfiguration* configuration,
BrowserState* browser_state,
UserAgentType user_agent_type,
id<CRWContextMenuDelegate> context_menu_delegate) {
UserAgentType user_agent_type) {
VerifyWKWebViewCreationPreConditions(browser_state, configuration);
GetWebClient()->PreWebViewCreation();
......@@ -65,18 +62,6 @@ WKWebView* BuildWKWebView(CGRect frame,
// reasonable value.
web_view.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
if (context_menu_delegate) {
CRWContextMenuController* context_menu_controller =
[[CRWContextMenuController alloc]
initWithWebView:web_view
browserState:browser_state
delegate:context_menu_delegate];
void* associated_object_key = (__bridge void*)context_menu_controller;
objc_setAssociatedObject(web_view, associated_object_key,
context_menu_controller,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
// Uses the default value for |allowsLinkPreview| i.e., YES in iOS 10 or
// later, and NO for iOS 9 or before. But the link preview is still disabled
// by default on iOS 10 or later. You need to return true from
......@@ -84,14 +69,6 @@ WKWebView* BuildWKWebView(CGRect frame,
return web_view;
}
WKWebView* BuildWKWebView(CGRect frame,
WKWebViewConfiguration* configuration,
BrowserState* browser_state,
UserAgentType user_agent_type) {
return BuildWKWebView(frame, configuration, browser_state, user_agent_type,
nil);
}
WKWebView* BuildWKWebView(CGRect frame,
WKWebViewConfiguration* configuration,
BrowserState* browser_state) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment