OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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/chrome/browser/find_in_page/find_in_page_controller.h" | 5 #import "ios/chrome/browser/find_in_page/find_in_page_controller.h" |
6 | 6 |
7 #import <UIKit/UIKit.h> | 7 #import <UIKit/UIKit.h> |
8 | 8 |
9 #import <cmath> | 9 #import <cmath> |
10 #include <memory> | 10 #include <memory> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/mac/foundation_util.h" | 13 #include "base/mac/foundation_util.h" |
14 #include "base/mac/scoped_nsobject.h" | |
15 #import "ios/chrome/browser/find_in_page/find_in_page_model.h" | 14 #import "ios/chrome/browser/find_in_page/find_in_page_model.h" |
16 #import "ios/chrome/browser/find_in_page/js_findinpage_manager.h" | 15 #import "ios/chrome/browser/find_in_page/js_findinpage_manager.h" |
17 #import "ios/chrome/browser/web/dom_altering_lock.h" | 16 #import "ios/chrome/browser/web/dom_altering_lock.h" |
18 #import "ios/web/public/web_state/crw_web_view_proxy.h" | 17 #import "ios/web/public/web_state/crw_web_view_proxy.h" |
19 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" | 18 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" |
20 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" | 19 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" |
21 #import "ios/web/public/web_state/web_state.h" | 20 #import "ios/web/public/web_state/web_state.h" |
22 #import "ios/web/public/web_state/web_state_observer_bridge.h" | 21 #import "ios/web/public/web_state/web_state_observer_bridge.h" |
23 | 22 |
| 23 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 24 #error "This file requires ARC support." |
| 25 #endif |
| 26 |
24 NSString* const kFindBarTextFieldWillBecomeFirstResponderNotification = | 27 NSString* const kFindBarTextFieldWillBecomeFirstResponderNotification = |
25 @"kFindBarTextFieldWillBecomeFirstResponderNotification"; | 28 @"kFindBarTextFieldWillBecomeFirstResponderNotification"; |
26 NSString* const kFindBarTextFieldDidResignFirstResponderNotification = | 29 NSString* const kFindBarTextFieldDidResignFirstResponderNotification = |
27 @"kFindBarTextFieldDidResignFirstResponderNotification"; | 30 @"kFindBarTextFieldDidResignFirstResponderNotification"; |
28 | 31 |
29 namespace { | 32 namespace { |
30 // The delay (in secs) after which the find in page string will be pumped again. | 33 // The delay (in secs) after which the find in page string will be pumped again. |
31 const NSTimeInterval kRecurringPumpDelay = .01; | 34 const NSTimeInterval kRecurringPumpDelay = .01; |
32 | 35 |
33 // Keeps find in page search term to be shared between different tabs. Never | 36 // Keeps find in page search term to be shared between different tabs. Never |
34 // reset, not stored on disk. | 37 // reset, not stored on disk. |
35 static NSString* gSearchTerm; | 38 static NSString* gSearchTerm; |
36 } | 39 } |
37 | 40 |
38 @interface FindInPageController () <DOMAltering, CRWWebStateObserver> | 41 @interface FindInPageController () <DOMAltering, CRWWebStateObserver> |
39 // The find in page controller delegate. | 42 // The find in page controller delegate. |
40 @property(nonatomic, readonly) id<FindInPageControllerDelegate> delegate; | 43 @property(nonatomic, readonly) id<FindInPageControllerDelegate> delegate; |
| 44 |
41 // The web view's scroll view. | 45 // The web view's scroll view. |
42 @property(nonatomic, readonly) CRWWebViewScrollViewProxy* webViewScrollView; | 46 - (CRWWebViewScrollViewProxy*)webViewScrollView; |
43 | |
44 // Find in Page text field listeners. | 47 // Find in Page text field listeners. |
45 - (void)findBarTextFieldWillBecomeFirstResponder:(NSNotification*)note; | 48 - (void)findBarTextFieldWillBecomeFirstResponder:(NSNotification*)note; |
46 - (void)findBarTextFieldDidResignFirstResponder:(NSNotification*)note; | 49 - (void)findBarTextFieldDidResignFirstResponder:(NSNotification*)note; |
47 // Keyboard listeners. | 50 // Keyboard listeners. |
48 - (void)keyboardDidShow:(NSNotification*)note; | 51 - (void)keyboardDidShow:(NSNotification*)note; |
49 - (void)keyboardWillHide:(NSNotification*)note; | 52 - (void)keyboardWillHide:(NSNotification*)note; |
50 // Constantly injects the find string in page until | 53 // Constantly injects the find string in page until |
51 // |disableFindInPageWithCompletionHandler:| is called or the find operation is | 54 // |disableFindInPageWithCompletionHandler:| is called or the find operation is |
52 // complete. Calls |completionHandler| if the find operation is complete. | 55 // complete. Calls |completionHandler| if the find operation is complete. |
53 // |completionHandler| can be nil. | 56 // |completionHandler| can be nil. |
(...skipping 15 matching lines...) Expand all Loading... |
69 - (web::WebState*)webState; | 72 - (web::WebState*)webState; |
70 @end | 73 @end |
71 | 74 |
72 @implementation FindInPageController { | 75 @implementation FindInPageController { |
73 @private | 76 @private |
74 // Object that manages find_in_page.js injection into the web view. | 77 // Object that manages find_in_page.js injection into the web view. |
75 __unsafe_unretained JsFindinpageManager* _findInPageJsManager; | 78 __unsafe_unretained JsFindinpageManager* _findInPageJsManager; |
76 __unsafe_unretained id<FindInPageControllerDelegate> _delegate; | 79 __unsafe_unretained id<FindInPageControllerDelegate> _delegate; |
77 | 80 |
78 // Access to the web view from the web state. | 81 // Access to the web view from the web state. |
79 base::scoped_nsprotocol<id<CRWWebViewProxy>> _webViewProxy; | 82 id<CRWWebViewProxy> _webViewProxy; |
80 | 83 |
81 // True when a find is in progress. Used to avoid running JavaScript during | 84 // True when a find is in progress. Used to avoid running JavaScript during |
82 // disable when there is nothing to clear. | 85 // disable when there is nothing to clear. |
83 BOOL _findStringStarted; | 86 BOOL _findStringStarted; |
84 | 87 |
85 // Bridge to observe the web state from Objective-C. | 88 // Bridge to observe the web state from Objective-C. |
86 std::unique_ptr<web::WebStateObserverBridge> _webStateObserverBridge; | 89 std::unique_ptr<web::WebStateObserverBridge> _webStateObserverBridge; |
87 } | 90 } |
88 | 91 |
89 @synthesize delegate = _delegate; | 92 @synthesize delegate = _delegate; |
90 | 93 |
91 + (void)setSearchTerm:(NSString*)string { | 94 + (void)setSearchTerm:(NSString*)string { |
92 [gSearchTerm release]; | |
93 gSearchTerm = [string copy]; | 95 gSearchTerm = [string copy]; |
94 } | 96 } |
95 | 97 |
96 + (NSString*)searchTerm { | 98 + (NSString*)searchTerm { |
97 return gSearchTerm; | 99 return gSearchTerm; |
98 } | 100 } |
99 | 101 |
100 - (id)initWithWebState:(web::WebState*)webState | 102 - (id)initWithWebState:(web::WebState*)webState |
101 delegate:(id<FindInPageControllerDelegate>)delegate { | 103 delegate:(id<FindInPageControllerDelegate>)delegate { |
102 self = [super init]; | 104 self = [super init]; |
103 if (self) { | 105 if (self) { |
104 DCHECK(delegate); | 106 DCHECK(delegate); |
105 _findInPageJsManager = base::mac::ObjCCastStrict<JsFindinpageManager>( | 107 _findInPageJsManager = base::mac::ObjCCastStrict<JsFindinpageManager>( |
106 [webState->GetJSInjectionReceiver() | 108 [webState->GetJSInjectionReceiver() |
107 instanceOfClass:[JsFindinpageManager class]]); | 109 instanceOfClass:[JsFindinpageManager class]]); |
108 _delegate = delegate; | 110 _delegate = delegate; |
109 _webStateObserverBridge.reset( | 111 _webStateObserverBridge.reset( |
110 new web::WebStateObserverBridge(webState, self)); | 112 new web::WebStateObserverBridge(webState, self)); |
111 _webViewProxy.reset([webState->GetWebViewProxy() retain]); | 113 _webViewProxy = webState->GetWebViewProxy(); |
112 [[NSNotificationCenter defaultCenter] | 114 [[NSNotificationCenter defaultCenter] |
113 addObserver:self | 115 addObserver:self |
114 selector:@selector(findBarTextFieldWillBecomeFirstResponder:) | 116 selector:@selector(findBarTextFieldWillBecomeFirstResponder:) |
115 name:kFindBarTextFieldWillBecomeFirstResponderNotification | 117 name:kFindBarTextFieldWillBecomeFirstResponderNotification |
116 object:nil]; | 118 object:nil]; |
117 [[NSNotificationCenter defaultCenter] | 119 [[NSNotificationCenter defaultCenter] |
118 addObserver:self | 120 addObserver:self |
119 selector:@selector(findBarTextFieldDidResignFirstResponder:) | 121 selector:@selector(findBarTextFieldDidResignFirstResponder:) |
120 name:kFindBarTextFieldDidResignFirstResponderNotification | 122 name:kFindBarTextFieldDidResignFirstResponderNotification |
121 object:nil]; | 123 object:nil]; |
122 DOMAlteringLock::CreateForWebState(webState); | 124 DOMAlteringLock::CreateForWebState(webState); |
123 } | 125 } |
124 return self; | 126 return self; |
125 } | 127 } |
126 | 128 |
127 - (void)dealloc { | 129 - (void)dealloc { |
128 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 130 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
129 [super dealloc]; | |
130 } | 131 } |
131 | 132 |
132 - (FindInPageModel*)findInPageModel { | 133 - (FindInPageModel*)findInPageModel { |
133 return [_findInPageJsManager findInPageModel]; | 134 return [_findInPageJsManager findInPageModel]; |
134 } | 135 } |
135 | 136 |
136 - (BOOL)canFindInPage { | 137 - (BOOL)canFindInPage { |
137 return [_webViewProxy hasSearchableTextContent]; | 138 return [_webViewProxy hasSearchableTextContent]; |
138 } | 139 } |
139 | 140 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 completionHandler(); | 186 completionHandler(); |
186 } | 187 } |
187 return; | 188 return; |
188 } | 189 } |
189 // Cancel any previous pumping. | 190 // Cancel any previous pumping. |
190 [NSObject cancelPreviousPerformRequestsWithTarget:self]; | 191 [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
191 [self initFindInPage]; | 192 [self initFindInPage]; |
192 // Keep track of whether a find is in progress so to avoid running | 193 // Keep track of whether a find is in progress so to avoid running |
193 // JavaScript during disable if unnecessary. | 194 // JavaScript during disable if unnecessary. |
194 _findStringStarted = YES; | 195 _findStringStarted = YES; |
195 base::WeakNSObject<FindInPageController> weakSelf(self); | 196 __weak FindInPageController* weakSelf = self; |
196 [_findInPageJsManager findString:query | 197 [_findInPageJsManager findString:query |
197 completionHandler:^(BOOL finished, CGPoint point) { | 198 completionHandler:^(BOOL finished, CGPoint point) { |
198 [weakSelf processPumpResult:finished | 199 [weakSelf processPumpResult:finished |
199 scrollPoint:point | 200 scrollPoint:point |
200 completionHandler:completionHandler]; | 201 completionHandler:completionHandler]; |
201 }]; | 202 }]; |
202 }; | 203 }; |
203 DOMAlteringLock::FromWebState([self webState])->Acquire(self, lockAction); | 204 DOMAlteringLock::FromWebState([self webState])->Acquire(self, lockAction); |
204 } | 205 } |
205 | 206 |
206 - (void)startPumpingWithCompletionHandler:(ProceduralBlock)completionHandler { | 207 - (void)startPumpingWithCompletionHandler:(ProceduralBlock)completionHandler { |
207 base::WeakNSObject<FindInPageController> weakSelf(self); | 208 __weak FindInPageController* weakSelf = self; |
208 id completionHandlerBlock = ^void(BOOL findFinished) { | 209 id completionHandlerBlock = ^void(BOOL findFinished) { |
209 if (findFinished) { | 210 if (findFinished) { |
210 // Pumping complete. Nothing else to do. | 211 // Pumping complete. Nothing else to do. |
211 if (completionHandler) | 212 if (completionHandler) |
212 completionHandler(); | 213 completionHandler(); |
213 return; | 214 return; |
214 } | 215 } |
215 // Further pumping is required. | 216 // Further pumping is required. |
216 [weakSelf performSelector:@selector(startPumpingWithCompletionHandler:) | 217 [weakSelf performSelector:@selector(startPumpingWithCompletionHandler:) |
217 withObject:completionHandler | 218 withObject:completionHandler |
218 afterDelay:kRecurringPumpDelay]; | 219 afterDelay:kRecurringPumpDelay]; |
219 }; | 220 }; |
220 [self pumpFindStringInPageWithCompletionHandler:completionHandlerBlock]; | 221 [self pumpFindStringInPageWithCompletionHandler:completionHandlerBlock]; |
221 } | 222 } |
222 | 223 |
223 - (void)pumpFindStringInPageWithCompletionHandler: | 224 - (void)pumpFindStringInPageWithCompletionHandler: |
224 (void (^)(BOOL))completionHandler { | 225 (void (^)(BOOL))completionHandler { |
225 base::WeakNSObject<FindInPageController> weakSelf(self); | 226 __weak FindInPageController* weakSelf = self; |
226 [_findInPageJsManager pumpWithCompletionHandler:^(BOOL finished, | 227 [_findInPageJsManager pumpWithCompletionHandler:^(BOOL finished, |
227 CGPoint point) { | 228 CGPoint point) { |
228 base::scoped_nsobject<FindInPageController> strongSelf([weakSelf retain]); | 229 FindInPageController* strongSelf = weakSelf; |
229 if (finished) { | 230 if (finished) { |
230 [[strongSelf delegate] willAdjustScrollPosition]; | 231 [[strongSelf delegate] willAdjustScrollPosition]; |
231 point = [strongSelf limitOverscroll:[strongSelf webViewScrollView] | 232 point = [strongSelf limitOverscroll:[strongSelf webViewScrollView] |
232 atPoint:point]; | 233 atPoint:point]; |
233 [[strongSelf webViewScrollView] setContentOffset:point animated:YES]; | 234 [[strongSelf webViewScrollView] setContentOffset:point animated:YES]; |
234 } | 235 } |
235 completionHandler(finished); | 236 completionHandler(finished); |
236 }]; | 237 }]; |
237 } | 238 } |
238 | 239 |
239 - (void)findNextStringInPageWithCompletionHandler: | 240 - (void)findNextStringInPageWithCompletionHandler: |
240 (ProceduralBlock)completionHandler { | 241 (ProceduralBlock)completionHandler { |
241 [self initFindInPage]; | 242 [self initFindInPage]; |
242 base::WeakNSObject<FindInPageController> weakSelf(self); | 243 __weak FindInPageController* weakSelf = self; |
243 [_findInPageJsManager nextMatchWithCompletionHandler:^(CGPoint point) { | 244 [_findInPageJsManager nextMatchWithCompletionHandler:^(CGPoint point) { |
244 base::scoped_nsobject<FindInPageController> strongSelf([weakSelf retain]); | 245 FindInPageController* strongSelf = weakSelf; |
245 [[strongSelf delegate] willAdjustScrollPosition]; | 246 [[strongSelf delegate] willAdjustScrollPosition]; |
246 point = [strongSelf limitOverscroll:[strongSelf webViewScrollView] | 247 point = [strongSelf limitOverscroll:[strongSelf webViewScrollView] |
247 atPoint:point]; | 248 atPoint:point]; |
248 [[strongSelf webViewScrollView] setContentOffset:point animated:YES]; | 249 [[strongSelf webViewScrollView] setContentOffset:point animated:YES]; |
249 if (completionHandler) | 250 if (completionHandler) |
250 completionHandler(); | 251 completionHandler(); |
251 }]; | 252 }]; |
252 } | 253 } |
253 | 254 |
254 // Highlight the previous search match, update model and scroll to match. | 255 // Highlight the previous search match, update model and scroll to match. |
255 - (void)findPreviousStringInPageWithCompletionHandler: | 256 - (void)findPreviousStringInPageWithCompletionHandler: |
256 (ProceduralBlock)completionHandler { | 257 (ProceduralBlock)completionHandler { |
257 [self initFindInPage]; | 258 [self initFindInPage]; |
258 base::WeakNSObject<FindInPageController> weakSelf(self); | 259 __weak FindInPageController* weakSelf = self; |
259 [_findInPageJsManager previousMatchWithCompletionHandler:^(CGPoint point) { | 260 [_findInPageJsManager previousMatchWithCompletionHandler:^(CGPoint point) { |
260 base::scoped_nsobject<FindInPageController> strongSelf([weakSelf retain]); | 261 FindInPageController* strongSelf = weakSelf; |
261 [[strongSelf delegate] willAdjustScrollPosition]; | 262 [[strongSelf delegate] willAdjustScrollPosition]; |
262 point = [strongSelf limitOverscroll:[strongSelf webViewScrollView] | 263 point = [strongSelf limitOverscroll:[strongSelf webViewScrollView] |
263 atPoint:point]; | 264 atPoint:point]; |
264 [[strongSelf webViewScrollView] setContentOffset:point animated:YES]; | 265 [[strongSelf webViewScrollView] setContentOffset:point animated:YES]; |
265 if (completionHandler) | 266 if (completionHandler) |
266 completionHandler(); | 267 completionHandler(); |
267 }]; | 268 }]; |
268 } | 269 } |
269 | 270 |
270 // Remove highlights from the page and disable the model. | 271 // Remove highlights from the page and disable the model. |
271 - (void)disableFindInPageWithCompletionHandler: | 272 - (void)disableFindInPageWithCompletionHandler: |
272 (ProceduralBlock)completionHandler { | 273 (ProceduralBlock)completionHandler { |
273 if (![self canFindInPage]) | 274 if (![self canFindInPage]) |
274 return; | 275 return; |
275 // Cancel any queued calls to |recurringPumpWithCompletionHandler|. | 276 // Cancel any queued calls to |recurringPumpWithCompletionHandler|. |
276 [NSObject cancelPreviousPerformRequestsWithTarget:self]; | 277 [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
277 base::WeakNSObject<FindInPageController> weakSelf(self); | 278 __weak FindInPageController* weakSelf = self; |
278 ProceduralBlock handler = ^{ | 279 ProceduralBlock handler = ^{ |
279 base::scoped_nsobject<FindInPageController> strongSelf([weakSelf retain]); | 280 FindInPageController* strongSelf = weakSelf; |
280 if (strongSelf) { | 281 if (strongSelf) { |
281 [strongSelf.get().findInPageModel setEnabled:NO]; | 282 [strongSelf.findInPageModel setEnabled:NO]; |
282 web::WebState* webState = [strongSelf webState]; | 283 web::WebState* webState = [strongSelf webState]; |
283 if (webState) | 284 if (webState) |
284 DOMAlteringLock::FromWebState(webState)->Release(strongSelf); | 285 DOMAlteringLock::FromWebState(webState)->Release(strongSelf); |
285 } | 286 } |
286 if (completionHandler) | 287 if (completionHandler) |
287 completionHandler(); | 288 completionHandler(); |
288 }; | 289 }; |
289 // Only run JSFindInPageManager disable if there is a string in progress to | 290 // Only run JSFindInPageManager disable if there is a string in progress to |
290 // avoid WKWebView crash on deallocation due to outstanding completion | 291 // avoid WKWebView crash on deallocation due to outstanding completion |
291 // handler. | 292 // handler. |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 | 375 |
375 - (BOOL)canReleaseDOMLock { | 376 - (BOOL)canReleaseDOMLock { |
376 return NO; | 377 return NO; |
377 } | 378 } |
378 | 379 |
379 - (void)releaseDOMLockWithCompletionHandler:(ProceduralBlock)completionHandler { | 380 - (void)releaseDOMLockWithCompletionHandler:(ProceduralBlock)completionHandler { |
380 NOTREACHED(); | 381 NOTREACHED(); |
381 } | 382 } |
382 | 383 |
383 @end | 384 @end |
OLD | NEW |