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/chrome/browser/ui/contextual_search/contextual_search_controller.h" | 5 #import "ios/chrome/browser/ui/contextual_search/contextual_search_controller.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/ios/ios_util.h" | 10 #include "base/ios/ios_util.h" |
11 #import "base/ios/weak_nsobject.h" | |
12 #include "base/json/json_reader.h" | 11 #include "base/json/json_reader.h" |
13 #include "base/logging.h" | 12 #include "base/logging.h" |
14 #import "base/mac/bind_objc_block.h" | 13 #import "base/mac/bind_objc_block.h" |
15 #include "base/mac/foundation_util.h" | 14 #include "base/mac/foundation_util.h" |
16 #include "base/mac/scoped_block.h" | 15 #include "base/mac/scoped_block.h" |
17 #include "base/mac/scoped_nsobject.h" | |
18 #include "base/strings/sys_string_conversions.h" | 16 #include "base/strings/sys_string_conversions.h" |
19 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
20 #include "base/time/time.h" | 18 #include "base/time/time.h" |
21 #include "base/values.h" | 19 #include "base/values.h" |
22 #include "components/google/core/browser/google_util.h" | 20 #include "components/google/core/browser/google_util.h" |
23 #include "components/search_engines/template_url_service.h" | 21 #include "components/search_engines/template_url_service.h" |
24 #include "ios/chrome/browser/application_context.h" | 22 #include "ios/chrome/browser/application_context.h" |
25 #import "ios/chrome/browser/procedural_block_types.h" | 23 #import "ios/chrome/browser/procedural_block_types.h" |
26 #import "ios/chrome/browser/tabs/tab.h" | 24 #import "ios/chrome/browser/tabs/tab.h" |
27 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" | 25 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" |
(...skipping 26 matching lines...) Expand all Loading... |
54 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" | 52 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" |
55 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" | 53 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" |
56 #include "ios/web/public/web_state/web_state.h" | 54 #include "ios/web/public/web_state/web_state.h" |
57 #include "ios/web/public/web_state/web_state_observer.h" | 55 #include "ios/web/public/web_state/web_state_observer.h" |
58 #include "ui/base/l10n/l10n_util.h" | 56 #include "ui/base/l10n/l10n_util.h" |
59 #include "ui/base/l10n/l10n_util_mac.h" | 57 #include "ui/base/l10n/l10n_util_mac.h" |
60 | 58 |
61 // Returns |value| clamped so that min <= value <= max | 59 // Returns |value| clamped so that min <= value <= max |
62 #define CLAMP(min, value, max) MAX(min, MIN(value, max)) | 60 #define CLAMP(min, value, max) MAX(min, MIN(value, max)) |
63 | 61 |
| 62 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 63 #error "This file requires ARC support." |
| 64 #endif |
| 65 |
64 namespace { | 66 namespace { |
65 // command prefix for injected JavaScript. | 67 // command prefix for injected JavaScript. |
66 const std::string kCommandPrefix = "contextualSearch"; | 68 const std::string kCommandPrefix = "contextualSearch"; |
67 | 69 |
68 // Distance from edges of frame when scrolling to show selection. | 70 // Distance from edges of frame when scrolling to show selection. |
69 const CGFloat kYScrollMargin = 30.0; | 71 const CGFloat kYScrollMargin = 30.0; |
70 const CGFloat kXScrollMargin = 10.0; | 72 const CGFloat kXScrollMargin = 10.0; |
71 | 73 |
72 // Delay to check if there is a DOM modification (in second). | 74 // Delay to check if there is a DOM modification (in second). |
73 // If delay is too short, JavaScript won't have time to handle the event and the | 75 // If delay is too short, JavaScript won't have time to handle the event and the |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 rectBottom <= rectTop) { | 119 rectBottom <= rectTop) { |
118 return CGRectNull; | 120 return CGRectNull; |
119 } | 121 } |
120 CGRect rect = | 122 CGRect rect = |
121 CGRectMake(rectLeft, rectTop, rectRight - rectLeft, rectBottom - rectTop); | 123 CGRectMake(rectLeft, rectTop, rectRight - rectLeft, rectBottom - rectTop); |
122 return rect; | 124 return rect; |
123 } | 125 } |
124 | 126 |
125 NSArray* StringValueToRectArray(const std::string& list) { | 127 NSArray* StringValueToRectArray(const std::string& list) { |
126 NSString* nsList = base::SysUTF8ToNSString(list); | 128 NSString* nsList = base::SysUTF8ToNSString(list); |
127 NSMutableArray* rectsArray = [[[NSMutableArray alloc] init] autorelease]; | 129 NSMutableArray* rectsArray = [[NSMutableArray alloc] init]; |
128 NSArray* items = [nsList componentsSeparatedByString:@","]; | 130 NSArray* items = [nsList componentsSeparatedByString:@","]; |
129 for (NSString* item : items) { | 131 for (NSString* item : items) { |
130 CGRect rect = StringValueToRect(item); | 132 CGRect rect = StringValueToRect(item); |
131 if (CGRectIsNull(rect)) { | 133 if (CGRectIsNull(rect)) { |
132 return nil; | 134 return nil; |
133 } | 135 } |
134 [rectsArray addObject:[NSValue valueWithCGRect:rect]]; | 136 [rectsArray addObject:[NSValue valueWithCGRect:rect]]; |
135 } | 137 } |
136 return rectsArray; | 138 return rectsArray; |
137 } | 139 } |
138 | 140 |
139 } // namespace | 141 } // namespace |
140 | 142 |
141 @interface ContextualSearchController ()<DOMAltering, | 143 @interface ContextualSearchController ()<DOMAltering, |
142 CRWWebViewScrollViewProxyObserver, | 144 CRWWebViewScrollViewProxyObserver, |
143 UIGestureRecognizerDelegate, | 145 UIGestureRecognizerDelegate, |
144 ContextualSearchHighlighterDelegate, | 146 ContextualSearchHighlighterDelegate, |
145 ContextualSearchPromoViewDelegate, | 147 ContextualSearchPromoViewDelegate, |
146 ContextualSearchPanelMotionObserver, | 148 ContextualSearchPanelMotionObserver, |
147 ContextualSearchPanelTapHandler, | 149 ContextualSearchPanelTapHandler, |
148 ContextualSearchPreloadChecker, | 150 ContextualSearchPreloadChecker, |
149 ContextualSearchTabPromoter, | 151 ContextualSearchTabPromoter, |
150 ContextualSearchWebStateDelegate, | 152 ContextualSearchWebStateDelegate, |
151 TouchToSearchPermissionsChangeAudience> | 153 TouchToSearchPermissionsChangeAudience> |
152 | 154 |
153 // Controller delegate for the controller to call back to. | 155 // Controller delegate for the controller to call back to. |
154 @property(nonatomic, readwrite, assign) id<ContextualSearchControllerDelegate> | 156 @property(nonatomic, readwrite, weak) id<ContextualSearchControllerDelegate> |
155 controllerDelegate; | 157 controllerDelegate; |
156 | 158 |
157 // Permissions interface for this feature. Property is readwrite for testing. | 159 // Permissions interface for this feature. Property is readwrite for testing. |
158 @property(nonatomic, readwrite, retain) | 160 @property(nonatomic, readwrite, strong) |
159 TouchToSearchPermissionsMediator* permissions; | 161 TouchToSearchPermissionsMediator* permissions; |
160 | 162 |
161 // Synchronous method executed by -asynchronouslyEnableContextualSearch: | 163 // Synchronous method executed by -asynchronouslyEnableContextualSearch: |
162 - (void)doEnableContextualSearch:(BOOL)enabled; | 164 - (void)doEnableContextualSearch:(BOOL)enabled; |
163 | 165 |
164 // Handler for injected JavaScript callbacks. | 166 // Handler for injected JavaScript callbacks. |
165 - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand; | 167 - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand; |
166 | 168 |
167 // Handle the selection change event if the DOM lock is acquired. | 169 // Handle the selection change event if the DOM lock is acquired. |
168 // |selection| is the currently selected text in the webview. | 170 // |selection| is the currently selected text in the webview. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 // - vertical: put |_highlightBoundingRect| at |kYScrollMargin| from top edge. | 238 // - vertical: put |_highlightBoundingRect| at |kYScrollMargin| from top edge. |
237 - (void)scrollToShowSelection:(CRWWebViewScrollViewProxy*)scrollView; | 239 - (void)scrollToShowSelection:(CRWWebViewScrollViewProxy*)scrollView; |
238 | 240 |
239 // Creates, enables or disables the dismiss recognizer based on state_. | 241 // Creates, enables or disables the dismiss recognizer based on state_. |
240 - (void)updateDismissRecognizer; | 242 - (void)updateDismissRecognizer; |
241 | 243 |
242 @end | 244 @end |
243 | 245 |
244 @implementation ContextualSearchController { | 246 @implementation ContextualSearchController { |
245 // Permissions interface for this feature. | 247 // Permissions interface for this feature. |
246 base::scoped_nsobject<TouchToSearchPermissionsMediator> _permissions; | 248 TouchToSearchPermissionsMediator* _permissions; |
247 | 249 |
248 // WebState for the tab this object is attached to. | 250 // WebState for the tab this object is attached to. |
249 web::WebState* _webState; | 251 web::WebState* _webState; |
250 | 252 |
251 // Access to the web view from |_webState|. | 253 // Access to the web view from |_webState|. |
252 base::scoped_nsprotocol<id<CRWWebViewProxy>> _webViewProxy; | 254 id<CRWWebViewProxy> _webViewProxy; |
253 | 255 |
254 // Observer for |_webState|. | 256 // Observer for |_webState|. |
255 std::unique_ptr<ContextualSearchWebStateObserver> _webStateObserver; | 257 std::unique_ptr<ContextualSearchWebStateObserver> _webStateObserver; |
256 | 258 |
257 // Observer for search tab's web state. | 259 // Observer for search tab's web state. |
258 std::unique_ptr<ContextualSearchWebStateObserver> _searchTabWebStateObserver; | 260 std::unique_ptr<ContextualSearchWebStateObserver> _searchTabWebStateObserver; |
259 | 261 |
260 // Object that manages find_in_page.js injection into the web view. | 262 // Object that manages find_in_page.js injection into the web view. |
261 base::WeakNSObject<JsContextualSearchManager> _contextualSearchJsManager; | 263 __weak JsContextualSearchManager* _contextualSearchJsManager; |
262 | 264 |
263 // Gesture reccognizer for contextual search taps. | 265 // Gesture reccognizer for contextual search taps. |
264 base::scoped_nsobject<UITapGestureRecognizer> _tapRecognizer; | 266 UITapGestureRecognizer* _tapRecognizer; |
265 | 267 |
266 // Gesture reccognizer for double tap. It is used to prevent |_tapRecognizer| | 268 // Gesture reccognizer for double tap. It is used to prevent |_tapRecognizer| |
267 // from firing if there is a double tap on the web view. It is disabled when | 269 // from firing if there is a double tap on the web view. It is disabled when |
268 // the panel is displayed, since any tap will dismiss the panel in that case. | 270 // the panel is displayed, since any tap will dismiss the panel in that case. |
269 base::scoped_nsobject<UITapGestureRecognizer> _doubleTapRecognizer; | 271 UITapGestureRecognizer* _doubleTapRecognizer; |
270 | 272 |
271 // Gesture recognizer for long-tap copy. | 273 // Gesture recognizer for long-tap copy. |
272 base::scoped_nsobject<UILongPressGestureRecognizer> _copyGestureRecognizer; | 274 UILongPressGestureRecognizer* _copyGestureRecognizer; |
273 | 275 |
274 // Gesture recognizer to detect taps outside of the CS interface that would | 276 // Gesture recognizer to detect taps outside of the CS interface that would |
275 // cause it to dismiss. | 277 // cause it to dismiss. |
276 base::scoped_nsobject<WindowGestureObserver> _dismissRecognizer; | 278 WindowGestureObserver* _dismissRecognizer; |
277 | 279 |
278 // Context information retrieved from a search tap. | 280 // Context information retrieved from a search tap. |
279 std::shared_ptr<ContextualSearchContext> _searchContext; | 281 std::shared_ptr<ContextualSearchContext> _searchContext; |
280 | 282 |
281 // Resolved search information generated from the context or text selection. | 283 // Resolved search information generated from the context or text selection. |
282 ContextualSearchDelegate::SearchResolution _resolvedSearch; | 284 ContextualSearchDelegate::SearchResolution _resolvedSearch; |
283 | 285 |
284 // Delegate for fetching search information. | 286 // Delegate for fetching search information. |
285 std::unique_ptr<ContextualSearchDelegate> _delegate; | 287 std::unique_ptr<ContextualSearchDelegate> _delegate; |
286 | 288 |
287 // The panel view controlled by this object; it is created externally and | 289 // The panel view controlled by this object; it is created externally and |
288 // owned by its superview. There is no guarantee about its lifetime. | 290 // owned by its superview. There is no guarantee about its lifetime. |
289 base::WeakNSObject<ContextualSearchPanelView> _panelView; | 291 __weak ContextualSearchPanelView* _panelView; |
290 | 292 |
291 // The view containing the highlighting of the search terms. | 293 // The view containing the highlighting of the search terms. |
292 base::WeakNSObject<ContextualSearchHighlighterView> _contextualHighlightView; | 294 __weak ContextualSearchHighlighterView* _contextualHighlightView; |
293 | 295 |
294 // Content view displayed in the peeking section of the panel. | 296 // Content view displayed in the peeking section of the panel. |
295 base::scoped_nsobject<ContextualSearchHeaderView> _headerView; | 297 ContextualSearchHeaderView* _headerView; |
296 | 298 |
297 // Vertical constraints for layout of the search tab. | 299 // Vertical constraints for layout of the search tab. |
298 base::scoped_nsobject<NSArray> _searchTabVerticalConstraints; | 300 NSArray* _searchTabVerticalConstraints; |
299 | 301 |
300 // Container view for the opt-out promo and the search tab view. | 302 // Container view for the opt-out promo and the search tab view. |
301 base::scoped_nsobject<ContextualSearchResultsView> _searchResultsView; | 303 ContextualSearchResultsView* _searchResultsView; |
302 | 304 |
303 // View for the opt-out promo. | 305 // View for the opt-out promo. |
304 base::scoped_nsobject<ContextualSearchPromoView> _promoView; | 306 ContextualSearchPromoView* _promoView; |
305 | 307 |
306 // The tab that should be used as the opener for the search tab. | 308 // The tab that should be used as the opener for the search tab. |
307 Tab* _opener; | 309 Tab* _opener; |
308 | 310 |
309 // YES if a cancel event was received since last tap, meaning the current tap | 311 // YES if a cancel event was received since last tap, meaning the current tap |
310 // must not result in a search. | 312 // must not result in a search. |
311 BOOL _currentTapCancelled; | 313 BOOL _currentTapCancelled; |
312 | 314 |
313 // The current selection text. | 315 // The current selection text. |
314 std::string _selectedText; | 316 std::string _selectedText; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 // True when closed has been called and contextual search controller | 372 // True when closed has been called and contextual search controller |
371 // has been destroyed. | 373 // has been destroyed. |
372 BOOL _closed; | 374 BOOL _closed; |
373 | 375 |
374 // When view is resized, JavaScript and UIView sizes are not updated at the | 376 // When view is resized, JavaScript and UIView sizes are not updated at the |
375 // same time. Computing a scroll delta to make selection visible in these | 377 // same time. Computing a scroll delta to make selection visible in these |
376 // conditions will likely scroll to a random position. | 378 // conditions will likely scroll to a random position. |
377 BOOL _preventScrollToShowSelection; | 379 BOOL _preventScrollToShowSelection; |
378 | 380 |
379 // The time of the last dismiss. | 381 // The time of the last dismiss. |
380 base::scoped_nsobject<NSDate> _lastDismiss; | 382 NSDate* _lastDismiss; |
381 } | 383 } |
382 | 384 |
383 @synthesize enabled = _enabled; | 385 @synthesize enabled = _enabled; |
384 @synthesize controllerDelegate = _controllerDelegate; | 386 @synthesize controllerDelegate = _controllerDelegate; |
385 @synthesize webState = _webState; | 387 @synthesize webState = _webState; |
386 | 388 |
387 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState | 389 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState |
388 delegate:(id<ContextualSearchControllerDelegate>) | 390 delegate:(id<ContextualSearchControllerDelegate>) |
389 delegate { | 391 delegate { |
390 if ((self = [super init])) { | 392 if ((self = [super init])) { |
391 _permissions.reset([[TouchToSearchPermissionsMediator alloc] | 393 _permissions = [[TouchToSearchPermissionsMediator alloc] |
392 initWithBrowserState:browserState]); | 394 initWithBrowserState:browserState]; |
393 [_permissions setAudience:self]; | 395 [_permissions setAudience:self]; |
394 | 396 |
395 self.controllerDelegate = delegate; | 397 self.controllerDelegate = delegate; |
396 | 398 |
397 // Set up the web state observer. This lasts as long as this object does, | 399 // Set up the web state observer. This lasts as long as this object does, |
398 // but it will observe and un-observe the web tabs as it changes over time. | 400 // but it will observe and un-observe the web tabs as it changes over time. |
399 _webStateObserver.reset(new ContextualSearchWebStateObserver(self)); | 401 _webStateObserver.reset(new ContextualSearchWebStateObserver(self)); |
400 | 402 |
401 _copyGestureRecognizer.reset([[UILongPressGestureRecognizer alloc] | 403 _copyGestureRecognizer = [[UILongPressGestureRecognizer alloc] |
402 initWithTarget:self | 404 initWithTarget:self |
403 action:@selector(handleLongPressFrom:)]); | 405 action:@selector(handleLongPressFrom:)]; |
404 | 406 |
405 base::WeakNSObject<ContextualSearchController> weakself(self); | 407 __weak ContextualSearchController* weakself = self; |
406 auto callback = base::BindBlock( | 408 auto callback = base::BindBlockArc( |
407 ^(ContextualSearchDelegate::SearchResolution resolution) { | 409 ^(ContextualSearchDelegate::SearchResolution resolution) { |
408 [weakself updateForResolvedSearch:resolution]; | 410 [weakself updateForResolvedSearch:resolution]; |
409 }); | 411 }); |
410 | 412 |
411 _delegate.reset(new ContextualSearchDelegate(browserState, callback)); | 413 _delegate.reset(new ContextualSearchDelegate(browserState, callback)); |
412 } | 414 } |
413 return self; | 415 return self; |
414 } | 416 } |
415 | 417 |
416 - (TouchToSearchPermissionsMediator*)permissions { | 418 - (TouchToSearchPermissionsMediator*)permissions { |
417 return _permissions; | 419 return _permissions; |
418 } | 420 } |
419 | 421 |
420 - (void)setPermissions:(TouchToSearchPermissionsMediator*)permissions { | 422 - (void)setPermissions:(TouchToSearchPermissionsMediator*)permissions { |
421 _permissions.reset(permissions); | 423 _permissions = permissions; |
422 } | 424 } |
423 | 425 |
424 - (ContextualSearchPanelView*)panel { | 426 - (ContextualSearchPanelView*)panel { |
425 return _panelView; | 427 return _panelView; |
426 } | 428 } |
427 | 429 |
428 - (void)setPanel:(ContextualSearchPanelView*)panel { | 430 - (void)setPanel:(ContextualSearchPanelView*)panel { |
429 DCHECK(!_panelView); | 431 DCHECK(!_panelView); |
430 DCHECK(panel); | 432 DCHECK(panel); |
431 | 433 |
432 // Save the new panel, set up observation and delegation relationships. | 434 // Save the new panel, set up observation and delegation relationships. |
433 _panelView.reset(panel); | 435 _panelView = panel; |
434 [_panelView addMotionObserver:self]; | 436 [_panelView addMotionObserver:self]; |
435 [_dismissRecognizer setViewToExclude:_panelView]; | 437 [_dismissRecognizer setViewToExclude:_panelView]; |
436 | 438 |
437 // Create new subviews. | 439 // Create new subviews. |
438 NSMutableArray* panelContents = [NSMutableArray arrayWithCapacity:3]; | 440 NSMutableArray* panelContents = [NSMutableArray arrayWithCapacity:3]; |
439 | 441 |
440 _headerView.reset([[ContextualSearchHeaderView alloc] | 442 _headerView = [[ContextualSearchHeaderView alloc] |
441 initWithHeight:[_panelView configuration].peekingHeight]); | 443 initWithHeight:[_panelView configuration].peekingHeight]; |
442 [_headerView addGestureRecognizer:_copyGestureRecognizer]; | 444 [_headerView addGestureRecognizer:_copyGestureRecognizer]; |
443 [_headerView setTapHandler:self]; | 445 [_headerView setTapHandler:self]; |
444 | 446 |
445 [panelContents addObject:_headerView]; | 447 [panelContents addObject:_headerView]; |
446 | 448 |
447 if (self.permissions.preferenceState == TouchToSearch::UNDECIDED) { | 449 if (self.permissions.preferenceState == TouchToSearch::UNDECIDED) { |
448 _promoView.reset([[ContextualSearchPromoView alloc] initWithFrame:CGRectZero | 450 _promoView = [[ContextualSearchPromoView alloc] initWithFrame:CGRectZero |
449 delegate:self]); | 451 delegate:self]; |
450 [panelContents addObject:_promoView]; | 452 [panelContents addObject:_promoView]; |
451 } | 453 } |
452 | 454 |
453 _searchResultsView.reset( | 455 _searchResultsView = |
454 [[ContextualSearchResultsView alloc] initWithFrame:CGRectZero]); | 456 [[ContextualSearchResultsView alloc] initWithFrame:CGRectZero]; |
455 [_searchResultsView setPromoter:self]; | 457 [_searchResultsView setPromoter:self]; |
456 [_searchResultsView setPreloadChecker:self]; | 458 [_searchResultsView setPreloadChecker:self]; |
457 [panelContents addObject:_searchResultsView]; | 459 [panelContents addObject:_searchResultsView]; |
458 | 460 |
459 [_panelView addContentViews:panelContents]; | 461 [_panelView addContentViews:panelContents]; |
460 } | 462 } |
461 | 463 |
462 - (void)enableContextualSearch:(BOOL)enabled { | 464 - (void)enableContextualSearch:(BOOL)enabled { |
463 // Asynchronously enables contextual search, so that some preferences | 465 // Asynchronously enables contextual search, so that some preferences |
464 // (UIAccessibilityIsVoiceOverRunning(), for example) have time to synchronize | 466 // (UIAccessibilityIsVoiceOverRunning(), for example) have time to synchronize |
465 // with their own notifications. | 467 // with their own notifications. |
466 base::WeakNSObject<ContextualSearchController> weakSelf(self); | 468 __weak ContextualSearchController* weakSelf = self; |
467 dispatch_async(dispatch_get_main_queue(), ^{ | 469 dispatch_async(dispatch_get_main_queue(), ^{ |
468 [weakSelf doEnableContextualSearch:enabled]; | 470 [weakSelf doEnableContextualSearch:enabled]; |
469 }); | 471 }); |
470 } | 472 } |
471 | 473 |
472 - (void)doEnableContextualSearch:(BOOL)enabled { | 474 - (void)doEnableContextualSearch:(BOOL)enabled { |
473 enabled = enabled && [self.permissions canEnable]; | 475 enabled = enabled && [self.permissions canEnable]; |
474 | 476 |
475 BOOL changing = _enabled != enabled; | 477 BOOL changing = _enabled != enabled; |
476 if (changing) { | 478 if (changing) { |
477 if (!enabled) { | 479 if (!enabled) { |
478 [self dismissPane:ContextualSearch::RESET]; | 480 [self dismissPane:ContextualSearch::RESET]; |
479 } | 481 } |
480 _enabled = enabled; | 482 _enabled = enabled; |
481 [self enableCurrentWebState]; | 483 [self enableCurrentWebState]; |
482 } | 484 } |
483 } | 485 } |
484 | 486 |
485 - (void)updateWebViewProxy:(id<CRWWebViewProxy>)webViewProxy { | 487 - (void)updateWebViewProxy:(id<CRWWebViewProxy>)webViewProxy { |
486 if (_webViewProxy) { | 488 if (_webViewProxy) { |
487 [[_webViewProxy scrollViewProxy] removeObserver:self]; | 489 [[_webViewProxy scrollViewProxy] removeObserver:self]; |
488 } | 490 } |
489 _webViewProxy.reset([webViewProxy retain]); | 491 _webViewProxy = webViewProxy; |
490 if (_webViewProxy) { | 492 if (_webViewProxy) { |
491 [[_webViewProxy scrollViewProxy] addObserver:self]; | 493 [[_webViewProxy scrollViewProxy] addObserver:self]; |
492 } | 494 } |
493 } | 495 } |
494 | 496 |
495 - (void)setTab:(Tab*)tab { | 497 - (void)setTab:(Tab*)tab { |
496 [self setWebState:tab.webState]; | 498 [self setWebState:tab.webState]; |
497 [_searchResultsView setOpener:tab]; | 499 [_searchResultsView setOpener:tab]; |
498 } | 500 } |
499 | 501 |
500 - (void)setWebState:(web::WebState*)webState { | 502 - (void)setWebState:(web::WebState*)webState { |
501 [self disconnectWebState]; | 503 [self disconnectWebState]; |
502 if (webState) { | 504 if (webState) { |
503 _contextualSearchJsManager.reset(static_cast<JsContextualSearchManager*>( | 505 _contextualSearchJsManager = static_cast<JsContextualSearchManager*>( |
504 [webState->GetJSInjectionReceiver() | 506 [webState->GetJSInjectionReceiver() |
505 instanceOfClass:[JsContextualSearchManager class]])); | 507 instanceOfClass:[JsContextualSearchManager class]]); |
506 _webState = webState; | 508 _webState = webState; |
507 _webStateObserver->ObserveWebState(webState); | 509 _webStateObserver->ObserveWebState(webState); |
508 [self updateWebViewProxy:webState->GetWebViewProxy()]; | 510 [self updateWebViewProxy:webState->GetWebViewProxy()]; |
509 [self enableCurrentWebState]; | 511 [self enableCurrentWebState]; |
510 } else { | 512 } else { |
511 _webState = nullptr; | 513 _webState = nullptr; |
512 } | 514 } |
513 } | 515 } |
514 | 516 |
515 - (void)enableCurrentWebState { | 517 - (void)enableCurrentWebState { |
516 if (![self webState]) | 518 if (![self webState]) |
517 return; | 519 return; |
518 if (_enabled && [self webState]->ContentIsHTML()) { | 520 if (_enabled && [self webState]->ContentIsHTML()) { |
519 if (!_webStateEnabled) { | 521 if (!_webStateEnabled) { |
520 DOMAlteringLock::CreateForWebState([self webState]); | 522 DOMAlteringLock::CreateForWebState([self webState]); |
521 | 523 |
522 base::WeakNSObject<ContextualSearchController> weakSelf(self); | 524 __weak ContextualSearchController* weakSelf = self; |
523 auto callback = | 525 auto callback = base::BindBlockArc( |
524 base::BindBlock(^bool(const base::DictionaryValue& JSON, | 526 ^bool(const base::DictionaryValue& JSON, const GURL& originURL, |
525 const GURL& originURL, bool userIsInteracting) { | 527 bool userIsInteracting) { |
526 base::scoped_nsobject<ContextualSearchController> strongSelf( | 528 ContextualSearchController* strongSelf = weakSelf; |
527 [weakSelf retain]); | |
528 // |originURL| and |isInteracting| aren't used. | 529 // |originURL| and |isInteracting| aren't used. |
529 return [strongSelf handleScriptCommand:JSON]; | 530 return [strongSelf handleScriptCommand:JSON]; |
530 }); | 531 }); |
531 [self webState]->AddScriptCommandCallback(callback, kCommandPrefix); | 532 [self webState]->AddScriptCommandCallback(callback, kCommandPrefix); |
532 | 533 |
533 // |_doubleTapRecognizer| should be added to the web view before | 534 // |_doubleTapRecognizer| should be added to the web view before |
534 // |_tapRecognizer| so |_tapRecognizer| can require it to fail. | 535 // |_tapRecognizer| so |_tapRecognizer| can require it to fail. |
535 _doubleTapRecognizer.reset([[UITapGestureRecognizer alloc] | 536 _doubleTapRecognizer = |
536 initWithTarget:self | 537 [[UITapGestureRecognizer alloc] initWithTarget:self |
537 action:@selector(ignoreTap:)]); | 538 action:@selector(ignoreTap:)]; |
538 [_doubleTapRecognizer setDelegate:self]; | 539 [_doubleTapRecognizer setDelegate:self]; |
539 [_doubleTapRecognizer setNumberOfTapsRequired:2]; | 540 [_doubleTapRecognizer setNumberOfTapsRequired:2]; |
540 [_webViewProxy addGestureRecognizer:_doubleTapRecognizer]; | 541 [_webViewProxy addGestureRecognizer:_doubleTapRecognizer]; |
541 | 542 |
542 _tapRecognizer.reset([[UITapGestureRecognizer alloc] | 543 _tapRecognizer = [[UITapGestureRecognizer alloc] |
543 initWithTarget:self | 544 initWithTarget:self |
544 action:@selector(handleTapFrom:)]); | 545 action:@selector(handleTapFrom:)]; |
545 [_tapRecognizer setDelegate:self]; | 546 [_tapRecognizer setDelegate:self]; |
546 [_webViewProxy addGestureRecognizer:_tapRecognizer]; | 547 [_webViewProxy addGestureRecognizer:_tapRecognizer]; |
547 | 548 |
548 // Make sure that |_tapRecogngizer| doesn't fire if the web view's other | 549 // Make sure that |_tapRecogngizer| doesn't fire if the web view's other |
549 // non-single-finger non-single-tap recognizers fire. | 550 // non-single-finger non-single-tap recognizers fire. |
550 for (UIGestureRecognizer* recognizer in | 551 for (UIGestureRecognizer* recognizer in |
551 [[_tapRecognizer view] gestureRecognizers]) { | 552 [[_tapRecognizer view] gestureRecognizers]) { |
552 if ([recognizer isKindOfClass:[UITapGestureRecognizer class]] && | 553 if ([recognizer isKindOfClass:[UITapGestureRecognizer class]] && |
553 ([static_cast<UITapGestureRecognizer*>(recognizer) | 554 ([static_cast<UITapGestureRecognizer*>(recognizer) |
554 numberOfTapsRequired] > 1 || | 555 numberOfTapsRequired] > 1 || |
(...skipping 22 matching lines...) Expand all Loading... |
577 _webState->RemoveScriptCommandCallback(kCommandPrefix); | 578 _webState->RemoveScriptCommandCallback(kCommandPrefix); |
578 DOMAlteringLock::FromWebState(_webState)->Release(self); | 579 DOMAlteringLock::FromWebState(_webState)->Release(self); |
579 [_webViewProxy removeGestureRecognizer:_tapRecognizer]; | 580 [_webViewProxy removeGestureRecognizer:_tapRecognizer]; |
580 [_webViewProxy removeGestureRecognizer:_doubleTapRecognizer]; | 581 [_webViewProxy removeGestureRecognizer:_doubleTapRecognizer]; |
581 _webStateEnabled = NO; | 582 _webStateEnabled = NO; |
582 } | 583 } |
583 } | 584 } |
584 | 585 |
585 - (void)disconnectWebState { | 586 - (void)disconnectWebState { |
586 if (_webState) { | 587 if (_webState) { |
587 _contextualSearchJsManager.reset(); | 588 _contextualSearchJsManager = nil; |
588 _webStateObserver->ObserveWebState(nullptr); | 589 _webStateObserver->ObserveWebState(nullptr); |
589 [self updateWebViewProxy:nil]; | 590 [self updateWebViewProxy:nil]; |
590 [self disableCurrentWebState]; | 591 [self disableCurrentWebState]; |
591 } | 592 } |
592 } | 593 } |
593 | 594 |
594 - (void)updateDismissRecognizer { | 595 - (void)updateDismissRecognizer { |
595 if (!_panelView) | 596 if (!_panelView) |
596 return; | 597 return; |
597 if (!_dismissRecognizer) { | 598 if (!_dismissRecognizer) { |
598 _dismissRecognizer.reset([[WindowGestureObserver alloc] | 599 _dismissRecognizer = [[WindowGestureObserver alloc] |
599 initWithTarget:self | 600 initWithTarget:self |
600 action:@selector(handleWindowGesture:)]); | 601 action:@selector(handleWindowGesture:)]; |
601 [_dismissRecognizer setViewToExclude:_panelView]; | 602 [_dismissRecognizer setViewToExclude:_panelView]; |
602 [[_panelView window] addGestureRecognizer:_dismissRecognizer]; | 603 [[_panelView window] addGestureRecognizer:_dismissRecognizer]; |
603 } | 604 } |
604 | 605 |
605 [_dismissRecognizer | 606 [_dismissRecognizer |
606 setEnabled:[_panelView state] >= ContextualSearch::PEEKING]; | 607 setEnabled:[_panelView state] >= ContextualSearch::PEEKING]; |
607 } | 608 } |
608 | 609 |
609 - (void)showLearnMore { | 610 - (void)showLearnMore { |
610 [self dismissPane:ContextualSearch::UNKNOWN]; | 611 [self dismissPane:ContextualSearch::UNKNOWN]; |
611 GURL learnMoreUrl = google_util::AppendGoogleLocaleParam( | 612 GURL learnMoreUrl = google_util::AppendGoogleLocaleParam( |
612 GURL(l10n_util::GetStringUTF8(IDS_IOS_CONTEXTUAL_SEARCH_LEARN_MORE_URL)), | 613 GURL(l10n_util::GetStringUTF8(IDS_IOS_CONTEXTUAL_SEARCH_LEARN_MORE_URL)), |
613 GetApplicationContext()->GetApplicationLocale()); | 614 GetApplicationContext()->GetApplicationLocale()); |
614 [_controllerDelegate createTabFromContextualSearchController:learnMoreUrl]; | 615 [_controllerDelegate createTabFromContextualSearchController:learnMoreUrl]; |
615 } | 616 } |
616 | 617 |
617 - (void)dealloc { | 618 - (void)dealloc { |
618 [self close]; | 619 [self close]; |
619 [super dealloc]; | |
620 } | 620 } |
621 | 621 |
622 - (void)handleWindowGesture:(UIGestureRecognizer*)recognizer { | 622 - (void)handleWindowGesture:(UIGestureRecognizer*)recognizer { |
623 DCHECK(recognizer == _dismissRecognizer.get()); | 623 DCHECK(recognizer == _dismissRecognizer); |
624 [self dismissPane:ContextualSearch::BASE_PAGE_TAP]; | 624 [self dismissPane:ContextualSearch::BASE_PAGE_TAP]; |
625 } | 625 } |
626 | 626 |
627 - (BOOL)canExtractTapContext { | 627 - (BOOL)canExtractTapContext { |
628 web::URLVerificationTrustLevel trustLevel = web::kNone; | 628 web::URLVerificationTrustLevel trustLevel = web::kNone; |
629 GURL pageURL = [self webState]->GetCurrentURL(&trustLevel); | 629 GURL pageURL = [self webState]->GetCurrentURL(&trustLevel); |
630 return [self.permissions canExtractTapContextForURL:pageURL]; | 630 return [self.permissions canExtractTapContextForURL:pageURL]; |
631 } | 631 } |
632 | 632 |
633 - (void)initializeWebViewForContextualSearch { | 633 - (void)initializeWebViewForContextualSearch { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
699 if (command == "contextualSearch.selectionChanged") { | 699 if (command == "contextualSearch.selectionChanged") { |
700 std::string selectedText; | 700 std::string selectedText; |
701 if (!JSONCommand.GetString("text", &selectedText)) | 701 if (!JSONCommand.GetString("text", &selectedText)) |
702 return NO; | 702 return NO; |
703 bool selectionUpdated; | 703 bool selectionUpdated; |
704 if (!JSONCommand.GetBoolean("updated", &selectionUpdated)) | 704 if (!JSONCommand.GetBoolean("updated", &selectionUpdated)) |
705 selectionUpdated = false; | 705 selectionUpdated = false; |
706 bool selectionValid; | 706 bool selectionValid; |
707 if (!JSONCommand.GetBoolean("valid", &selectionValid)) | 707 if (!JSONCommand.GetBoolean("valid", &selectionValid)) |
708 selectionValid = true; | 708 selectionValid = true; |
709 base::WeakNSObject<ContextualSearchController> weakSelf(self); | 709 __weak ContextualSearchController* weakSelf = self; |
710 ProceduralBlockWithBool lockAction = ^(BOOL lockAcquired) { | 710 ProceduralBlockWithBool lockAction = ^(BOOL lockAcquired) { |
711 if (lockAcquired) { | 711 if (lockAcquired) { |
712 [weakSelf handleSelectionChanged:selectedText | 712 [weakSelf handleSelectionChanged:selectedText |
713 selectionUpdated:selectionUpdated | 713 selectionUpdated:selectionUpdated |
714 selectionValid:selectionValid]; | 714 selectionValid:selectionValid]; |
715 } | 715 } |
716 }; | 716 }; |
717 DOMAlteringLock::FromWebState([self webState])->Acquire(self, lockAction); | 717 DOMAlteringLock::FromWebState([self webState])->Acquire(self, lockAction); |
718 return YES; | 718 return YES; |
719 } | 719 } |
720 if (command == "contextualSearch.mutationEvent") { | 720 if (command == "contextualSearch.mutationEvent") { |
721 if ([_panelView state] <= ContextualSearch::PEEKING && | 721 if ([_panelView state] <= ContextualSearch::PEEKING && |
722 !_searchTermResolved) { | 722 !_searchTermResolved) { |
723 [self dismissPane:ContextualSearch::UNKNOWN]; | 723 [self dismissPane:ContextualSearch::UNKNOWN]; |
724 } | 724 } |
725 return YES; | 725 return YES; |
726 } | 726 } |
727 return NO; | 727 return NO; |
728 } | 728 } |
729 | 729 |
730 - (void)ignoreTap:(UIGestureRecognizer*)recognizer { | 730 - (void)ignoreTap:(UIGestureRecognizer*)recognizer { |
731 // This method is intentionally empty. It is intended to ignore the tap. | 731 // This method is intentionally empty. It is intended to ignore the tap. |
732 } | 732 } |
733 | 733 |
734 - (void)handleTapFrom:(UIGestureRecognizer*)recognizer { | 734 - (void)handleTapFrom:(UIGestureRecognizer*)recognizer { |
735 DCHECK(recognizer == _tapRecognizer.get()); | 735 DCHECK(recognizer == _tapRecognizer); |
736 // Taps will be triggered by long-presses to make a selection in the webview, | 736 // Taps will be triggered by long-presses to make a selection in the webview, |
737 // as well as 'regular' taps. Long-presses that create a selection will set | 737 // as well as 'regular' taps. Long-presses that create a selection will set |
738 // |_newSelectionDisplaying| as well as populating _selectedText (this happens | 738 // |_newSelectionDisplaying| as well as populating _selectedText (this happens |
739 // in -handleScriptCommand:). | 739 // in -handleScriptCommand:). |
740 | 740 |
741 // If we just dismissed, do not consider this tap. | 741 // If we just dismissed, do not consider this tap. |
742 NSTimeInterval dismissTimeout = [_lastDismiss timeIntervalSinceNow] + | 742 NSTimeInterval dismissTimeout = [_lastDismiss timeIntervalSinceNow] + |
743 kPreventTriggerAfterDismissDelaySeconds; | 743 kPreventTriggerAfterDismissDelaySeconds; |
744 | 744 |
745 // If the panel is already displayed, just dismiss it and return, unless the | 745 // If the panel is already displayed, just dismiss it and return, unless the |
(...skipping 21 matching lines...) Expand all Loading... |
767 CGPoint tapPoint = [recognizer locationInView:recognizer.view]; | 767 CGPoint tapPoint = [recognizer locationInView:recognizer.view]; |
768 // tapPoint is the coordinate of the tap in the webView. If the view is | 768 // tapPoint is the coordinate of the tap in the webView. If the view is |
769 // currently offset because a header is displayed, offset the tapPoint. | 769 // currently offset because a header is displayed, offset the tapPoint. |
770 tapPoint.y -= [_controllerDelegate currentHeaderHeight]; | 770 tapPoint.y -= [_controllerDelegate currentHeaderHeight]; |
771 | 771 |
772 // Handle tap asynchronously to monitor DOM modifications. See comment | 772 // Handle tap asynchronously to monitor DOM modifications. See comment |
773 // of |kDOMModificationDelaySeconds| for details. | 773 // of |kDOMModificationDelaySeconds| for details. |
774 dispatch_time_t dispatch = dispatch_time( | 774 dispatch_time_t dispatch = dispatch_time( |
775 DISPATCH_TIME_NOW, | 775 DISPATCH_TIME_NOW, |
776 static_cast<int64_t>(kDOMModificationDelaySeconds * NSEC_PER_SEC)); | 776 static_cast<int64_t>(kDOMModificationDelaySeconds * NSEC_PER_SEC)); |
777 base::WeakNSObject<ContextualSearchController> weakSelf(self); | 777 __weak ContextualSearchController* weakSelf = self; |
778 dispatch_after(dispatch, dispatch_get_main_queue(), ^{ | 778 dispatch_after(dispatch, dispatch_get_main_queue(), ^{ |
779 [weakSelf handleTapAtPoint:tapPoint]; | 779 [weakSelf handleTapAtPoint:tapPoint]; |
780 }); | 780 }); |
781 }; | 781 }; |
782 DOMAlteringLock::FromWebState([self webState])->Acquire(self, lockAction); | 782 DOMAlteringLock::FromWebState([self webState])->Acquire(self, lockAction); |
783 } | 783 } |
784 | 784 |
785 - (void)handleLongPressFrom:(UIGestureRecognizer*)recognizer { | 785 - (void)handleLongPressFrom:(UIGestureRecognizer*)recognizer { |
786 DCHECK(recognizer == _copyGestureRecognizer.get()); | 786 DCHECK(recognizer == _copyGestureRecognizer); |
787 if (recognizer.state != UIGestureRecognizerStateEnded) | 787 if (recognizer.state != UIGestureRecognizerStateEnded) |
788 return; | 788 return; |
789 | 789 |
790 // Put the resolved search term (or the current selected text) into the | 790 // Put the resolved search term (or the current selected text) into the |
791 // pasteboard. | 791 // pasteboard. |
792 std::string text; | 792 std::string text; |
793 if (!_resolvedSearch.display_text.empty()) { | 793 if (!_resolvedSearch.display_text.empty()) { |
794 text = _resolvedSearch.display_text; | 794 text = _resolvedSearch.display_text; |
795 } | 795 } |
796 | 796 |
(...skipping 23 matching lines...) Expand all Loading... |
820 std::string encoding = "UTF-8"; | 820 std::string encoding = "UTF-8"; |
821 | 821 |
822 CGPoint relativeTapPoint = point; | 822 CGPoint relativeTapPoint = point; |
823 CGSize contentSize = [_webViewProxy scrollViewProxy].contentSize; | 823 CGSize contentSize = [_webViewProxy scrollViewProxy].contentSize; |
824 relativeTapPoint.x += [_webViewProxy scrollViewProxy].contentOffset.x; | 824 relativeTapPoint.x += [_webViewProxy scrollViewProxy].contentOffset.x; |
825 relativeTapPoint.y += [_webViewProxy scrollViewProxy].contentOffset.y; | 825 relativeTapPoint.y += [_webViewProxy scrollViewProxy].contentOffset.y; |
826 | 826 |
827 relativeTapPoint.x /= contentSize.width; | 827 relativeTapPoint.x /= contentSize.width; |
828 relativeTapPoint.y /= contentSize.height; | 828 relativeTapPoint.y /= contentSize.height; |
829 | 829 |
830 base::WeakNSProtocol<id<CRWWebViewProxy>> weakWebViewProxy( | 830 __weak id<CRWWebViewProxy> weakWebViewProxy = _webViewProxy; |
831 _webViewProxy.get()); | |
832 void (^handler)(NSString*) = ^(NSString* result) { | 831 void (^handler)(NSString*) = ^(NSString* result) { |
833 [_tapRecognizer setEnabled:YES]; | 832 [_tapRecognizer setEnabled:YES]; |
834 // If there has been an error in the javascript, return can be nil. | 833 // If there has been an error in the javascript, return can be nil. |
835 if (!result || _currentTapCancelled) | 834 if (!result || _currentTapCancelled) |
836 return; | 835 return; |
837 | 836 |
838 // Parse JSON. | 837 // Parse JSON. |
839 const std::string json = base::SysNSStringToUTF8(result); | 838 const std::string json = base::SysNSStringToUTF8(result); |
840 std::unique_ptr<base::Value> parsedResult( | 839 std::unique_ptr<base::Value> parsedResult( |
841 base::JSONReader::Read(json, false)); | 840 base::JSONReader::Read(json, false)); |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1015 | 1014 |
1016 if (_resolvedSearch.is_invalid) { | 1015 if (_resolvedSearch.is_invalid) { |
1017 [self dismissPane:ContextualSearch::UNKNOWN]; | 1016 [self dismissPane:ContextualSearch::UNKNOWN]; |
1018 } else { | 1017 } else { |
1019 _searchTermResolved = YES; | 1018 _searchTermResolved = YES; |
1020 [_headerView | 1019 [_headerView |
1021 setSearchTerm:base::SysUTF8ToNSString(_resolvedSearch.display_text) | 1020 setSearchTerm:base::SysUTF8ToNSString(_resolvedSearch.display_text) |
1022 animated:[_panelView state] != ContextualSearch::DISMISSED]; | 1021 animated:[_panelView state] != ContextualSearch::DISMISSED]; |
1023 if (_resolvedSearch.start_offset != -1 && | 1022 if (_resolvedSearch.start_offset != -1 && |
1024 _resolvedSearch.end_offset != -1) { | 1023 _resolvedSearch.end_offset != -1) { |
1025 base::WeakNSObject<ContextualSearchController> weakSelf(self); | 1024 __weak ContextualSearchController* weakSelf = self; |
1026 [_contextualSearchJsManager | 1025 [_contextualSearchJsManager |
1027 expandHighlightToStartOffset:_resolvedSearch.start_offset | 1026 expandHighlightToStartOffset:_resolvedSearch.start_offset |
1028 endOffset:_resolvedSearch.end_offset | 1027 endOffset:_resolvedSearch.end_offset |
1029 completionHandler:^(id result, NSError* error) { | 1028 completionHandler:^(id result, NSError* error) { |
1030 [weakSelf handleHighlightJSResult:result | 1029 [weakSelf handleHighlightJSResult:result |
1031 withError:error]; | 1030 withError:error]; |
1032 }]; | 1031 }]; |
1033 } | 1032 } |
1034 GURL url = _delegate->GetURLForResolvedSearch(_resolvedSearch, true); | 1033 GURL url = _delegate->GetURLForResolvedSearch(_resolvedSearch, true); |
1035 [_searchResultsView createTabForSearch:url | 1034 [_searchResultsView createTabForSearch:url |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1069 animated:[_panelView state] != ContextualSearch::DISMISSED]; | 1068 animated:[_panelView state] != ContextualSearch::DISMISSED]; |
1070 } | 1069 } |
1071 } else { | 1070 } else { |
1072 ContextualSearch::RecordSelectionIsValid(false); | 1071 ContextualSearch::RecordSelectionIsValid(false); |
1073 [self dismissPane:ContextualSearch::INVALID_SELECTION]; | 1072 [self dismissPane:ContextualSearch::INVALID_SELECTION]; |
1074 } | 1073 } |
1075 } | 1074 } |
1076 - (void)scrollToShowSelection:(CRWWebViewScrollViewProxy*)scrollView { | 1075 - (void)scrollToShowSelection:(CRWWebViewScrollViewProxy*)scrollView { |
1077 if (!scrollView || _preventScrollToShowSelection) | 1076 if (!scrollView || _preventScrollToShowSelection) |
1078 return; | 1077 return; |
1079 if (!_contextualHighlightView.get()) { | 1078 if (!_contextualHighlightView) { |
1080 return; | 1079 return; |
1081 } | 1080 } |
1082 CGRect highlightBoundingRect = [_contextualHighlightView boundingRect]; | 1081 CGRect highlightBoundingRect = [_contextualHighlightView boundingRect]; |
1083 if (CGRectIsNull(highlightBoundingRect)) { | 1082 if (CGRectIsNull(highlightBoundingRect)) { |
1084 return; | 1083 return; |
1085 } | 1084 } |
1086 | 1085 |
1087 // Do the maths without the insets. | 1086 // Do the maths without the insets. |
1088 CGPoint scrollPoint = [scrollView contentOffset]; | 1087 CGPoint scrollPoint = [scrollView contentOffset]; |
1089 scrollPoint.y += scrollView.contentInset.top; | 1088 scrollPoint.y += scrollView.contentInset.top; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1157 | 1156 |
1158 scrollPoint.y -= scrollView.contentInset.top; | 1157 scrollPoint.y -= scrollView.contentInset.top; |
1159 scrollPoint.x -= scrollView.contentInset.left; | 1158 scrollPoint.x -= scrollView.contentInset.left; |
1160 [scrollView setContentOffset:scrollPoint animated:YES]; | 1159 [scrollView setContentOffset:scrollPoint animated:YES]; |
1161 } | 1160 } |
1162 | 1161 |
1163 - (void)highlightRects:(NSArray*)rects { | 1162 - (void)highlightRects:(NSArray*)rects { |
1164 if (![self webState]) { | 1163 if (![self webState]) { |
1165 return; | 1164 return; |
1166 } | 1165 } |
1167 if (!_contextualHighlightView.get() && [rects count]) { | 1166 if (!_contextualHighlightView && [rects count]) { |
1168 CGRect frame = [[self webState]->GetWebViewProxy() frame]; | 1167 CGRect frame = [[self webState]->GetWebViewProxy() frame]; |
1169 ContextualSearchHighlighterView* highlightView = | 1168 ContextualSearchHighlighterView* highlightView = |
1170 [[[ContextualSearchHighlighterView alloc] initWithFrame:frame | 1169 [[ContextualSearchHighlighterView alloc] initWithFrame:frame |
1171 delegate:self] | 1170 delegate:self]; |
1172 autorelease]; | 1171 _contextualHighlightView = highlightView; |
1173 _contextualHighlightView.reset(highlightView); | |
1174 [[self webState]->GetWebViewProxy() addSubview:highlightView]; | 1172 [[self webState]->GetWebViewProxy() addSubview:highlightView]; |
1175 } | 1173 } |
1176 CGPoint scroll = [[_webViewProxy scrollViewProxy] contentOffset]; | 1174 CGPoint scroll = [[_webViewProxy scrollViewProxy] contentOffset]; |
1177 [_contextualHighlightView | 1175 [_contextualHighlightView |
1178 highlightRects:rects | 1176 highlightRects:rects |
1179 withOffset:[_controllerDelegate currentHeaderHeight] | 1177 withOffset:[_controllerDelegate currentHeaderHeight] |
1180 zoom:[[_webViewProxy scrollViewProxy] zoomScale] | 1178 zoom:[[_webViewProxy scrollViewProxy] zoomScale] |
1181 scroll:scroll]; | 1179 scroll:scroll]; |
1182 } | 1180 } |
1183 | 1181 |
(...skipping 22 matching lines...) Expand all Loading... |
1206 if (_closed) | 1204 if (_closed) |
1207 return; | 1205 return; |
1208 | 1206 |
1209 _closed = YES; | 1207 _closed = YES; |
1210 [self disableCurrentWebState]; | 1208 [self disableCurrentWebState]; |
1211 [self setWebState:nil]; | 1209 [self setWebState:nil]; |
1212 [_headerView removeGestureRecognizer:_copyGestureRecognizer]; | 1210 [_headerView removeGestureRecognizer:_copyGestureRecognizer]; |
1213 [[_panelView window] removeGestureRecognizer:_dismissRecognizer]; | 1211 [[_panelView window] removeGestureRecognizer:_dismissRecognizer]; |
1214 _delegate.reset(); | 1212 _delegate.reset(); |
1215 [_searchResultsView setActive:NO]; | 1213 [_searchResultsView setActive:NO]; |
1216 _searchResultsView.reset(); | 1214 _searchResultsView = nil; |
1217 } | 1215 } |
1218 | 1216 |
1219 #pragma mark - Promo view management | 1217 #pragma mark - Promo view management |
1220 | 1218 |
1221 - (void)userOptedInFromPromo:(BOOL)optIn { | 1219 - (void)userOptedInFromPromo:(BOOL)optIn { |
1222 if (optIn) { | 1220 if (optIn) { |
1223 self.permissions.preferenceState = TouchToSearch::ENABLED; | 1221 self.permissions.preferenceState = TouchToSearch::ENABLED; |
1224 [_promoView closeAnimated:YES]; | 1222 [_promoView closeAnimated:YES]; |
1225 [_promoView setDisabled:YES]; | 1223 [_promoView setDisabled:YES]; |
1226 } else { | 1224 } else { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1282 // Dragged up. | 1280 // Dragged up. |
1283 [self coverPane:ContextualSearch::SWIPE]; | 1281 [self coverPane:ContextualSearch::SWIPE]; |
1284 } | 1282 } |
1285 } | 1283 } |
1286 [self updateHighlight]; | 1284 [self updateHighlight]; |
1287 } | 1285 } |
1288 | 1286 |
1289 - (void)panelWillPromote:(ContextualSearchPanelView*)panel { | 1287 - (void)panelWillPromote:(ContextualSearchPanelView*)panel { |
1290 DCHECK(panel == _panelView); | 1288 DCHECK(panel == _panelView); |
1291 [panel removeMotionObserver:self]; | 1289 [panel removeMotionObserver:self]; |
1292 _panelView.reset(); | 1290 _panelView = nil; |
1293 [self setState:ContextualSearch::DISMISSED | 1291 [self setState:ContextualSearch::DISMISSED |
1294 reason:ContextualSearch::TAB_PROMOTION]; | 1292 reason:ContextualSearch::TAB_PROMOTION]; |
1295 } | 1293 } |
1296 | 1294 |
1297 #pragma mark - ContextualSearchPanelTapHandler | 1295 #pragma mark - ContextualSearchPanelTapHandler |
1298 | 1296 |
1299 - (void)panelWasTapped:(UIGestureRecognizer*)gesture { | 1297 - (void)panelWasTapped:(UIGestureRecognizer*)gesture { |
1300 // Tapping when peeking switches to previewing. | 1298 // Tapping when peeking switches to previewing. |
1301 // Tapping otherwise turns the panel into a tab. | 1299 // Tapping otherwise turns the panel into a tab. |
1302 if ([_panelView state] == ContextualSearch::PEEKING) { | 1300 if ([_panelView state] == ContextualSearch::PEEKING) { |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1416 - (void) | 1414 - (void) |
1417 dismissPaneWithJavascriptCompletionHandler:(ProceduralBlock)completionHandler | 1415 dismissPaneWithJavascriptCompletionHandler:(ProceduralBlock)completionHandler |
1418 reason:(ContextualSearch::StateChangeReason) | 1416 reason:(ContextualSearch::StateChangeReason) |
1419 reason { | 1417 reason { |
1420 [self cleanUpWebStateForDismissWithCompletion:completionHandler]; | 1418 [self cleanUpWebStateForDismissWithCompletion:completionHandler]; |
1421 [self setState:ContextualSearch::DISMISSED reason:reason]; | 1419 [self setState:ContextualSearch::DISMISSED reason:reason]; |
1422 } | 1420 } |
1423 | 1421 |
1424 - (void)cleanUpWebStateForDismissWithCompletion: | 1422 - (void)cleanUpWebStateForDismissWithCompletion: |
1425 (ProceduralBlock)completionHandler { | 1423 (ProceduralBlock)completionHandler { |
1426 _lastDismiss.reset([[NSDate date] retain]); | 1424 _lastDismiss = [NSDate date]; |
1427 _currentTapCancelled = YES; | 1425 _currentTapCancelled = YES; |
1428 ContextualSearch::PanelState originalState = [_panelView state]; | 1426 ContextualSearch::PanelState originalState = [_panelView state]; |
1429 if (originalState == ContextualSearch::DISMISSED) { | 1427 if (originalState == ContextualSearch::DISMISSED) { |
1430 DCHECK(![_searchResultsView active]); | 1428 DCHECK(![_searchResultsView active]); |
1431 if ([self webState]) { | 1429 if ([self webState]) { |
1432 DOMAlteringLock* lock = DOMAlteringLock::FromWebState([self webState]); | 1430 DOMAlteringLock* lock = DOMAlteringLock::FromWebState([self webState]); |
1433 if (lock) { | 1431 if (lock) { |
1434 lock->Release(self); | 1432 lock->Release(self); |
1435 } | 1433 } |
1436 } | 1434 } |
1437 if (completionHandler) | 1435 if (completionHandler) |
1438 completionHandler(); | 1436 completionHandler(); |
1439 return; | 1437 return; |
1440 } | 1438 } |
1441 | 1439 |
1442 [_doubleTapRecognizer setEnabled:YES]; | 1440 [_doubleTapRecognizer setEnabled:YES]; |
1443 _searchContext.reset(); | 1441 _searchContext.reset(); |
1444 [_searchResultsView setActive:NO]; | 1442 [_searchResultsView setActive:NO]; |
1445 _delegate->CancelSearchTermRequest(); | 1443 _delegate->CancelSearchTermRequest(); |
1446 _selectedText = ""; | 1444 _selectedText = ""; |
1447 | 1445 |
1448 ContextualSearchDelegate::SearchResolution blank; | 1446 ContextualSearchDelegate::SearchResolution blank; |
1449 _resolvedSearch = blank; | 1447 _resolvedSearch = blank; |
1450 if (completionHandler) { | 1448 if (completionHandler) { |
1451 base::WeakNSObject<ContextualSearchController> weakSelf(self); | 1449 __weak ContextualSearchController* weakSelf = self; |
1452 ProceduralBlock javaScriptCompletion = ^{ | 1450 ProceduralBlock javaScriptCompletion = ^{ |
1453 if ([self webState]) { | 1451 if ([weakSelf webState]) { |
1454 DOMAlteringLock::FromWebState([self webState])->Release(self); | 1452 DOMAlteringLock::FromWebState([weakSelf webState])->Release(weakSelf); |
1455 completionHandler(); | 1453 completionHandler(); |
1456 } | 1454 } |
1457 }; | 1455 }; |
1458 [self highlightRects:nil]; | 1456 [self highlightRects:nil]; |
1459 [_contextualSearchJsManager clearHighlight]; | 1457 [_contextualSearchJsManager clearHighlight]; |
1460 javaScriptCompletion(); | 1458 javaScriptCompletion(); |
1461 } else { | 1459 } else { |
1462 [self highlightRects:nil]; | 1460 [self highlightRects:nil]; |
1463 [_contextualSearchJsManager clearHighlight]; | 1461 [_contextualSearchJsManager clearHighlight]; |
1464 DOMAlteringLock::FromWebState([self webState])->Release(self); | 1462 DOMAlteringLock::FromWebState([self webState])->Release(self); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1513 | 1511 |
1514 - (void)promoViewAcceptTapped { | 1512 - (void)promoViewAcceptTapped { |
1515 [self userOptedInFromPromo:YES]; | 1513 [self userOptedInFromPromo:YES]; |
1516 } | 1514 } |
1517 | 1515 |
1518 - (void)promoViewDeclineTapped { | 1516 - (void)promoViewDeclineTapped { |
1519 [self userOptedInFromPromo:NO]; | 1517 [self userOptedInFromPromo:NO]; |
1520 } | 1518 } |
1521 | 1519 |
1522 - (void)promoViewSettingsTapped { | 1520 - (void)promoViewSettingsTapped { |
1523 base::scoped_nsobject<GenericChromeCommand> command( | 1521 GenericChromeCommand* command = [[GenericChromeCommand alloc] |
1524 [[GenericChromeCommand alloc] | 1522 initWithTag:IDC_SHOW_CONTEXTUAL_SEARCH_SETTINGS]; |
1525 initWithTag:IDC_SHOW_CONTEXTUAL_SEARCH_SETTINGS]); | |
1526 UIWindow* main_window = [[UIApplication sharedApplication] keyWindow]; | 1523 UIWindow* main_window = [[UIApplication sharedApplication] keyWindow]; |
1527 [main_window chromeExecuteCommand:command]; | 1524 [main_window chromeExecuteCommand:command]; |
1528 } | 1525 } |
1529 | 1526 |
1530 #pragma mark - ContextualSearchWebStateObserver methods | 1527 #pragma mark - ContextualSearchWebStateObserver methods |
1531 | 1528 |
1532 - (void)webState:(web::WebState*)webState | 1529 - (void)webState:(web::WebState*)webState |
1533 pageLoadedWithStatus:(web::PageLoadCompletionStatus)loadStatus { | 1530 pageLoadedWithStatus:(web::PageLoadCompletionStatus)loadStatus { |
1534 if (loadStatus != web::PageLoadCompletionStatus::SUCCESS) | 1531 if (loadStatus != web::PageLoadCompletionStatus::SUCCESS) |
1535 return; | 1532 return; |
1536 | 1533 |
1537 [self movePanelOffscreen]; | 1534 [self movePanelOffscreen]; |
1538 _isScriptInjected = NO; | 1535 _isScriptInjected = NO; |
1539 [self enableCurrentWebState]; | 1536 [self enableCurrentWebState]; |
1540 } | 1537 } |
1541 | 1538 |
1542 - (void)webStateDestroyed:(web::WebState*)webState { | 1539 - (void)webStateDestroyed:(web::WebState*)webState { |
1543 [self updateWebViewProxy:nil]; | 1540 [self updateWebViewProxy:nil]; |
1544 } | 1541 } |
1545 | 1542 |
1546 #pragma mark - UIGestureRecognizerDelegate Methods | 1543 #pragma mark - UIGestureRecognizerDelegate Methods |
1547 | 1544 |
1548 // Ensures that |_tapRecognizer| and |_doubleTapRecognizer| cooperate with all | 1545 // Ensures that |_tapRecognizer| and |_doubleTapRecognizer| cooperate with all |
1549 // other gesture recognizers. | 1546 // other gesture recognizers. |
1550 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer | 1547 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer |
1551 shouldRecognizeSimultaneouslyWithGestureRecognizer: | 1548 shouldRecognizeSimultaneouslyWithGestureRecognizer: |
1552 (UIGestureRecognizer*)otherGestureRecognizer { | 1549 (UIGestureRecognizer*)otherGestureRecognizer { |
1553 return gestureRecognizer == _tapRecognizer.get() || | 1550 return gestureRecognizer == _tapRecognizer || |
1554 gestureRecognizer == _doubleTapRecognizer.get(); | 1551 gestureRecognizer == _doubleTapRecognizer; |
1555 } | 1552 } |
1556 | 1553 |
1557 #pragma mark - CRWWebViewScrollViewObserver methods | 1554 #pragma mark - CRWWebViewScrollViewObserver methods |
1558 | 1555 |
1559 - (void)webViewScrollViewWillBeginDragging: | 1556 - (void)webViewScrollViewWillBeginDragging: |
1560 (CRWWebViewScrollViewProxy*)webViewScrollViewProxy { | 1557 (CRWWebViewScrollViewProxy*)webViewScrollViewProxy { |
1561 [self dismissPane:ContextualSearch::BASE_PAGE_SCROLL]; | 1558 [self dismissPane:ContextualSearch::BASE_PAGE_SCROLL]; |
1562 [_tapRecognizer setEnabled:NO]; | 1559 [_tapRecognizer setEnabled:NO]; |
1563 } | 1560 } |
1564 | 1561 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1616 | 1613 |
1617 - (void)touchToSearchPermissionsUpdated { | 1614 - (void)touchToSearchPermissionsUpdated { |
1618 // This method is already invoked asynchronously, so it's safe to | 1615 // This method is already invoked asynchronously, so it's safe to |
1619 // synchronously attempt to enable the feature. | 1616 // synchronously attempt to enable the feature. |
1620 [self enableContextualSearch:YES]; | 1617 [self enableContextualSearch:YES]; |
1621 } | 1618 } |
1622 | 1619 |
1623 #pragma mark - ContextualSearchHighlighterDelegate methods | 1620 #pragma mark - ContextualSearchHighlighterDelegate methods |
1624 | 1621 |
1625 - (void)updateHighlight { | 1622 - (void)updateHighlight { |
1626 base::WeakNSObject<ContextualSearchController> weakSelf(self); | 1623 __weak ContextualSearchController* weakSelf = self; |
1627 [_contextualSearchJsManager | 1624 [_contextualSearchJsManager |
1628 highlightRectsWithCompletionHandler:^void(id result, NSError* error) { | 1625 highlightRectsWithCompletionHandler:^void(id result, NSError* error) { |
1629 [weakSelf handleHighlightJSResult:result withError:error]; | 1626 [weakSelf handleHighlightJSResult:result withError:error]; |
1630 }]; | 1627 }]; |
1631 } | 1628 } |
1632 | 1629 |
1633 @end | 1630 @end |
OLD | NEW |