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/weak_nsobject.h"
8 #include "base/mac/scoped_nsobject.h"
9 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h"
10 #import "ios/web/web_state/ui/crw_web_controller.h"
14 // Returns the first responder in the subviews of |view|, or nil if no view in
15 // the subtree is the first responder.
16 UIView* GetFirstResponderSubview(UIView* view) {
17 if ([view isFirstResponder])
20 for (UIView* subview in [view subviews]) {
21 UIView* firstResponder = GetFirstResponderSubview(subview);
23 return firstResponder;
31 @interface CRWWebViewScrollViewProxy (ContentInsetsAlgebra)
32 // Adds the given insets to the current content insets and scroll indicator
33 // insets of the receiver.
34 - (void)cr_addInsets:(UIEdgeInsets)insets;
35 // Removes the given insets to the current content insets and scroll indicator
36 // insets of the receiver.
37 - (void)cr_removeInsets:(UIEdgeInsets)insets;
40 @implementation CRWWebViewScrollViewProxy (ContentInsetsAlgebra)
42 - (void)cr_addInsets:(UIEdgeInsets)insets {
43 if (UIEdgeInsetsEqualToEdgeInsets(insets, UIEdgeInsetsZero))
46 UIEdgeInsets currentInsets = [self contentInset];
47 currentInsets.top += insets.top;
48 currentInsets.left += insets.left;
49 currentInsets.bottom += insets.bottom;
50 currentInsets.right += insets.right;
51 [self setContentInset:currentInsets];
52 [self setScrollIndicatorInsets:currentInsets];
55 - (void)cr_removeInsets:(UIEdgeInsets)insets {
56 UIEdgeInsets negativeInsets = UIEdgeInsetsZero;
57 negativeInsets.top = -insets.top;
58 negativeInsets.left = -insets.left;
59 negativeInsets.bottom = -insets.bottom;
60 negativeInsets.right = -insets.right;
61 [self cr_addInsets:negativeInsets];
66 @implementation CRWWebViewProxyImpl {
67 base::WeakNSObject<UIView> _webView;
68 base::WeakNSObject<CRWWebController> _webController;
69 base::scoped_nsobject<NSMutableDictionary> _registeredInsets;
70 // The WebViewScrollViewProxy is a wrapper around the UIWebView's
71 // UIScrollView to give components access in a limited and controlled manner.
72 base::scoped_nsobject<CRWWebViewScrollViewProxy> _webViewScrollViewProxy;
75 - (instancetype)initWithWebController:(CRWWebController*)webController {
78 DCHECK(webController);
79 _registeredInsets.reset([[NSMutableDictionary alloc] init]);
80 _webController.reset(webController);
81 _webViewScrollViewProxy.reset([[CRWWebViewScrollViewProxy alloc] init]);
86 - (CRWWebViewScrollViewProxy*)scrollViewProxy {
87 return _webViewScrollViewProxy.get();
91 return [_webView bounds];
94 - (NSArray*)gestureRecognizers {
95 return [_webView gestureRecognizers];
98 - (web::WebViewType)webViewType {
99 return [_webController webViewType];
102 - (void)registerInsets:(UIEdgeInsets)insets forCaller:(id)caller {
103 NSValue* callerValue = [NSValue valueWithNonretainedObject:caller];
104 if ([_registeredInsets objectForKey:callerValue])
105 [self unregisterInsetsForCaller:caller];
106 [self.scrollViewProxy cr_addInsets:insets];
107 [_registeredInsets setObject:[NSValue valueWithUIEdgeInsets:insets]
111 - (void)unregisterInsetsForCaller:(id)caller {
112 NSValue* callerValue = [NSValue valueWithNonretainedObject:caller];
113 NSValue* insetsValue = [_registeredInsets objectForKey:callerValue];
114 [self.scrollViewProxy cr_removeInsets:[insetsValue UIEdgeInsetsValue]];
115 [_registeredInsets removeObjectForKey:callerValue];
118 - (void)setWebView:(UIView*)webView scrollView:(UIScrollView*)scrollView {
119 _webView.reset(webView);
122 [_webViewScrollViewProxy setScrollView:scrollView];
125 - (void)addSubview:(UIView*)view {
126 return [_webView addSubview:view];
129 - (BOOL)hasSearchableTextContent {
130 return _webView != nil && [_webController contentIsHTML];
133 - (UIView*)getKeyboardAccessory {
136 UIView* firstResponder = GetFirstResponderSubview(_webView);
137 return firstResponder.inputAccessoryView;
140 - (BOOL)keyboardDisplayRequiresUserAction {
141 return [_webController keyboardDisplayRequiresUserAction];
144 - (void)setKeyboardDisplayRequiresUserAction:
145 (BOOL)keyboardDisplayRequiresUserAction {
147 setKeyboardDisplayRequiresUserAction:keyboardDisplayRequiresUserAction];