| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #import "ios/web/web_state/crw_web_view_proxy_impl.h" | |
| 6 | |
| 7 #import "base/mac/scoped_nsobject.h" | |
| 8 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" | |
| 9 #import "ios/web/public/web_state/ui/crw_content_view.h" | |
| 10 #import "ios/web/web_state/ui/crw_web_controller.h" | |
| 11 | |
| 12 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 13 #error "This file requires ARC support." | |
| 14 #endif | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 // Returns the first responder in the subviews of |view|, or nil if no view in | |
| 19 // the subtree is the first responder. | |
| 20 UIView* GetFirstResponderSubview(UIView* view) { | |
| 21 if ([view isFirstResponder]) | |
| 22 return view; | |
| 23 | |
| 24 for (UIView* subview in [view subviews]) { | |
| 25 UIView* firstResponder = GetFirstResponderSubview(subview); | |
| 26 if (firstResponder) | |
| 27 return firstResponder; | |
| 28 } | |
| 29 | |
| 30 return nil; | |
| 31 } | |
| 32 | |
| 33 } // namespace | |
| 34 | |
| 35 @interface CRWWebViewScrollViewProxy (ContentInsetsAlgebra) | |
| 36 // Adds the given insets to the current content insets and scroll indicator | |
| 37 // insets of the receiver. | |
| 38 - (void)cr_addInsets:(UIEdgeInsets)insets; | |
| 39 // Removes the given insets to the current content insets and scroll indicator | |
| 40 // insets of the receiver. | |
| 41 - (void)cr_removeInsets:(UIEdgeInsets)insets; | |
| 42 @end | |
| 43 | |
| 44 @implementation CRWWebViewScrollViewProxy (ContentInsetsAlgebra) | |
| 45 | |
| 46 - (void)cr_addInsets:(UIEdgeInsets)insets { | |
| 47 if (UIEdgeInsetsEqualToEdgeInsets(insets, UIEdgeInsetsZero)) | |
| 48 return; | |
| 49 | |
| 50 UIEdgeInsets currentInsets = [self contentInset]; | |
| 51 currentInsets.top += insets.top; | |
| 52 currentInsets.left += insets.left; | |
| 53 currentInsets.bottom += insets.bottom; | |
| 54 currentInsets.right += insets.right; | |
| 55 [self setContentInset:currentInsets]; | |
| 56 [self setScrollIndicatorInsets:currentInsets]; | |
| 57 } | |
| 58 | |
| 59 - (void)cr_removeInsets:(UIEdgeInsets)insets { | |
| 60 UIEdgeInsets negativeInsets = UIEdgeInsetsZero; | |
| 61 negativeInsets.top = -insets.top; | |
| 62 negativeInsets.left = -insets.left; | |
| 63 negativeInsets.bottom = -insets.bottom; | |
| 64 negativeInsets.right = -insets.right; | |
| 65 [self cr_addInsets:negativeInsets]; | |
| 66 } | |
| 67 | |
| 68 @end | |
| 69 | |
| 70 @implementation CRWWebViewProxyImpl { | |
| 71 __weak CRWWebController* _webController; | |
| 72 base::scoped_nsobject<NSMutableDictionary> _registeredInsets; | |
| 73 // The WebViewScrollViewProxy is a wrapper around the web view's | |
| 74 // UIScrollView to give components access in a limited and controlled manner. | |
| 75 base::scoped_nsobject<CRWWebViewScrollViewProxy> _contentViewScrollViewProxy; | |
| 76 } | |
| 77 @synthesize contentView = _contentView; | |
| 78 | |
| 79 - (instancetype)initWithWebController:(CRWWebController*)webController { | |
| 80 self = [super init]; | |
| 81 if (self) { | |
| 82 DCHECK(webController); | |
| 83 _registeredInsets.reset([[NSMutableDictionary alloc] init]); | |
| 84 _webController = webController; | |
| 85 _contentViewScrollViewProxy.reset([[CRWWebViewScrollViewProxy alloc] init]); | |
| 86 } | |
| 87 return self; | |
| 88 } | |
| 89 | |
| 90 - (CRWWebViewScrollViewProxy*)scrollViewProxy { | |
| 91 return _contentViewScrollViewProxy.get(); | |
| 92 } | |
| 93 | |
| 94 - (CGRect)bounds { | |
| 95 return [_contentView bounds]; | |
| 96 } | |
| 97 | |
| 98 - (CGRect)frame { | |
| 99 return [_contentView frame]; | |
| 100 } | |
| 101 | |
| 102 - (CGFloat)topContentPadding { | |
| 103 return [_contentView topContentPadding]; | |
| 104 } | |
| 105 | |
| 106 - (void)setTopContentPadding:(CGFloat)newTopContentPadding { | |
| 107 [_contentView setTopContentPadding:newTopContentPadding]; | |
| 108 } | |
| 109 | |
| 110 - (NSArray*)gestureRecognizers { | |
| 111 return [_contentView gestureRecognizers]; | |
| 112 } | |
| 113 | |
| 114 - (void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer { | |
| 115 [_contentView addGestureRecognizer:gestureRecognizer]; | |
| 116 } | |
| 117 | |
| 118 - (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer { | |
| 119 [_contentView removeGestureRecognizer:gestureRecognizer]; | |
| 120 } | |
| 121 | |
| 122 - (BOOL)shouldUseInsetForTopPadding { | |
| 123 SEL shouldUseInsetSelector = @selector(shouldUseInsetForTopPadding); | |
| 124 return [_contentView respondsToSelector:shouldUseInsetSelector] && | |
| 125 [_contentView shouldUseInsetForTopPadding]; | |
| 126 } | |
| 127 | |
| 128 - (void)setShouldUseInsetForTopPadding:(BOOL)shouldUseInsetForTopPadding { | |
| 129 if ([_contentView | |
| 130 respondsToSelector:@selector(setShouldUseInsetForTopPadding:)]) { | |
| 131 [_contentView setShouldUseInsetForTopPadding:shouldUseInsetForTopPadding]; | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 - (void)registerInsets:(UIEdgeInsets)insets forCaller:(id)caller { | |
| 136 NSValue* callerValue = [NSValue valueWithNonretainedObject:caller]; | |
| 137 if ([_registeredInsets objectForKey:callerValue]) | |
| 138 [self unregisterInsetsForCaller:caller]; | |
| 139 [self.scrollViewProxy cr_addInsets:insets]; | |
| 140 [_registeredInsets setObject:[NSValue valueWithUIEdgeInsets:insets] | |
| 141 forKey:callerValue]; | |
| 142 } | |
| 143 | |
| 144 - (void)unregisterInsetsForCaller:(id)caller { | |
| 145 NSValue* callerValue = [NSValue valueWithNonretainedObject:caller]; | |
| 146 NSValue* insetsValue = [_registeredInsets objectForKey:callerValue]; | |
| 147 [self.scrollViewProxy cr_removeInsets:[insetsValue UIEdgeInsetsValue]]; | |
| 148 [_registeredInsets removeObjectForKey:callerValue]; | |
| 149 } | |
| 150 | |
| 151 - (void)setContentView:(CRWContentView*)contentView { | |
| 152 _contentView = contentView; | |
| 153 [_contentViewScrollViewProxy setScrollView:contentView.scrollView]; | |
| 154 } | |
| 155 | |
| 156 - (void)addSubview:(UIView*)view { | |
| 157 return [_contentView addSubview:view]; | |
| 158 } | |
| 159 | |
| 160 - (BOOL)hasSearchableTextContent { | |
| 161 return _contentView != nil && [_webController contentIsHTML]; | |
| 162 } | |
| 163 | |
| 164 - (UIView*)keyboardAccessory { | |
| 165 if (!_contentView) | |
| 166 return nil; | |
| 167 UIView* firstResponder = GetFirstResponderSubview(_contentView); | |
| 168 return firstResponder.inputAccessoryView; | |
| 169 } | |
| 170 | |
| 171 - (UITextInputAssistantItem*)inputAssistantItem { | |
| 172 if (!_contentView) | |
| 173 return nil; | |
| 174 UIView* firstResponder = GetFirstResponderSubview(_contentView); | |
| 175 return firstResponder.inputAssistantItem; | |
| 176 } | |
| 177 | |
| 178 - (BOOL)becomeFirstResponder { | |
| 179 return [_contentView becomeFirstResponder]; | |
| 180 } | |
| 181 | |
| 182 @end | |
| OLD | NEW |