| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" | 5 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" |
| 6 | 6 |
| 7 #import <objc/runtime.h> | 7 #import <objc/runtime.h> |
| 8 | 8 |
| 9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #import "base/ios/crb_protocol_observers.h" | 10 #import "base/ios/crb_protocol_observers.h" |
| 11 #include "base/mac/foundation_util.h" | 11 #include "base/mac/foundation_util.h" |
| 12 #import "base/mac/scoped_nsobject.h" | 12 #import "base/mac/scoped_nsobject.h" |
| 13 | 13 |
| 14 #if !defined(__has_feature) || !__has_feature(objc_arc) | 14 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 15 #error "This file requires ARC support." | 15 #error "This file requires ARC support." |
| 16 #endif | 16 #endif |
| 17 | 17 |
| 18 @interface CRWWebViewScrollViewProxy () { | 18 @interface CRWWebViewScrollViewProxy () { |
| 19 __weak UIScrollView* _scrollView; | 19 __weak UIScrollView* _scrollView; |
| 20 base::scoped_nsobject<id> _observers; | 20 base::scoped_nsobject<id> _observers; |
| 21 // When |_ignoreScroll| is set to YES, do not pass on -scrollViewDidScroll | |
| 22 // calls to observers. This is used by -setContentInsetFast, which needs to | |
| 23 // update and reset the contentOffset to force a fast update. These updates | |
| 24 // should be a no-op for the contentOffset, so the callbacks can be ignored. | |
| 25 BOOL _ignoreScroll; | |
| 26 } | 21 } |
| 27 | 22 |
| 28 // Returns the key paths that need to be observed for UIScrollView. | 23 // Returns the key paths that need to be observed for UIScrollView. |
| 29 + (NSArray*)scrollViewObserverKeyPaths; | 24 + (NSArray*)scrollViewObserverKeyPaths; |
| 30 | 25 |
| 31 // Adds and removes |self| as an observer for |scrollView| with key paths | 26 // Adds and removes |self| as an observer for |scrollView| with key paths |
| 32 // returned by |+scrollViewObserverKeyPaths|. | 27 // returned by |+scrollViewObserverKeyPaths|. |
| 33 - (void)startObservingScrollView:(UIScrollView*)scrollView; | 28 - (void)startObservingScrollView:(UIScrollView*)scrollView; |
| 34 - (void)stopObservingScrollView:(UIScrollView*)scrollView; | 29 - (void)stopObservingScrollView:(UIScrollView*)scrollView; |
| 35 | 30 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 } | 102 } |
| 108 | 103 |
| 109 - (void)setContentOffset:(CGPoint)contentOffset { | 104 - (void)setContentOffset:(CGPoint)contentOffset { |
| 110 [_scrollView setContentOffset:contentOffset]; | 105 [_scrollView setContentOffset:contentOffset]; |
| 111 } | 106 } |
| 112 | 107 |
| 113 - (CGPoint)contentOffset { | 108 - (CGPoint)contentOffset { |
| 114 return _scrollView ? [_scrollView contentOffset] : CGPointZero; | 109 return _scrollView ? [_scrollView contentOffset] : CGPointZero; |
| 115 } | 110 } |
| 116 | 111 |
| 117 - (void)setContentInsetFast:(UIEdgeInsets)contentInset { | |
| 118 if (!_scrollView) | |
| 119 return; | |
| 120 | |
| 121 // The method -scrollViewSetContentInsetImpl below is bypassing UIWebView's | |
| 122 // subclassed UIScrollView implemention of setContentOffset. UIKIt's | |
| 123 // implementation calls the internal method |_updateViewSettings| after | |
| 124 // updating the contentInsets. This ensures things like absolute positions | |
| 125 // are correctly updated. The problem is |_updateViewSettings| does lots of | |
| 126 // other things and is very very slow. The workaround below simply sets the | |
| 127 // scrollView's content insets directly, and then fiddles with the | |
| 128 // contentOffset below to correct the absolute positioning of elements. | |
| 129 static void (*scrollViewSetContentInsetImpl)(id, SEL, UIEdgeInsets); | |
| 130 static SEL setContentInset; | |
| 131 static dispatch_once_t onceToken; | |
| 132 dispatch_once(&onceToken, ^{ | |
| 133 setContentInset = @selector(setContentInset:); | |
| 134 scrollViewSetContentInsetImpl = | |
| 135 (void (*)(id, SEL, UIEdgeInsets))class_getMethodImplementation( | |
| 136 [UIScrollView class], setContentInset); | |
| 137 }); | |
| 138 scrollViewSetContentInsetImpl(_scrollView, setContentInset, contentInset); | |
| 139 | |
| 140 // Change and then reset the contentOffset to force the view into updating the | |
| 141 // absolute position of elements and content frame. Updating the | |
| 142 // contentOffset will cause the -scrollViewDidScroll callback to fire. | |
| 143 // Because we are eventually setting the contentOffset back to it's original | |
| 144 // position, we can ignore these calls. | |
| 145 base::AutoReset<BOOL> autoReset(&_ignoreScroll, YES); | |
| 146 CGPoint contentOffset = [_scrollView contentOffset]; | |
| 147 _scrollView.contentOffset = CGPointMake(contentOffset.x, contentOffset.y + 1); | |
| 148 _scrollView.contentOffset = contentOffset; | |
| 149 } | |
| 150 | |
| 151 - (void)setContentInset:(UIEdgeInsets)contentInset { | 112 - (void)setContentInset:(UIEdgeInsets)contentInset { |
| 152 [_scrollView setContentInset:contentInset]; | 113 [_scrollView setContentInset:contentInset]; |
| 153 } | 114 } |
| 154 | 115 |
| 155 - (UIEdgeInsets)contentInset { | 116 - (UIEdgeInsets)contentInset { |
| 156 return _scrollView ? [_scrollView contentInset] : UIEdgeInsetsZero; | 117 return _scrollView ? [_scrollView contentInset] : UIEdgeInsetsZero; |
| 157 } | 118 } |
| 158 | 119 |
| 159 - (void)setScrollIndicatorInsets:(UIEdgeInsets)scrollIndicatorInsets { | 120 - (void)setScrollIndicatorInsets:(UIEdgeInsets)scrollIndicatorInsets { |
| 160 [_scrollView setScrollIndicatorInsets:scrollIndicatorInsets]; | 121 [_scrollView setScrollIndicatorInsets:scrollIndicatorInsets]; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 182 | 143 |
| 183 - (NSArray*)gestureRecognizers { | 144 - (NSArray*)gestureRecognizers { |
| 184 return [_scrollView gestureRecognizers]; | 145 return [_scrollView gestureRecognizers]; |
| 185 } | 146 } |
| 186 | 147 |
| 187 #pragma mark - | 148 #pragma mark - |
| 188 #pragma mark UIScrollViewDelegate callbacks | 149 #pragma mark UIScrollViewDelegate callbacks |
| 189 | 150 |
| 190 - (void)scrollViewDidScroll:(UIScrollView*)scrollView { | 151 - (void)scrollViewDidScroll:(UIScrollView*)scrollView { |
| 191 DCHECK_EQ(_scrollView, scrollView); | 152 DCHECK_EQ(_scrollView, scrollView); |
| 192 if (!_ignoreScroll) { | 153 [_observers webViewScrollViewDidScroll:self]; |
| 193 [_observers webViewScrollViewDidScroll:self]; | |
| 194 } | |
| 195 } | 154 } |
| 196 | 155 |
| 197 - (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView { | 156 - (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView { |
| 198 DCHECK_EQ(_scrollView, scrollView); | 157 DCHECK_EQ(_scrollView, scrollView); |
| 199 [_observers webViewScrollViewWillBeginDragging:self]; | 158 [_observers webViewScrollViewWillBeginDragging:self]; |
| 200 | 159 |
| 201 // TODO(crbug.com/555723) Remove this once the fix to | 160 // TODO(crbug.com/555723) Remove this once the fix to |
| 202 // https://bugs.webkit.org/show_bug.cgi?id=148086 makes it's way in to iOS. | 161 // https://bugs.webkit.org/show_bug.cgi?id=148086 makes it's way in to iOS. |
| 203 scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; | 162 scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; |
| 204 } | 163 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 - (void)observeValueForKeyPath:(NSString*)keyPath | 224 - (void)observeValueForKeyPath:(NSString*)keyPath |
| 266 ofObject:(id)object | 225 ofObject:(id)object |
| 267 change:(NSDictionary*)change | 226 change:(NSDictionary*)change |
| 268 context:(void*)context { | 227 context:(void*)context { |
| 269 DCHECK_EQ(object, _scrollView); | 228 DCHECK_EQ(object, _scrollView); |
| 270 if ([keyPath isEqualToString:@"contentSize"]) | 229 if ([keyPath isEqualToString:@"contentSize"]) |
| 271 [_observers webViewScrollViewDidResetContentSize:self]; | 230 [_observers webViewScrollViewDidResetContentSize:self]; |
| 272 } | 231 } |
| 273 | 232 |
| 274 @end | 233 @end |
| OLD | NEW |