| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/ui/omnibox/omnibox_text_field_ios.h" | 5 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h" |
| 6 | 6 |
| 7 #import <CoreText/CoreText.h> | 7 #import <CoreText/CoreText.h> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/mac/foundation_util.h" | 11 #include "base/mac/foundation_util.h" |
| 12 #include "base/mac/objc_property_releaser.h" | 12 |
| 13 #include "base/mac/scoped_nsobject.h" | |
| 14 #include "base/strings/sys_string_conversions.h" | 13 #include "base/strings/sys_string_conversions.h" |
| 15 #include "components/grit/components_scaled_resources.h" | 14 #include "components/grit/components_scaled_resources.h" |
| 16 #include "components/omnibox/browser/autocomplete_input.h" | 15 #include "components/omnibox/browser/autocomplete_input.h" |
| 17 #include "ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.h" | 16 #include "ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.h" |
| 18 #import "ios/chrome/browser/ui/animation_util.h" | 17 #import "ios/chrome/browser/ui/animation_util.h" |
| 19 #include "ios/chrome/browser/ui/omnibox/omnibox_util.h" | 18 #include "ios/chrome/browser/ui/omnibox/omnibox_util.h" |
| 20 #import "ios/chrome/browser/ui/reversed_animation.h" | 19 #import "ios/chrome/browser/ui/reversed_animation.h" |
| 21 #include "ios/chrome/browser/ui/rtl_geometry.h" | 20 #include "ios/chrome/browser/ui/rtl_geometry.h" |
| 22 #include "ios/chrome/browser/ui/ui_util.h" | 21 #include "ios/chrome/browser/ui/ui_util.h" |
| 23 #import "ios/chrome/browser/ui/uikit_ui_util.h" | 22 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 24 #import "ios/chrome/common/material_timing.h" | 23 #import "ios/chrome/common/material_timing.h" |
| 25 #include "ios/chrome/grit/ios_strings.h" | 24 #include "ios/chrome/grit/ios_strings.h" |
| 26 #include "ios/chrome/grit/ios_theme_resources.h" | 25 #include "ios/chrome/grit/ios_theme_resources.h" |
| 27 #include "skia/ext/skia_utils_ios.h" | 26 #include "skia/ext/skia_utils_ios.h" |
| 28 #include "third_party/google_toolbox_for_mac/src/iPhone/GTMFadeTruncatingLabel.h
" | 27 #include "third_party/google_toolbox_for_mac/src/iPhone/GTMFadeTruncatingLabel.h
" |
| 29 #include "ui/base/l10n/l10n_util_mac.h" | 28 #include "ui/base/l10n/l10n_util_mac.h" |
| 30 #include "ui/gfx/color_palette.h" | 29 #include "ui/gfx/color_palette.h" |
| 31 #include "ui/gfx/image/image.h" | 30 #include "ui/gfx/image/image.h" |
| 32 #import "ui/gfx/ios/NSString+CrStringDrawing.h" | 31 #import "ui/gfx/ios/NSString+CrStringDrawing.h" |
| 33 #include "ui/gfx/scoped_cg_context_save_gstate_mac.h" | 32 #include "ui/gfx/scoped_cg_context_save_gstate_mac.h" |
| 34 | 33 |
| 34 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 35 #error "This file requires ARC support." |
| 36 #endif |
| 37 |
| 35 namespace { | 38 namespace { |
| 36 const CGFloat kFontSize = 16; | 39 const CGFloat kFontSize = 16; |
| 37 const CGFloat kEditingRectX = 16; | 40 const CGFloat kEditingRectX = 16; |
| 38 const CGFloat kEditingRectWidthInset = 10; | 41 const CGFloat kEditingRectWidthInset = 10; |
| 39 const CGFloat kTextInset = 8; | 42 const CGFloat kTextInset = 8; |
| 40 const CGFloat kTextInsetWithChip = 3; | 43 const CGFloat kTextInsetWithChip = 3; |
| 41 const CGFloat kTextInsetNoLeftView = 12; | 44 const CGFloat kTextInsetNoLeftView = 12; |
| 42 const CGFloat kImageInset = 9; | 45 const CGFloat kImageInset = 9; |
| 43 const CGFloat kClearButtonRightMarginIphone = 7; | 46 const CGFloat kClearButtonRightMarginIphone = 7; |
| 44 const CGFloat kClearButtonRightMarginIpad = 12; | 47 const CGFloat kClearButtonRightMarginIpad = 12; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 // conversion from NSString to base::string16 if possible. | 88 // conversion from NSString to base::string16 if possible. |
| 86 - (NSString*)nsDisplayedText; | 89 - (NSString*)nsDisplayedText; |
| 87 | 90 |
| 88 @end | 91 @end |
| 89 | 92 |
| 90 #pragma mark - | 93 #pragma mark - |
| 91 #pragma mark OmniboxTextFieldIOS | 94 #pragma mark OmniboxTextFieldIOS |
| 92 | 95 |
| 93 @implementation OmniboxTextFieldIOS { | 96 @implementation OmniboxTextFieldIOS { |
| 94 // Currently selected chip text. Nil if no chip. | 97 // Currently selected chip text. Nil if no chip. |
| 95 base::scoped_nsobject<NSString> _chipText; | 98 NSString* _chipText; |
| 96 base::scoped_nsobject<UILabel> _selection; | 99 UILabel* _selection; |
| 97 base::scoped_nsobject<UILabel> _preEditStaticLabel; | 100 UILabel* _preEditStaticLabel; |
| 98 NSString* _preEditText; | 101 UIFont* _font; |
| 99 base::scoped_nsobject<UIFont> _font; | 102 UIColor* _displayedTextColor; |
| 100 base::scoped_nsobject<UIColor> _displayedTextColor; | 103 UIColor* _displayedTintColor; |
| 101 base::scoped_nsobject<UIColor> _displayedTintColor; | |
| 102 UIColor* _selectedTextBackgroundColor; | |
| 103 UIColor* _placeholderTextColor; | |
| 104 | 104 |
| 105 // The 'Copy URL' menu item is sometimes shown in the edit menu, so keep it | 105 // The 'Copy URL' menu item is sometimes shown in the edit menu, so keep it |
| 106 // around to make adding/removing easier. | 106 // around to make adding/removing easier. |
| 107 base::scoped_nsobject<UIMenuItem> _copyUrlMenuItem; | 107 UIMenuItem* _copyUrlMenuItem; |
| 108 | |
| 109 base::mac::ObjCPropertyReleaser _propertyReleaser_OmniboxTextFieldIOS; | |
| 110 } | 108 } |
| 111 | 109 |
| 112 @synthesize leftViewImageId = _leftViewImageId; | 110 @synthesize leftViewImageId = _leftViewImageId; |
| 113 @synthesize preEditText = _preEditText; | 111 @synthesize preEditText = _preEditText; |
| 114 @synthesize clearingPreEditText = _clearingPreEditText; | 112 @synthesize clearingPreEditText = _clearingPreEditText; |
| 115 @synthesize selectedTextBackgroundColor = _selectedTextBackgroundColor; | 113 @synthesize selectedTextBackgroundColor = _selectedTextBackgroundColor; |
| 116 @synthesize placeholderTextColor = _placeholderTextColor; | 114 @synthesize placeholderTextColor = _placeholderTextColor; |
| 117 @synthesize incognito = _incognito; | 115 @synthesize incognito = _incognito; |
| 118 | 116 |
| 119 // Overload to allow for code-based initialization. | 117 // Overload to allow for code-based initialization. |
| 120 - (instancetype)initWithFrame:(CGRect)frame { | 118 - (instancetype)initWithFrame:(CGRect)frame { |
| 121 return [self initWithFrame:frame | 119 return [self initWithFrame:frame |
| 122 font:[UIFont systemFontOfSize:kFontSize] | 120 font:[UIFont systemFontOfSize:kFontSize] |
| 123 textColor:TextColor() | 121 textColor:TextColor() |
| 124 tintColor:nil]; | 122 tintColor:nil]; |
| 125 } | 123 } |
| 126 | 124 |
| 127 - (instancetype)initWithFrame:(CGRect)frame | 125 - (instancetype)initWithFrame:(CGRect)frame |
| 128 font:(UIFont*)font | 126 font:(UIFont*)font |
| 129 textColor:(UIColor*)textColor | 127 textColor:(UIColor*)textColor |
| 130 tintColor:(UIColor*)tintColor { | 128 tintColor:(UIColor*)tintColor { |
| 131 self = [super initWithFrame:frame]; | 129 self = [super initWithFrame:frame]; |
| 132 if (self) { | 130 if (self) { |
| 133 _propertyReleaser_OmniboxTextFieldIOS.Init(self, | 131 _font = font; |
| 134 [OmniboxTextFieldIOS class]); | 132 _displayedTextColor = textColor; |
| 135 _font.reset([font retain]); | |
| 136 _displayedTextColor.reset([textColor retain]); | |
| 137 if (tintColor) { | 133 if (tintColor) { |
| 138 [self setTintColor:tintColor]; | 134 [self setTintColor:tintColor]; |
| 139 _displayedTintColor.reset([tintColor retain]); | 135 _displayedTintColor = tintColor; |
| 140 } else { | 136 } else { |
| 141 _displayedTintColor.reset([self.tintColor retain]); | 137 _displayedTintColor = self.tintColor; |
| 142 } | 138 } |
| 143 [self setFont:_font]; | 139 [self setFont:_font]; |
| 144 [self setTextColor:_displayedTextColor]; | 140 [self setTextColor:_displayedTextColor]; |
| 145 [self setClearButtonMode:UITextFieldViewModeNever]; | 141 [self setClearButtonMode:UITextFieldViewModeNever]; |
| 146 [self setRightViewMode:UITextFieldViewModeAlways]; | 142 [self setRightViewMode:UITextFieldViewModeAlways]; |
| 147 [self setAutocorrectionType:UITextAutocorrectionTypeNo]; | 143 [self setAutocorrectionType:UITextAutocorrectionTypeNo]; |
| 148 [self setAutocapitalizationType:UITextAutocapitalizationTypeNone]; | 144 [self setAutocapitalizationType:UITextAutocapitalizationTypeNone]; |
| 149 [self setEnablesReturnKeyAutomatically:YES]; | 145 [self setEnablesReturnKeyAutomatically:YES]; |
| 150 [self setReturnKeyType:UIReturnKeyGo]; | 146 [self setReturnKeyType:UIReturnKeyGo]; |
| 151 [self setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter]; | 147 [self setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter]; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 } | 199 } |
| 204 | 200 |
| 205 // Method called when the users touches the text input. This will accept the | 201 // Method called when the users touches the text input. This will accept the |
| 206 // autocompleted text. | 202 // autocompleted text. |
| 207 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { | 203 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { |
| 208 if ([self isPreEditing]) { | 204 if ([self isPreEditing]) { |
| 209 [self exitPreEditState]; | 205 [self exitPreEditState]; |
| 210 [super selectAll:nil]; | 206 [super selectAll:nil]; |
| 211 } | 207 } |
| 212 | 208 |
| 213 if (!_selection.get()) { | 209 if (!_selection) { |
| 214 [super touchesBegan:touches withEvent:event]; | 210 [super touchesBegan:touches withEvent:event]; |
| 215 return; | 211 return; |
| 216 } | 212 } |
| 217 | 213 |
| 218 // Only consider a single touch. | 214 // Only consider a single touch. |
| 219 UITouch* touch = [touches anyObject]; | 215 UITouch* touch = [touches anyObject]; |
| 220 if (!touch) | 216 if (!touch) |
| 221 return; | 217 return; |
| 222 | 218 |
| 223 // Accept selection. | 219 // Accept selection. |
| 224 base::scoped_nsobject<NSString> newText([[self nsDisplayedText] copy]); | 220 NSString* newText = [[self nsDisplayedText] copy]; |
| 225 [self clearAutocompleteText]; | 221 [self clearAutocompleteText]; |
| 226 [self setText:newText]; | 222 [self setText:newText]; |
| 227 } | 223 } |
| 228 | 224 |
| 229 // Gets the bounds of the rect covering the URL. | 225 // Gets the bounds of the rect covering the URL. |
| 230 - (CGRect)preEditLabelRectForBounds:(CGRect)bounds { | 226 - (CGRect)preEditLabelRectForBounds:(CGRect)bounds { |
| 231 return [self editingRectForBounds:self.bounds]; | 227 return [self editingRectForBounds:self.bounds]; |
| 232 } | 228 } |
| 233 | 229 |
| 234 // Creates a UILabel based on the current dimension of the text field and | 230 // Creates a UILabel based on the current dimension of the text field and |
| 235 // displays the URL in the UILabel so it appears properly aligned to the URL. | 231 // displays the URL in the UILabel so it appears properly aligned to the URL. |
| 236 - (void)enterPreEditState { | 232 - (void)enterPreEditState { |
| 237 // Empty omnibox should show the insertion point immediately. There is | 233 // Empty omnibox should show the insertion point immediately. There is |
| 238 // nothing to erase. | 234 // nothing to erase. |
| 239 if (!self.text.length || UIAccessibilityIsVoiceOverRunning()) | 235 if (!self.text.length || UIAccessibilityIsVoiceOverRunning()) |
| 240 return; | 236 return; |
| 241 | 237 |
| 242 // Remembers the initial text input to compute the diff of what was there | 238 // Remembers the initial text input to compute the diff of what was there |
| 243 // and what was typed. | 239 // and what was typed. |
| 244 [self setPreEditText:self.text]; | 240 [self setPreEditText:self.text]; |
| 245 | 241 |
| 246 // Adjusts the placement so static URL lines up perfectly with UITextField. | 242 // Adjusts the placement so static URL lines up perfectly with UITextField. |
| 247 DCHECK(!_preEditStaticLabel.get()); | 243 DCHECK(!_preEditStaticLabel); |
| 248 CGRect rect = [self preEditLabelRectForBounds:self.bounds]; | 244 CGRect rect = [self preEditLabelRectForBounds:self.bounds]; |
| 249 _preEditStaticLabel.reset([[UILabel alloc] initWithFrame:rect]); | 245 _preEditStaticLabel = [[UILabel alloc] initWithFrame:rect]; |
| 250 _preEditStaticLabel.get().backgroundColor = [UIColor clearColor]; | 246 _preEditStaticLabel.backgroundColor = [UIColor clearColor]; |
| 251 _preEditStaticLabel.get().opaque = YES; | 247 _preEditStaticLabel.opaque = YES; |
| 252 _preEditStaticLabel.get().font = _font; | 248 _preEditStaticLabel.font = _font; |
| 253 _preEditStaticLabel.get().textColor = _displayedTextColor; | 249 _preEditStaticLabel.textColor = _displayedTextColor; |
| 254 _preEditStaticLabel.get().lineBreakMode = NSLineBreakByTruncatingHead; | 250 _preEditStaticLabel.lineBreakMode = NSLineBreakByTruncatingHead; |
| 255 | 251 |
| 256 NSDictionary* attributes = | 252 NSDictionary* attributes = |
| 257 @{NSBackgroundColorAttributeName : [self selectedTextBackgroundColor]}; | 253 @{NSBackgroundColorAttributeName : [self selectedTextBackgroundColor]}; |
| 258 base::scoped_nsobject<NSAttributedString> preEditString( | 254 NSAttributedString* preEditString = |
| 259 [[NSAttributedString alloc] initWithString:self.text | 255 [[NSAttributedString alloc] initWithString:self.text |
| 260 attributes:attributes]); | 256 attributes:attributes]; |
| 261 [_preEditStaticLabel setAttributedText:preEditString]; | 257 [_preEditStaticLabel setAttributedText:preEditString]; |
| 262 _preEditStaticLabel.get().textAlignment = [self preEditTextAlignment]; | 258 _preEditStaticLabel.textAlignment = [self preEditTextAlignment]; |
| 263 [self addSubview:_preEditStaticLabel]; | 259 [self addSubview:_preEditStaticLabel]; |
| 264 } | 260 } |
| 265 | 261 |
| 266 - (NSTextAlignment)bestAlignmentForText:(NSString*)text { | 262 - (NSTextAlignment)bestAlignmentForText:(NSString*)text { |
| 267 if (text.length) { | 263 if (text.length) { |
| 268 NSString* lang = CFBridgingRelease(CFStringTokenizerCopyBestStringLanguage( | 264 NSString* lang = CFBridgingRelease(CFStringTokenizerCopyBestStringLanguage( |
| 269 (CFStringRef)text, CFRangeMake(0, text.length))); | 265 (CFStringRef)text, CFRangeMake(0, text.length))); |
| 270 | 266 |
| 271 if ([NSLocale characterDirectionForLanguage:lang] == | 267 if ([NSLocale characterDirectionForLanguage:lang] == |
| 272 NSLocaleLanguageDirectionRightToLeft) { | 268 NSLocaleLanguageDirectionRightToLeft) { |
| 273 return NSTextAlignmentRight; | 269 return NSTextAlignmentRight; |
| 274 } | 270 } |
| 275 } | 271 } |
| 276 return NSTextAlignmentLeft; | 272 return NSTextAlignmentLeft; |
| 277 } | 273 } |
| 278 | 274 |
| 279 - (NSTextAlignment)bestTextAlignment { | 275 - (NSTextAlignment)bestTextAlignment { |
| 280 if ([self isFirstResponder]) { | 276 if ([self isFirstResponder]) { |
| 281 return [self bestAlignmentForText:[self text]]; | 277 return [self bestAlignmentForText:[self text]]; |
| 282 } | 278 } |
| 283 return NSTextAlignmentNatural; | 279 return NSTextAlignmentNatural; |
| 284 } | 280 } |
| 285 | 281 |
| 286 - (NSTextAlignment)preEditTextAlignment { | 282 - (NSTextAlignment)preEditTextAlignment { |
| 287 // If the pre-edit text is wider than the omnibox, right-align the text so it | 283 // If the pre-edit text is wider than the omnibox, right-align the text so it |
| 288 // ends at the same x coord as the blue selection box. | 284 // ends at the same x coord as the blue selection box. |
| 289 CGSize textSize = | 285 CGSize textSize = |
| 290 [_preEditStaticLabel.get().text cr_pixelAlignedSizeWithFont:_font]; | 286 [_preEditStaticLabel.text cr_pixelAlignedSizeWithFont:_font]; |
| 291 BOOL isLTR = [self bestTextAlignment] == NSTextAlignmentLeft; | 287 BOOL isLTR = [self bestTextAlignment] == NSTextAlignmentLeft; |
| 292 return textSize.width < _preEditStaticLabel.get().frame.size.width | 288 return textSize.width < _preEditStaticLabel.frame.size.width |
| 293 ? (isLTR ? NSTextAlignmentLeft : NSTextAlignmentRight) | 289 ? (isLTR ? NSTextAlignmentLeft : NSTextAlignmentRight) |
| 294 : (isLTR ? NSTextAlignmentRight : NSTextAlignmentLeft); | 290 : (isLTR ? NSTextAlignmentRight : NSTextAlignmentLeft); |
| 295 } | 291 } |
| 296 | 292 |
| 297 - (void)layoutSubviews { | 293 - (void)layoutSubviews { |
| 298 [super layoutSubviews]; | 294 [super layoutSubviews]; |
| 299 if ([self isPreEditing]) { | 295 if ([self isPreEditing]) { |
| 300 CGRect rect = [self preEditLabelRectForBounds:self.bounds]; | 296 CGRect rect = [self preEditLabelRectForBounds:self.bounds]; |
| 301 [_preEditStaticLabel setFrame:rect]; | 297 [_preEditStaticLabel setFrame:rect]; |
| 302 | 298 |
| 303 // Update text alignment since the pre-edit label's frame changed. | 299 // Update text alignment since the pre-edit label's frame changed. |
| 304 _preEditStaticLabel.get().textAlignment = [self preEditTextAlignment]; | 300 _preEditStaticLabel.textAlignment = [self preEditTextAlignment]; |
| 305 [self hideTextAndCursor]; | 301 [self hideTextAndCursor]; |
| 306 } else if (!_selection) { | 302 } else if (!_selection) { |
| 307 [self showTextAndCursor]; | 303 [self showTextAndCursor]; |
| 308 } | 304 } |
| 309 } | 305 } |
| 310 | 306 |
| 311 // Finishes pre-edit state by removing the UILabel with the URL. | 307 // Finishes pre-edit state by removing the UILabel with the URL. |
| 312 - (void)exitPreEditState { | 308 - (void)exitPreEditState { |
| 313 [self setPreEditText:nil]; | 309 [self setPreEditText:nil]; |
| 314 if (_preEditStaticLabel) { | 310 if (_preEditStaticLabel) { |
| 315 [_preEditStaticLabel removeFromSuperview]; | 311 [_preEditStaticLabel removeFromSuperview]; |
| 316 _preEditStaticLabel.reset(nil); | 312 _preEditStaticLabel = nil; |
| 317 [self showTextAndCursor]; | 313 [self showTextAndCursor]; |
| 318 } | 314 } |
| 319 } | 315 } |
| 320 | 316 |
| 321 - (UIColor*)displayedTextColor { | 317 - (UIColor*)displayedTextColor { |
| 322 return _displayedTextColor; | 318 return _displayedTextColor; |
| 323 } | 319 } |
| 324 | 320 |
| 325 // Returns whether we are processing the first touch event on the text field. | 321 // Returns whether we are processing the first touch event on the text field. |
| 326 - (BOOL)isPreEditing { | 322 - (BOOL)isPreEditing { |
| 327 return !![self preEditText]; | 323 return !![self preEditText]; |
| 328 } | 324 } |
| 329 | 325 |
| 330 - (void)enableLeftViewButton:(BOOL)isEnabled { | 326 - (void)enableLeftViewButton:(BOOL)isEnabled { |
| 331 if ([self leftView]) | 327 if ([self leftView]) |
| 332 [(UIButton*)[self leftView] setEnabled:isEnabled]; | 328 [(UIButton*)[self leftView] setEnabled:isEnabled]; |
| 333 } | 329 } |
| 334 | 330 |
| 335 - (NSString*)nsDisplayedText { | 331 - (NSString*)nsDisplayedText { |
| 336 if (_selection.get()) | 332 if (_selection) |
| 337 return [_selection text]; | 333 return [_selection text]; |
| 338 return [self text]; | 334 return [self text]; |
| 339 } | 335 } |
| 340 | 336 |
| 341 - (base::string16)displayedText { | 337 - (base::string16)displayedText { |
| 342 return base::SysNSStringToUTF16([self nsDisplayedText]); | 338 return base::SysNSStringToUTF16([self nsDisplayedText]); |
| 343 } | 339 } |
| 344 | 340 |
| 345 - (base::string16)autocompleteText { | 341 - (base::string16)autocompleteText { |
| 346 DCHECK_LT([[self text] length], [[_selection text] length]) | 342 DCHECK_LT([[self text] length], [[_selection text] length]) |
| 347 << "[_selection text] and [self text] are out of sync. " | 343 << "[_selection text] and [self text] are out of sync. " |
| 348 << "Please email justincohen@ and rohitrao@ if you see this."; | 344 << "Please email justincohen@ and rohitrao@ if you see this."; |
| 349 if (_selection.get() && [[_selection text] length] > [[self text] length]) { | 345 if (_selection && [[_selection text] length] > [[self text] length]) { |
| 350 return base::SysNSStringToUTF16( | 346 return base::SysNSStringToUTF16( |
| 351 [[_selection text] substringFromIndex:[[self text] length]]); | 347 [[_selection text] substringFromIndex:[[self text] length]]); |
| 352 } | 348 } |
| 353 return base::string16(); | 349 return base::string16(); |
| 354 } | 350 } |
| 355 | 351 |
| 356 - (void)select:(id)sender { | 352 - (void)select:(id)sender { |
| 357 if ([self isPreEditing]) { | 353 if ([self isPreEditing]) { |
| 358 [self exitPreEditState]; | 354 [self exitPreEditState]; |
| 359 } | 355 } |
| 360 [super select:sender]; | 356 [super select:sender]; |
| 361 } | 357 } |
| 362 | 358 |
| 363 - (void)selectAll:(id)sender { | 359 - (void)selectAll:(id)sender { |
| 364 if ([self isPreEditing]) { | 360 if ([self isPreEditing]) { |
| 365 [self exitPreEditState]; | 361 [self exitPreEditState]; |
| 366 } | 362 } |
| 367 if (_selection.get()) { | 363 if (_selection) { |
| 368 base::scoped_nsobject<NSString> newText([[self nsDisplayedText] copy]); | 364 NSString* newText = [[self nsDisplayedText] copy]; |
| 369 [self clearAutocompleteText]; | 365 [self clearAutocompleteText]; |
| 370 [self setText:newText]; | 366 [self setText:newText]; |
| 371 } | 367 } |
| 372 [super selectAll:sender]; | 368 [super selectAll:sender]; |
| 373 } | 369 } |
| 374 | 370 |
| 375 // Creates the SelectedTextLabel if it doesn't already exist and adds it as a | 371 // Creates the SelectedTextLabel if it doesn't already exist and adds it as a |
| 376 // subview. | 372 // subview. |
| 377 - (void)createSelectionViewIfNecessary { | 373 - (void)createSelectionViewIfNecessary { |
| 378 if (_selection.get()) | 374 if (_selection) |
| 379 return; | 375 return; |
| 380 | 376 |
| 381 _selection.reset([[UILabel alloc] initWithFrame:CGRectZero]); | 377 _selection = [[UILabel alloc] initWithFrame:CGRectZero]; |
| 382 [_selection setFont:_font]; | 378 [_selection setFont:_font]; |
| 383 [_selection setTextColor:_displayedTextColor]; | 379 [_selection setTextColor:_displayedTextColor]; |
| 384 [_selection setOpaque:NO]; | 380 [_selection setOpaque:NO]; |
| 385 [_selection setBackgroundColor:[UIColor clearColor]]; | 381 [_selection setBackgroundColor:[UIColor clearColor]]; |
| 386 [self addSubview:_selection]; | 382 [self addSubview:_selection]; |
| 387 [self hideTextAndCursor]; | 383 [self hideTextAndCursor]; |
| 388 } | 384 } |
| 389 | 385 |
| 390 - (BOOL)isShowingQueryRefinementChip { | 386 - (BOOL)isShowingQueryRefinementChip { |
| 391 return (_chipText && ([self isFirstResponder] || [self isPreEditing])); | 387 return (_chipText && ([self isFirstResponder] || [self isPreEditing])); |
| 392 } | 388 } |
| 393 | 389 |
| 394 - (void)updateLeftView { | 390 - (void)updateLeftView { |
| 395 const CGFloat kChipTextTopInset = 3.0; | 391 const CGFloat kChipTextTopInset = 3.0; |
| 396 const CGFloat kChipTextLeftInset = 3.0; | 392 const CGFloat kChipTextLeftInset = 3.0; |
| 397 | 393 |
| 398 UIButton* leftViewButton = (UIButton*)self.leftView; | 394 UIButton* leftViewButton = (UIButton*)self.leftView; |
| 399 // Only set the chip image if the omnibox is in focus. | 395 // Only set the chip image if the omnibox is in focus. |
| 400 if ([self isShowingQueryRefinementChip]) { | 396 if ([self isShowingQueryRefinementChip]) { |
| 401 [leftViewButton setTitle:_chipText forState:UIControlStateNormal]; | 397 [leftViewButton setTitle:_chipText forState:UIControlStateNormal]; |
| 402 [leftViewButton setImage:nil forState:UIControlStateNormal]; | 398 [leftViewButton setImage:nil forState:UIControlStateNormal]; |
| 403 [leftViewButton | 399 [leftViewButton |
| 404 setTitleEdgeInsets:UIEdgeInsetsMake(kChipTextTopInset, | 400 setTitleEdgeInsets:UIEdgeInsetsMake(kChipTextTopInset, |
| 405 kChipTextLeftInset, 0, 0)]; | 401 kChipTextLeftInset, 0, 0)]; |
| 406 // For iPhone, the left view is only updated when not in editing mode (i.e. | 402 // For iPhone, the left view is only updated when not in editing mode (i.e. |
| 407 // the text field is not first responder). | 403 // the text field is not first responder). |
| 408 } else if (_leftViewImageId && (IsIPadIdiom() || ![self isFirstResponder])) { | 404 } else if (_leftViewImageId && (IsIPadIdiom() || ![self isFirstResponder])) { |
| 409 UIImage* image = [NativeImage(_leftViewImageId) | 405 UIImage* image = [NativeImage(_leftViewImageId) |
| 410 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; | 406 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; |
| 411 UIImageView* imageView = | 407 UIImageView* imageView = [[UIImageView alloc] initWithImage:image]; |
| 412 [[[UIImageView alloc] initWithImage:image] autorelease]; | |
| 413 [leftViewButton setImage:imageView.image forState:UIControlStateNormal]; | 408 [leftViewButton setImage:imageView.image forState:UIControlStateNormal]; |
| 414 [leftViewButton setTitle:nil forState:UIControlStateNormal]; | 409 [leftViewButton setTitle:nil forState:UIControlStateNormal]; |
| 415 UIColor* tint = [UIColor whiteColor]; | 410 UIColor* tint = [UIColor whiteColor]; |
| 416 if (!_incognito) { | 411 if (!_incognito) { |
| 417 switch (_leftViewImageId) { | 412 switch (_leftViewImageId) { |
| 418 case IDR_IOS_LOCATION_BAR_HTTP: | 413 case IDR_IOS_LOCATION_BAR_HTTP: |
| 419 tint = [UIColor darkGrayColor]; | 414 tint = [UIColor darkGrayColor]; |
| 420 break; | 415 break; |
| 421 case IDR_IOS_OMNIBOX_HTTPS_VALID: | 416 case IDR_IOS_OMNIBOX_HTTPS_VALID: |
| 422 tint = skia::UIColorFromSkColor(gfx::kGoogleGreen700); | 417 tint = skia::UIColorFromSkColor(gfx::kGoogleGreen700); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 // Extract substrings for the permanent text and the autocomplete text. The | 463 // Extract substrings for the permanent text and the autocomplete text. The |
| 469 // former needs to retain any text attributes from the original string. | 464 // former needs to retain any text attributes from the original string. |
| 470 NSRange fieldRange = NSMakeRange(0, [text length] - autocompleteLength); | 465 NSRange fieldRange = NSMakeRange(0, [text length] - autocompleteLength); |
| 471 NSAttributedString* fieldText = | 466 NSAttributedString* fieldText = |
| 472 [text attributedSubstringFromRange:fieldRange]; | 467 [text attributedSubstringFromRange:fieldRange]; |
| 473 | 468 |
| 474 if (autocompleteLength > 0) { | 469 if (autocompleteLength > 0) { |
| 475 // Creating |autocompleteText| from |[text string]| has the added bonus of | 470 // Creating |autocompleteText| from |[text string]| has the added bonus of |
| 476 // removing all the previously set attributes. This way the autocomplete | 471 // removing all the previously set attributes. This way the autocomplete |
| 477 // text doesn't have a highlighted protocol, etc. | 472 // text doesn't have a highlighted protocol, etc. |
| 478 base::scoped_nsobject<NSMutableAttributedString> autocompleteText( | 473 NSMutableAttributedString* autocompleteText = |
| 479 [[NSMutableAttributedString alloc] initWithString:[text string]]); | 474 [[NSMutableAttributedString alloc] initWithString:[text string]]; |
| 480 | 475 |
| 481 [self createSelectionViewIfNecessary]; | 476 [self createSelectionViewIfNecessary]; |
| 482 DCHECK(_selection.get()); | 477 DCHECK(_selection); |
| 483 [autocompleteText | 478 [autocompleteText |
| 484 addAttribute:NSBackgroundColorAttributeName | 479 addAttribute:NSBackgroundColorAttributeName |
| 485 value:[self selectedTextBackgroundColor] | 480 value:[self selectedTextBackgroundColor] |
| 486 range:NSMakeRange([fieldText length], autocompleteLength)]; | 481 range:NSMakeRange([fieldText length], autocompleteLength)]; |
| 487 [_selection setAttributedText:autocompleteText]; | 482 [_selection setAttributedText:autocompleteText]; |
| 488 [_selection setTextAlignment:[self bestTextAlignment]]; | 483 [_selection setTextAlignment:[self bestTextAlignment]]; |
| 489 } else { | 484 } else { |
| 490 [self clearAutocompleteText]; | 485 [self clearAutocompleteText]; |
| 491 } | 486 } |
| 492 | 487 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 505 - (UIColor*)selectedTextBackgroundColor { | 500 - (UIColor*)selectedTextBackgroundColor { |
| 506 return _selectedTextBackgroundColor ? _selectedTextBackgroundColor | 501 return _selectedTextBackgroundColor ? _selectedTextBackgroundColor |
| 507 : [UIColor colorWithRed:204.0 / 255 | 502 : [UIColor colorWithRed:204.0 / 255 |
| 508 green:221.0 / 255 | 503 green:221.0 / 255 |
| 509 blue:237.0 / 255 | 504 blue:237.0 / 255 |
| 510 alpha:1.0]; | 505 alpha:1.0]; |
| 511 } | 506 } |
| 512 | 507 |
| 513 // Ensures that attributedText always uses the proper style attributes. | 508 // Ensures that attributedText always uses the proper style attributes. |
| 514 - (void)setAttributedText:(NSAttributedString*)attributedText { | 509 - (void)setAttributedText:(NSAttributedString*)attributedText { |
| 515 base::scoped_nsobject<NSMutableAttributedString> mutableText( | 510 NSMutableAttributedString* mutableText = [attributedText mutableCopy]; |
| 516 [attributedText mutableCopy]); | |
| 517 NSRange entireString = NSMakeRange(0, [mutableText length]); | 511 NSRange entireString = NSMakeRange(0, [mutableText length]); |
| 518 | 512 |
| 519 // Set the font. | 513 // Set the font. |
| 520 [mutableText addAttribute:NSFontAttributeName value:_font range:entireString]; | 514 [mutableText addAttribute:NSFontAttributeName value:_font range:entireString]; |
| 521 | 515 |
| 522 // When editing, use the default text color for all text. | 516 // When editing, use the default text color for all text. |
| 523 if (self.editing) { | 517 if (self.editing) { |
| 524 // Hide the text when the |_selection| label is displayed. | 518 // Hide the text when the |_selection| label is displayed. |
| 525 UIColor* textColor = | 519 UIColor* textColor = |
| 526 _selection ? [UIColor clearColor] : _displayedTextColor.get(); | 520 _selection ? [UIColor clearColor] : _displayedTextColor; |
| 527 [mutableText addAttribute:NSForegroundColorAttributeName | 521 [mutableText addAttribute:NSForegroundColorAttributeName |
| 528 value:textColor | 522 value:textColor |
| 529 range:entireString]; | 523 range:entireString]; |
| 530 } else { | 524 } else { |
| 531 base::scoped_nsobject<NSMutableParagraphStyle> style( | 525 NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init]; |
| 532 [[NSMutableParagraphStyle alloc] init]); | |
| 533 // URLs have their text direction set to to LTR (avoids RTL characters | 526 // URLs have their text direction set to to LTR (avoids RTL characters |
| 534 // making the URL render from right to left, as per RFC 3987 Section 4.1). | 527 // making the URL render from right to left, as per RFC 3987 Section 4.1). |
| 535 [style setBaseWritingDirection:NSWritingDirectionLeftToRight]; | 528 [style setBaseWritingDirection:NSWritingDirectionLeftToRight]; |
| 536 | 529 |
| 537 // Set linebreak mode to 'clipping' to ensure the text is never elided. | 530 // Set linebreak mode to 'clipping' to ensure the text is never elided. |
| 538 // This is a workaround for iOS 6, where it appears that | 531 // This is a workaround for iOS 6, where it appears that |
| 539 // [self.attributedText size] is not wide enough for the string (e.g. a URL | 532 // [self.attributedText size] is not wide enough for the string (e.g. a URL |
| 540 // else ending with '.com' will be elided to end with '.c...'). It appears | 533 // else ending with '.com' will be elided to end with '.c...'). It appears |
| 541 // to be off by one point so clipping is acceptable as it doesn't actually | 534 // to be off by one point so clipping is acceptable as it doesn't actually |
| 542 // cut off any of the text. | 535 // cut off any of the text. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 572 textRangeFromPosition:[self | 565 textRangeFromPosition:[self |
| 573 beginningOfDocument] | 566 beginningOfDocument] |
| 574 toPosition:[self endOfDocument]]]; | 567 toPosition:[self endOfDocument]]]; |
| 575 } | 568 } |
| 576 | 569 |
| 577 - (void)setPlaceholder:(NSString*)placeholder { | 570 - (void)setPlaceholder:(NSString*)placeholder { |
| 578 if (placeholder && _placeholderTextColor) { | 571 if (placeholder && _placeholderTextColor) { |
| 579 NSDictionary* attributes = | 572 NSDictionary* attributes = |
| 580 @{NSForegroundColorAttributeName : _placeholderTextColor}; | 573 @{NSForegroundColorAttributeName : _placeholderTextColor}; |
| 581 self.attributedPlaceholder = | 574 self.attributedPlaceholder = |
| 582 [[[NSAttributedString alloc] initWithString:placeholder | 575 [[NSAttributedString alloc] initWithString:placeholder |
| 583 attributes:attributes] autorelease]; | 576 attributes:attributes]; |
| 584 } else { | 577 } else { |
| 585 [super setPlaceholder:placeholder]; | 578 [super setPlaceholder:placeholder]; |
| 586 } | 579 } |
| 587 } | 580 } |
| 588 | 581 |
| 589 - (void)setText:(NSString*)text { | 582 - (void)setText:(NSString*)text { |
| 590 NSAttributedString* as = | 583 NSAttributedString* as = [[NSAttributedString alloc] initWithString:text]; |
| 591 [[[NSAttributedString alloc] initWithString:text] autorelease]; | |
| 592 if (self.text.length > 0 && as.length == 0) { | 584 if (self.text.length > 0 && as.length == 0) { |
| 593 // Remove the fade animations before the subviews are removed. | 585 // Remove the fade animations before the subviews are removed. |
| 594 [self cleanUpFadeAnimations]; | 586 [self cleanUpFadeAnimations]; |
| 595 } | 587 } |
| 596 [self setTextInternal:as autocompleteLength:0]; | 588 [self setTextInternal:as autocompleteLength:0]; |
| 597 } | 589 } |
| 598 | 590 |
| 599 - (void)setText:(NSAttributedString*)text | 591 - (void)setText:(NSAttributedString*)text |
| 600 userTextLength:(size_t)userTextLength { | 592 userTextLength:(size_t)userTextLength { |
| 601 DCHECK_LE(userTextLength, [text length]); | 593 DCHECK_LE(userTextLength, [text length]); |
| 602 | 594 |
| 603 NSUInteger autocompleteLength = [text length] - userTextLength; | 595 NSUInteger autocompleteLength = [text length] - userTextLength; |
| 604 [self setTextInternal:text autocompleteLength:autocompleteLength]; | 596 [self setTextInternal:text autocompleteLength:autocompleteLength]; |
| 605 } | 597 } |
| 606 | 598 |
| 607 - (void)setChipText:(NSString*)chipName { | 599 - (void)setChipText:(NSString*)chipName { |
| 608 _chipText.reset(); | 600 _chipText = nil; |
| 609 if ([chipName length]) { | 601 if ([chipName length]) { |
| 610 if ([self bestAlignmentForText:chipName] == NSTextAlignmentLeft) | 602 if ([self bestAlignmentForText:chipName] == NSTextAlignmentLeft) |
| 611 chipName = [chipName stringByAppendingString:@":"]; | 603 chipName = [chipName stringByAppendingString:@":"]; |
| 612 _chipText.reset([chipName copy]); | 604 _chipText = [chipName copy]; |
| 613 } | 605 } |
| 614 [self updateLeftView]; | 606 [self updateLeftView]; |
| 615 } | 607 } |
| 616 | 608 |
| 617 - (BOOL)hasAutocompleteText { | 609 - (BOOL)hasAutocompleteText { |
| 618 return !!_selection.get(); | 610 return !!_selection; |
| 619 } | 611 } |
| 620 | 612 |
| 621 - (void)clearAutocompleteText { | 613 - (void)clearAutocompleteText { |
| 622 if (_selection) { | 614 if (_selection) { |
| 623 [_selection removeFromSuperview]; | 615 [_selection removeFromSuperview]; |
| 624 _selection.reset(nil); | 616 _selection = nil; |
| 625 [self showTextAndCursor]; | 617 [self showTextAndCursor]; |
| 626 } | 618 } |
| 627 } | 619 } |
| 628 | 620 |
| 629 - (BOOL)isColorHidden:(UIColor*)color { | 621 - (BOOL)isColorHidden:(UIColor*)color { |
| 630 return ([color isEqual:[UIColor clearColor]] || | 622 return ([color isEqual:[UIColor clearColor]] || |
| 631 CGColorGetAlpha(color.CGColor) < 0.05); | 623 CGColorGetAlpha(color.CGColor) < 0.05); |
| 632 } | 624 } |
| 633 | 625 |
| 634 // Set the text field's text and cursor to their displayed colors. To be called | 626 // Set the text field's text and cursor to their displayed colors. To be called |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 985 [self offsetFromPosition:beginning toPosition:[selectedRange start]]; | 977 [self offsetFromPosition:beginning toPosition:[selectedRange start]]; |
| 986 NSInteger length = [self offsetFromPosition:[selectedRange start] | 978 NSInteger length = [self offsetFromPosition:[selectedRange start] |
| 987 toPosition:[selectedRange end]]; | 979 toPosition:[selectedRange end]]; |
| 988 return NSMakeRange(start, length); | 980 return NSMakeRange(start, length); |
| 989 } | 981 } |
| 990 | 982 |
| 991 - (BOOL)becomeFirstResponder { | 983 - (BOOL)becomeFirstResponder { |
| 992 if (![super becomeFirstResponder]) | 984 if (![super becomeFirstResponder]) |
| 993 return NO; | 985 return NO; |
| 994 | 986 |
| 995 if (!_copyUrlMenuItem.get()) { | 987 if (!_copyUrlMenuItem) { |
| 996 NSString* const kTitle = l10n_util::GetNSString(IDS_IOS_COPY_URL); | 988 NSString* const kTitle = l10n_util::GetNSString(IDS_IOS_COPY_URL); |
| 997 _copyUrlMenuItem.reset( | 989 _copyUrlMenuItem = |
| 998 [[UIMenuItem alloc] initWithTitle:kTitle action:@selector(copyUrl:)]); | 990 [[UIMenuItem alloc] initWithTitle:kTitle action:@selector(copyUrl:)]; |
| 999 } | 991 } |
| 1000 | 992 |
| 1001 // Add the "Copy URL" menu item to the |sharedMenuController| if necessary. | 993 // Add the "Copy URL" menu item to the |sharedMenuController| if necessary. |
| 1002 UIMenuController* menuController = [UIMenuController sharedMenuController]; | 994 UIMenuController* menuController = [UIMenuController sharedMenuController]; |
| 1003 if (menuController.menuItems) { | 995 if (menuController.menuItems) { |
| 1004 if (![menuController.menuItems containsObject:_copyUrlMenuItem]) { | 996 if (![menuController.menuItems containsObject:_copyUrlMenuItem]) { |
| 1005 menuController.menuItems = | 997 menuController.menuItems = |
| 1006 [menuController.menuItems arrayByAddingObject:_copyUrlMenuItem]; | 998 [menuController.menuItems arrayByAddingObject:_copyUrlMenuItem]; |
| 1007 } | 999 } |
| 1008 } else { | 1000 } else { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1042 // Disable the RTL arrow menu item. The omnibox sets alignment based on the | 1034 // Disable the RTL arrow menu item. The omnibox sets alignment based on the |
| 1043 // text in the field, and should not be overridden. | 1035 // text in the field, and should not be overridden. |
| 1044 if ([NSStringFromSelector(action) hasPrefix:@"makeTextWritingDirection"]) { | 1036 if ([NSStringFromSelector(action) hasPrefix:@"makeTextWritingDirection"]) { |
| 1045 return NO; | 1037 return NO; |
| 1046 } | 1038 } |
| 1047 | 1039 |
| 1048 return [super canPerformAction:action withSender:sender]; | 1040 return [super canPerformAction:action withSender:sender]; |
| 1049 } | 1041 } |
| 1050 | 1042 |
| 1051 @end | 1043 @end |
| OLD | NEW |