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 |