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/public/web_state/ui/crw_content_view.h"
11 #import "ios/web/web_state/ui/crw_web_controller.h"
15 // Returns the first responder in the subviews of |view|, or nil if no view in
16 // the subtree is the first responder.
17 UIView* GetFirstResponderSubview(UIView* view) {
18 if ([view isFirstResponder])
21 for (UIView* subview in [view subviews]) {
22 UIView* firstResponder = GetFirstResponderSubview(subview);
24 return firstResponder;
32 @interface CRWWebViewScrollViewProxy (ContentInsetsAlgebra)
33 // Adds the given insets to the current content insets and scroll indicator
34 // insets of the receiver.
35 - (void)cr_addInsets:(UIEdgeInsets)insets;
36 // Removes the given insets to the current content insets and scroll indicator
37 // insets of the receiver.
38 - (void)cr_removeInsets:(UIEdgeInsets)insets;
41 @implementation CRWWebViewScrollViewProxy (ContentInsetsAlgebra)
43 - (void)cr_addInsets:(UIEdgeInsets)insets {
44 if (UIEdgeInsetsEqualToEdgeInsets(insets, UIEdgeInsetsZero))
47 UIEdgeInsets currentInsets = [self contentInset];
48 currentInsets.top += insets.top;
49 currentInsets.left += insets.left;
50 currentInsets.bottom += insets.bottom;
51 currentInsets.right += insets.right;
52 [self setContentInset:currentInsets];
53 [self setScrollIndicatorInsets:currentInsets];
56 - (void)cr_removeInsets:(UIEdgeInsets)insets {
57 UIEdgeInsets negativeInsets = UIEdgeInsetsZero;
58 negativeInsets.top = -insets.top;
59 negativeInsets.left = -insets.left;
60 negativeInsets.bottom = -insets.bottom;
61 negativeInsets.right = -insets.right;
62 [self cr_addInsets:negativeInsets];
67 @implementation CRWWebViewProxyImpl {
68 base::WeakNSObject<CRWContentView> _contentView;
69 base::WeakNSObject<CRWWebController> _webController;
70 base::scoped_nsobject<NSMutableDictionary> _registeredInsets;
71 // The WebViewScrollViewProxy is a wrapper around the UIWebView's
72 // UIScrollView to give components access in a limited and controlled manner.
73 base::scoped_nsobject<CRWWebViewScrollViewProxy> _contentViewScrollViewProxy;
76 - (instancetype)initWithWebController:(CRWWebController*)webController {
79 DCHECK(webController);
80 _registeredInsets.reset([[NSMutableDictionary alloc] init]);
81 _webController.reset(webController);
82 _contentViewScrollViewProxy.reset([[CRWWebViewScrollViewProxy alloc] init]);
87 - (CRWWebViewScrollViewProxy*)scrollViewProxy {
88 return _contentViewScrollViewProxy.get();
92 return [_contentView bounds];
95 - (NSArray*)gestureRecognizers {
96 return [_contentView gestureRecognizers];
99 - (web::WebViewType)webViewType {
100 return [_webController webViewType];
103 - (void)registerInsets:(UIEdgeInsets)insets forCaller:(id)caller {
104 NSValue* callerValue = [NSValue valueWithNonretainedObject:caller];
105 if ([_registeredInsets objectForKey:callerValue])
106 [self unregisterInsetsForCaller:caller];
107 [self.scrollViewProxy cr_addInsets:insets];
108 [_registeredInsets setObject:[NSValue valueWithUIEdgeInsets:insets]
112 - (void)unregisterInsetsForCaller:(id)caller {
113 NSValue* callerValue = [NSValue valueWithNonretainedObject:caller];
114 NSValue* insetsValue = [_registeredInsets objectForKey:callerValue];
115 [self.scrollViewProxy cr_removeInsets:[insetsValue UIEdgeInsetsValue]];
116 [_registeredInsets removeObjectForKey:callerValue];
119 - (CRWContentView*)contentView {
120 return _contentView.get();
123 - (void)setContentView:(CRWContentView*)contentView {
124 _contentView.reset(contentView);
125 [_contentViewScrollViewProxy setScrollView:contentView.scrollView];
128 - (void)addSubview:(UIView*)view {
129 return [_contentView addSubview:view];
132 - (BOOL)hasSearchableTextContent {
133 return _contentView != nil && [_webController contentIsHTML];
136 - (UIView*)getKeyboardAccessory {
139 UIView* firstResponder = GetFirstResponderSubview(_contentView);
140 return firstResponder.inputAccessoryView;
143 - (BOOL)keyboardDisplayRequiresUserAction {
144 return [_webController keyboardDisplayRequiresUserAction];
147 - (void)setKeyboardDisplayRequiresUserAction:
148 (BOOL)keyboardDisplayRequiresUserAction {
150 setKeyboardDisplayRequiresUserAction:keyboardDisplayRequiresUserAction];