Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ios / web / web_state / crw_web_view_proxy_impl.mm
blob51549de33edf19463712a0ae8bc339bc2162257b
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ios/web/web_state/crw_web_view_proxy_impl.h"
7 #include "base/ios/ios_util.h"
8 #include "base/ios/weak_nsobject.h"
9 #include "base/mac/scoped_nsobject.h"
10 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h"
11 #import "ios/web/public/web_state/ui/crw_content_view.h"
12 #import "ios/web/web_state/ui/crw_web_controller.h"
14 namespace {
16 // Returns the first responder in the subviews of |view|, or nil if no view in
17 // the subtree is the first responder.
18 UIView* GetFirstResponderSubview(UIView* view) {
19   if ([view isFirstResponder])
20     return view;
22   for (UIView* subview in [view subviews]) {
23     UIView* firstResponder = GetFirstResponderSubview(subview);
24     if (firstResponder)
25       return firstResponder;
26   }
28   return nil;
31 }  // namespace
33 @interface CRWWebViewScrollViewProxy (ContentInsetsAlgebra)
34 // Adds the given insets to the current content insets and scroll indicator
35 // insets of the receiver.
36 - (void)cr_addInsets:(UIEdgeInsets)insets;
37 // Removes the given insets to the current content insets and scroll indicator
38 // insets of the receiver.
39 - (void)cr_removeInsets:(UIEdgeInsets)insets;
40 @end
42 @implementation CRWWebViewScrollViewProxy (ContentInsetsAlgebra)
44 - (void)cr_addInsets:(UIEdgeInsets)insets {
45   if (UIEdgeInsetsEqualToEdgeInsets(insets, UIEdgeInsetsZero))
46     return;
48   UIEdgeInsets currentInsets = [self contentInset];
49   currentInsets.top += insets.top;
50   currentInsets.left += insets.left;
51   currentInsets.bottom += insets.bottom;
52   currentInsets.right += insets.right;
53   [self setContentInset:currentInsets];
54   [self setScrollIndicatorInsets:currentInsets];
57 - (void)cr_removeInsets:(UIEdgeInsets)insets {
58   UIEdgeInsets negativeInsets = UIEdgeInsetsZero;
59   negativeInsets.top = -insets.top;
60   negativeInsets.left = -insets.left;
61   negativeInsets.bottom = -insets.bottom;
62   negativeInsets.right = -insets.right;
63   [self cr_addInsets:negativeInsets];
66 @end
68 @implementation CRWWebViewProxyImpl {
69   base::WeakNSObject<CRWContentView> _contentView;
70   base::WeakNSObject<CRWWebController> _webController;
71   base::scoped_nsobject<NSMutableDictionary> _registeredInsets;
72   // The WebViewScrollViewProxy is a wrapper around the web view's
73   // UIScrollView to give components access in a limited and controlled manner.
74   base::scoped_nsobject<CRWWebViewScrollViewProxy> _contentViewScrollViewProxy;
77 - (instancetype)initWithWebController:(CRWWebController*)webController {
78   self = [super init];
79   if (self) {
80     DCHECK(webController);
81     _registeredInsets.reset([[NSMutableDictionary alloc] init]);
82     _webController.reset(webController);
83     _contentViewScrollViewProxy.reset([[CRWWebViewScrollViewProxy alloc] init]);
84   }
85   return self;
88 - (CRWWebViewScrollViewProxy*)scrollViewProxy {
89   return _contentViewScrollViewProxy.get();
92 - (CGRect)bounds {
93   return [_contentView bounds];
96 - (CGRect)frame {
97   return [_contentView frame];
100 - (NSArray*)gestureRecognizers {
101   return [_contentView gestureRecognizers];
104 - (web::WebViewType)webViewType {
105   return [_webController webViewType];
108 - (void)registerInsets:(UIEdgeInsets)insets forCaller:(id)caller {
109   NSValue* callerValue = [NSValue valueWithNonretainedObject:caller];
110   if ([_registeredInsets objectForKey:callerValue])
111     [self unregisterInsetsForCaller:caller];
112   [self.scrollViewProxy cr_addInsets:insets];
113   [_registeredInsets setObject:[NSValue valueWithUIEdgeInsets:insets]
114                         forKey:callerValue];
117 - (void)unregisterInsetsForCaller:(id)caller {
118   NSValue* callerValue = [NSValue valueWithNonretainedObject:caller];
119   NSValue* insetsValue = [_registeredInsets objectForKey:callerValue];
120   [self.scrollViewProxy cr_removeInsets:[insetsValue UIEdgeInsetsValue]];
121   [_registeredInsets removeObjectForKey:callerValue];
124 - (CRWContentView*)contentView {
125   return _contentView.get();
128 - (void)setContentView:(CRWContentView*)contentView {
129   _contentView.reset(contentView);
130   [_contentViewScrollViewProxy setScrollView:contentView.scrollView];
133 - (void)addSubview:(UIView*)view {
134   return [_contentView addSubview:view];
137 - (BOOL)hasSearchableTextContent {
138   return _contentView != nil && [_webController contentIsHTML];
141 - (UIView*)getKeyboardAccessory {
142   return [self keyboardAccessory];
145 - (UIView*)keyboardAccessory {
146   if (!_contentView)
147     return nil;
148   UIView* firstResponder = GetFirstResponderSubview(_contentView);
149   return firstResponder.inputAccessoryView;
152 #if defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
153 - (UITextInputAssistantItem*)inputAssistantItem {
154   DCHECK(base::ios::IsRunningOnIOS9OrLater())
155       << "Cannot retrieve inputAssistantItem on iOS versions earlier than 9.";
156   if (!_contentView)
157     return nil;
158   UIView* firstResponder = GetFirstResponderSubview(_contentView);
159   return firstResponder.inputAssistantItem;
161 #endif
163 - (BOOL)keyboardDisplayRequiresUserAction {
164   return [_webController keyboardDisplayRequiresUserAction];
167 - (void)setKeyboardDisplayRequiresUserAction:
168         (BOOL)keyboardDisplayRequiresUserAction {
169   [_webController
170       setKeyboardDisplayRequiresUserAction:keyboardDisplayRequiresUserAction];
173 @end