Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / location_bar / location_bar_view_mac.mm
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/app/chrome_command_ids.h"
16 #import "chrome/browser/app_controller_mac.h"
17 #include "chrome/browser/command_updater.h"
18 #include "chrome/browser/defaults.h"
19 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
20 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
21 #include "chrome/browser/extensions/extension_action.h"
22 #include "chrome/browser/extensions/location_bar_controller.h"
23 #include "chrome/browser/extensions/tab_helper.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/search/instant_service.h"
26 #include "chrome/browser/search/instant_service_factory.h"
27 #include "chrome/browser/search/search.h"
28 #include "chrome/browser/search_engines/template_url_service_factory.h"
29 #include "chrome/browser/translate/chrome_translate_client.h"
30 #include "chrome/browser/translate/translate_service.h"
31 #include "chrome/browser/ui/browser_instant_controller.h"
32 #include "chrome/browser/ui/browser_list.h"
33 #import "chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.h"
34 #import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
35 #import "chrome/browser/ui/cocoa/first_run_bubble_controller.h"
36 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
37 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
38 #import "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h"
39 #import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h"
40 #import "chrome/browser/ui/cocoa/location_bar/generated_credit_card_decoration.h"
41 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
42 #import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
43 #import "chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.h"
44 #import "chrome/browser/ui/cocoa/location_bar/mic_search_decoration.h"
45 #import "chrome/browser/ui/cocoa/location_bar/origin_chip_decoration.h"
46 #import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h"
47 #import "chrome/browser/ui/cocoa/location_bar/search_button_decoration.h"
48 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
49 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
50 #import "chrome/browser/ui/cocoa/location_bar/translate_decoration.h"
51 #import "chrome/browser/ui/cocoa/location_bar/zoom_decoration.h"
52 #import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
53 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
54 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
55 #import "chrome/browser/ui/omnibox/omnibox_popup_model.h"
56 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
57 #include "chrome/browser/ui/tabs/tab_strip_model.h"
58 #include "chrome/browser/ui/toolbar/toolbar_model.h"
59 #include "chrome/browser/ui/zoom/zoom_controller.h"
60 #include "chrome/common/chrome_switches.h"
61 #include "chrome/common/pref_names.h"
62 #include "components/search_engines/template_url.h"
63 #include "components/search_engines/template_url_service.h"
64 #include "components/translate/core/browser/language_state.h"
65 #include "content/public/browser/web_contents.h"
66 #include "extensions/browser/extension_system.h"
67 #include "extensions/common/extension.h"
68 #include "extensions/common/permissions/permissions_data.h"
69 #include "grit/components_scaled_resources.h"
70 #include "grit/theme_resources.h"
71 #include "net/base/net_util.h"
72 #include "skia/ext/skia_utils_mac.h"
73 #import "ui/base/cocoa/cocoa_base_utils.h"
74 #include "ui/base/l10n/l10n_util_mac.h"
75 #include "ui/gfx/image/image.h"
76
77 using content::WebContents;
78
79 namespace {
80
81 // Vertical space between the bottom edge of the location_bar and the first run
82 // bubble arrow point.
83 const static int kFirstRunBubbleYOffset = 1;
84
85 // Functor for moving BookmarkManagerPrivate page actions to the right via
86 // stable_partition.
87 bool PageActionHasBookmarkManagerPrivate(PageActionDecoration* decoration) {
88   return decoration->GetExtension()->permissions_data()->HasAPIPermission(
89       extensions::APIPermission::kBookmarkManagerPrivate);
90 }
91
92 }  // namespace
93
94 // TODO(shess): This code is mostly copied from the gtk
95 // implementation.  Make sure it's all appropriate and flesh it out.
96
97 LocationBarViewMac::LocationBarViewMac(AutocompleteTextField* field,
98                                        CommandUpdater* command_updater,
99                                        Profile* profile,
100                                        Browser* browser)
101     : LocationBar(profile),
102       OmniboxEditController(command_updater),
103       omnibox_view_(new OmniboxViewMac(this, profile, command_updater, field)),
104       field_(field),
105       location_icon_decoration_(new LocationIconDecoration(this)),
106       selected_keyword_decoration_(new SelectedKeywordDecoration()),
107       ev_bubble_decoration_(
108           new EVBubbleDecoration(location_icon_decoration_.get())),
109       star_decoration_(new StarDecoration(command_updater)),
110       translate_decoration_(new TranslateDecoration(command_updater)),
111       zoom_decoration_(new ZoomDecoration(this)),
112       keyword_hint_decoration_(new KeywordHintDecoration()),
113       mic_search_decoration_(new MicSearchDecoration(command_updater)),
114       generated_credit_card_decoration_(
115           new GeneratedCreditCardDecoration(this)),
116       search_button_decoration_(new SearchButtonDecoration(this)),
117       manage_passwords_decoration_(
118           new ManagePasswordsDecoration(command_updater, this)),
119       browser_(browser),
120       weak_ptr_factory_(this) {
121   for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
122     DCHECK_EQ(i, content_setting_decorations_.size());
123     ContentSettingsType type = static_cast<ContentSettingsType>(i);
124     content_setting_decorations_.push_back(
125         new ContentSettingDecoration(type, this, profile));
126   }
127
128   edit_bookmarks_enabled_.Init(
129       bookmarks::prefs::kEditBookmarksEnabled, profile->GetPrefs(),
130       base::Bind(&LocationBarViewMac::OnEditBookmarksEnabledChanged,
131                  base::Unretained(this)));
132
133   browser_->search_model()->AddObserver(this);
134
135   [[field_ cell] setIsPopupMode:
136       !browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)];
137
138   if (chrome::ShouldDisplayOriginChip())
139     origin_chip_decoration_.reset(new OriginChipDecoration(
140         this, location_icon_decoration_.get()));
141
142   // Sets images for the decorations, and performs a layout. This call ensures
143   // that this class is in a consistent state after initialization.
144   OnChanged();
145 }
146
147 LocationBarViewMac::~LocationBarViewMac() {
148   // Disconnect from cell in case it outlives us.
149   [[field_ cell] clearDecorations];
150
151   browser_->search_model()->RemoveObserver(this);
152 }
153
154 void LocationBarViewMac::ShowFirstRunBubble() {
155   // We need the browser window to be shown before we can show the bubble, but
156   // we get called before that's happened.
157   base::MessageLoop::current()->PostTask(
158       FROM_HERE, base::Bind(&LocationBarViewMac::ShowFirstRunBubbleInternal,
159                             weak_ptr_factory_.GetWeakPtr()));
160 }
161
162 GURL LocationBarViewMac::GetDestinationURL() const {
163   return destination_url();
164 }
165
166 WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const {
167   return disposition();
168 }
169
170 ui::PageTransition LocationBarViewMac::GetPageTransition() const {
171   return transition();
172 }
173
174 void LocationBarViewMac::AcceptInput() {
175   WindowOpenDisposition disposition =
176       ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
177   omnibox_view_->model()->AcceptInput(disposition, false);
178 }
179
180 void LocationBarViewMac::FocusLocation(bool select_all) {
181   omnibox_view_->FocusLocation(select_all);
182 }
183
184 void LocationBarViewMac::FocusSearch() {
185   omnibox_view_->SetForcedQuery();
186 }
187
188 void LocationBarViewMac::UpdateContentSettingsIcons() {
189   if (RefreshContentSettingsDecorations())
190     OnDecorationsChanged();
191 }
192
193 void LocationBarViewMac::UpdateManagePasswordsIconAndBubble() {
194   WebContents* web_contents = GetWebContents();
195   if (!web_contents)
196     return;
197   ManagePasswordsUIController::FromWebContents(web_contents)
198       ->UpdateIconAndBubbleState(manage_passwords_decoration_->icon());
199   OnDecorationsChanged();
200 }
201
202 void LocationBarViewMac::UpdatePageActions() {
203   RefreshPageActionDecorations();
204   Layout();
205
206   [field_ updateMouseTracking];
207   [field_ setNeedsDisplay:YES];
208 }
209
210 void LocationBarViewMac::InvalidatePageActions() {
211   DeletePageActionDecorations();
212   Layout();
213 }
214
215 void LocationBarViewMac::UpdateBookmarkStarVisibility() {
216   star_decoration_->SetVisible(IsStarEnabled());
217 }
218
219 bool LocationBarViewMac::ShowPageActionPopup(
220     const extensions::Extension* extension, bool grant_active_tab) {
221   for (ScopedVector<PageActionDecoration>::iterator iter =
222            page_action_decorations_.begin();
223        iter != page_action_decorations_.end(); ++iter) {
224     if ((*iter)->GetExtension() == extension)
225       return (*iter)->ActivatePageAction(grant_active_tab);
226   }
227   return false;
228 }
229
230 void LocationBarViewMac::UpdateOpenPDFInReaderPrompt() {
231   // Not implemented on Mac.
232 }
233
234 void LocationBarViewMac::UpdateGeneratedCreditCardView() {
235   generated_credit_card_decoration_->Update();
236 }
237
238 void LocationBarViewMac::SaveStateToContents(WebContents* contents) {
239   // TODO(shess): Why SaveStateToContents vs SaveStateToTab?
240   omnibox_view_->SaveStateToTab(contents);
241 }
242
243 void LocationBarViewMac::Revert() {
244   omnibox_view_->RevertAll();
245 }
246
247 const OmniboxView* LocationBarViewMac::GetOmniboxView() const {
248   return omnibox_view_.get();
249 }
250
251 OmniboxView* LocationBarViewMac::GetOmniboxView() {
252   return omnibox_view_.get();
253 }
254
255 LocationBarTesting* LocationBarViewMac::GetLocationBarForTesting() {
256   return this;
257 }
258
259 // TODO(pamg): Change all these, here and for other platforms, to size_t.
260 int LocationBarViewMac::PageActionCount() {
261   return static_cast<int>(page_action_decorations_.size());
262 }
263
264 int LocationBarViewMac::PageActionVisibleCount() {
265   int result = 0;
266   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
267     if (page_action_decorations_[i]->IsVisible())
268       ++result;
269   }
270   return result;
271 }
272
273 ExtensionAction* LocationBarViewMac::GetPageAction(size_t index) {
274   if (index < page_action_decorations_.size())
275     return page_action_decorations_[index]->GetPageAction();
276   NOTREACHED();
277   return NULL;
278 }
279
280 ExtensionAction* LocationBarViewMac::GetVisiblePageAction(size_t index) {
281   size_t current = 0;
282   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
283     if (page_action_decorations_[i]->IsVisible()) {
284       if (current == index)
285         return page_action_decorations_[i]->GetPageAction();
286
287       ++current;
288     }
289   }
290
291   NOTREACHED();
292   return NULL;
293 }
294
295 void LocationBarViewMac::TestPageActionPressed(size_t index) {
296   DCHECK_LT(index, static_cast<size_t>(PageActionVisibleCount()));
297   size_t current = 0;
298   for (PageActionDecoration* decoration : page_action_decorations_) {
299     if (decoration->IsVisible()) {
300       if (current == index) {
301         decoration->OnMousePressed(NSZeroRect, NSZeroPoint);
302         return;
303       }
304       ++current;
305     }
306   }
307 }
308
309 bool LocationBarViewMac::GetBookmarkStarVisibility() {
310   DCHECK(star_decoration_.get());
311   return star_decoration_->IsVisible();
312 }
313
314 void LocationBarViewMac::SetEditable(bool editable) {
315   [field_ setEditable:editable ? YES : NO];
316   UpdateBookmarkStarVisibility();
317   UpdateZoomDecoration();
318   UpdatePageActions();
319   Layout();
320 }
321
322 bool LocationBarViewMac::IsEditable() {
323   return [field_ isEditable] ? true : false;
324 }
325
326 void LocationBarViewMac::SetStarred(bool starred) {
327   if (star_decoration_->starred() == starred)
328     return;
329
330   star_decoration_->SetStarred(starred);
331   UpdateBookmarkStarVisibility();
332   OnDecorationsChanged();
333 }
334
335 void LocationBarViewMac::SetTranslateIconLit(bool on) {
336   translate_decoration_->SetLit(on);
337   OnDecorationsChanged();
338 }
339
340 void LocationBarViewMac::ZoomChangedForActiveTab(bool can_show_bubble) {
341   bool changed = UpdateZoomDecoration();
342   if (changed)
343     OnDecorationsChanged();
344
345   if (can_show_bubble && zoom_decoration_->IsVisible())
346     zoom_decoration_->ShowBubble(YES);
347 }
348
349 bool LocationBarViewMac::IsStarEnabled() const {
350   return browser_defaults::bookmarks_enabled &&
351          [field_ isEditable] &&
352          !GetToolbarModel()->input_in_progress() &&
353          edit_bookmarks_enabled_.GetValue() &&
354          !IsBookmarkStarHiddenByExtension();
355 }
356
357 NSPoint LocationBarViewMac::GetBookmarkBubblePoint() const {
358   DCHECK(IsStarEnabled());
359   return [field_ bubblePointForDecoration:star_decoration_.get()];
360 }
361
362 NSPoint LocationBarViewMac::GetTranslateBubblePoint() const {
363   return [field_ bubblePointForDecoration:translate_decoration_.get()];
364 }
365
366 NSPoint LocationBarViewMac::GetManagePasswordsBubblePoint() const {
367   return [field_ bubblePointForDecoration:manage_passwords_decoration_.get()];
368 }
369
370 NSPoint LocationBarViewMac::GetPageInfoBubblePoint() const {
371   if (origin_chip_decoration_ && origin_chip_decoration_->IsVisible()) {
372     return [field_ bubblePointForDecoration:origin_chip_decoration_.get()];
373   } else if (ev_bubble_decoration_->IsVisible()) {
374     return [field_ bubblePointForDecoration:ev_bubble_decoration_.get()];
375   } else {
376     return [field_ bubblePointForDecoration:location_icon_decoration_.get()];
377   }
378 }
379
380 NSPoint LocationBarViewMac::GetGeneratedCreditCardBubblePoint() const {
381   return
382       [field_ bubblePointForDecoration:generated_credit_card_decoration_.get()];
383 }
384
385 void LocationBarViewMac::OnDecorationsChanged() {
386   // TODO(shess): The field-editor frame and cursor rects should not
387   // change, here.
388   [field_ updateMouseTracking];
389   [field_ resetFieldEditorFrameIfNeeded];
390   [field_ setNeedsDisplay:YES];
391 }
392
393 // TODO(shess): This function should over time grow to closely match
394 // the views Layout() function.
395 void LocationBarViewMac::Layout() {
396   AutocompleteTextFieldCell* cell = [field_ cell];
397
398   // Reset the left-hand decorations.
399   // TODO(shess): Shortly, this code will live somewhere else, like in
400   // the constructor.  I am still wrestling with how best to deal with
401   // right-hand decorations, which are not a static set.
402   [cell clearDecorations];
403   if (origin_chip_decoration_.get())
404     [cell addLeftDecoration:origin_chip_decoration_.get()];
405   [cell addLeftDecoration:location_icon_decoration_.get()];
406   [cell addLeftDecoration:selected_keyword_decoration_.get()];
407   if (!origin_chip_decoration_.get())
408     [cell addLeftDecoration:ev_bubble_decoration_.get()];
409   [cell addRightDecoration:search_button_decoration_.get()];
410   [cell addRightDecoration:star_decoration_.get()];
411   [cell addRightDecoration:translate_decoration_.get()];
412   [cell addRightDecoration:zoom_decoration_.get()];
413   [cell addRightDecoration:generated_credit_card_decoration_.get()];
414   [cell addRightDecoration:manage_passwords_decoration_.get()];
415
416   // Note that display order is right to left.
417   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
418     [cell addRightDecoration:page_action_decorations_[i]];
419   }
420
421   for (ScopedVector<ContentSettingDecoration>::iterator i =
422        content_setting_decorations_.begin();
423        i != content_setting_decorations_.end(); ++i) {
424     [cell addRightDecoration:*i];
425   }
426
427   [cell addRightDecoration:keyword_hint_decoration_.get()];
428   [cell addRightDecoration:mic_search_decoration_.get()];
429
430   // By default only the location icon is visible.
431   location_icon_decoration_->SetVisible(!origin_chip_decoration_.get() ||
432                                         !origin_chip_decoration_->IsVisible());
433   selected_keyword_decoration_->SetVisible(false);
434   ev_bubble_decoration_->SetVisible(false);
435   keyword_hint_decoration_->SetVisible(false);
436
437   // Get the keyword to use for keyword-search and hinting.
438   const base::string16 keyword = omnibox_view_->model()->keyword();
439   base::string16 short_name;
440   bool is_extension_keyword = false;
441   if (!keyword.empty()) {
442     short_name = TemplateURLServiceFactory::GetForProfile(profile())->
443         GetKeywordShortName(keyword, &is_extension_keyword);
444   }
445
446   const bool is_keyword_hint = omnibox_view_->model()->is_keyword_hint();
447   if (!keyword.empty() && !is_keyword_hint) {
448     // Switch from location icon to keyword mode.
449     location_icon_decoration_->SetVisible(false);
450     selected_keyword_decoration_->SetVisible(true);
451     selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword);
452     selected_keyword_decoration_->SetImage(GetKeywordImage(keyword));
453   } else if ((GetToolbarModel()->GetSecurityLevel(false) ==
454               ToolbarModel::EV_SECURE) && !origin_chip_decoration_.get()) {
455     // Switch from location icon to show the EV bubble instead.
456     location_icon_decoration_->SetVisible(false);
457     ev_bubble_decoration_->SetVisible(true);
458
459     base::string16 label(GetToolbarModel()->GetEVCertName());
460     ev_bubble_decoration_->SetFullLabel(base::SysUTF16ToNSString(label));
461   } else if (!keyword.empty() && is_keyword_hint) {
462     keyword_hint_decoration_->SetKeyword(short_name,
463                                          is_extension_keyword);
464     keyword_hint_decoration_->SetVisible(true);
465   }
466
467   // These need to change anytime the layout changes.
468   // TODO(shess): Anytime the field editor might have changed, the
469   // cursor rects almost certainly should have changed.  The tooltips
470   // might change even when the rects don't change.
471   OnDecorationsChanged();
472 }
473
474 void LocationBarViewMac::RedrawDecoration(LocationBarDecoration* decoration) {
475   AutocompleteTextFieldCell* cell = [field_ cell];
476   NSRect frame = [cell frameForDecoration:decoration
477                                   inFrame:[field_ bounds]];
478   if (!NSIsEmptyRect(frame))
479     [field_ setNeedsDisplayInRect:frame];
480 }
481
482 void LocationBarViewMac::SetPreviewEnabledPageAction(
483     ExtensionAction* page_action, bool preview_enabled) {
484   DCHECK(page_action);
485   WebContents* contents = GetWebContents();
486   if (!contents)
487     return;
488   RefreshPageActionDecorations();
489   Layout();
490
491   PageActionDecoration* decoration = GetPageActionDecoration(page_action);
492   DCHECK(decoration);
493   if (!decoration)
494     return;
495
496   decoration->set_preview_enabled(preview_enabled);
497   decoration->UpdateVisibility(contents);
498 }
499
500 NSRect LocationBarViewMac::GetPageActionFrame(ExtensionAction* page_action) {
501   PageActionDecoration* decoration = GetPageActionDecoration(page_action);
502   if (!decoration)
503     return NSZeroRect;
504
505   AutocompleteTextFieldCell* cell = [field_ cell];
506   NSRect frame = [cell frameForDecoration:decoration inFrame:[field_ bounds]];
507   return frame;
508 }
509
510 NSPoint LocationBarViewMac::GetPageActionBubblePoint(
511     ExtensionAction* page_action) {
512   PageActionDecoration* decoration = GetPageActionDecoration(page_action);
513   if (!decoration)
514     return NSZeroPoint;
515
516   NSRect frame = GetPageActionFrame(page_action);
517   if (NSIsEmptyRect(frame)) {
518     // The bubble point positioning assumes that the page action is visible. If
519     // not, something else needs to be done otherwise the bubble will appear
520     // near the top left corner (unanchored).
521     NOTREACHED();
522     return NSZeroPoint;
523   }
524
525   NSPoint bubble_point = decoration->GetBubblePointInFrame(frame);
526   return [field_ convertPoint:bubble_point toView:nil];
527 }
528
529 void LocationBarViewMac::Update(const WebContents* contents) {
530   UpdateManagePasswordsIconAndBubble();
531   UpdateBookmarkStarVisibility();
532   UpdateTranslateDecoration();
533   UpdateZoomDecoration();
534   RefreshPageActionDecorations();
535   RefreshContentSettingsDecorations();
536   UpdateMicSearchDecorationVisibility();
537   UpdateGeneratedCreditCardView();
538   if (contents)
539     omnibox_view_->OnTabChanged(contents);
540   else
541     omnibox_view_->Update();
542   OnChanged();
543 }
544
545 void LocationBarViewMac::OnChanged() {
546   // Update the location-bar icon.
547   const int resource_id = omnibox_view_->GetIcon();
548   NSImage* image = OmniboxViewMac::ImageForResource(resource_id);
549   location_icon_decoration_->SetImage(image);
550   ev_bubble_decoration_->SetImage(image);
551
552   if (origin_chip_decoration_.get())
553     origin_chip_decoration_->Update();
554
555   ToolbarModel* toolbar_model = GetToolbarModel();
556   const chrome::DisplaySearchButtonConditions conditions =
557       chrome::GetDisplaySearchButtonConditions();
558   const bool meets_conditions =
559       (conditions == chrome::DISPLAY_SEARCH_BUTTON_ALWAYS) ||
560       ((conditions != chrome::DISPLAY_SEARCH_BUTTON_NEVER) &&
561        (toolbar_model->WouldPerformSearchTermReplacement(true) ||
562         ((conditions == chrome::DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP) &&
563          toolbar_model->input_in_progress())));
564   search_button_decoration_->SetVisible(
565       ![[field_ cell] isPopupMode] && meets_conditions);
566   search_button_decoration_->SetIcon(
567       (resource_id == IDR_OMNIBOX_SEARCH) ?
568           IDR_OMNIBOX_SEARCH_BUTTON_LOUPE : IDR_OMNIBOX_SEARCH_BUTTON_ARROW);
569
570   Layout();
571
572   InstantService* instant_service =
573       InstantServiceFactory::GetForProfile(profile());
574   if (instant_service) {
575     gfx::Rect bounds(NSRectToCGRect([field_ frame]));
576     instant_service->OnOmniboxStartMarginChanged(bounds.x());
577   }
578 }
579
580 void LocationBarViewMac::OnSetFocus() {
581   // Update the keyword and search hint states.
582   OnChanged();
583 }
584
585 void LocationBarViewMac::ShowURL() {
586   omnibox_view_->ShowURL();
587 }
588
589 void LocationBarViewMac::HideURL() {
590   omnibox_view_->HideURL();
591 }
592
593 void LocationBarViewMac::EndOriginChipAnimations(bool cancel_fade) {
594 }
595
596 InstantController* LocationBarViewMac::GetInstant() {
597   return browser_->instant_controller() ?
598       browser_->instant_controller()->instant() : NULL;
599 }
600
601 WebContents* LocationBarViewMac::GetWebContents() {
602   return browser_->tab_strip_model()->GetActiveWebContents();
603 }
604
605 ToolbarModel* LocationBarViewMac::GetToolbarModel() {
606   return browser_->toolbar_model();
607 }
608
609 const ToolbarModel* LocationBarViewMac::GetToolbarModel() const {
610   return browser_->toolbar_model();
611 }
612
613 NSImage* LocationBarViewMac::GetKeywordImage(const base::string16& keyword) {
614   const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile(
615       profile())->GetTemplateURLForKeyword(keyword);
616   if (template_url &&
617       (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) {
618     return extensions::OmniboxAPI::Get(profile())->
619         GetOmniboxIcon(template_url->GetExtensionId()).AsNSImage();
620   }
621
622   return OmniboxViewMac::ImageForResource(IDR_OMNIBOX_SEARCH);
623 }
624
625 void LocationBarViewMac::ModelChanged(const SearchModel::State& old_state,
626                                       const SearchModel::State& new_state) {
627   if (UpdateMicSearchDecorationVisibility())
628     Layout();
629 }
630
631 void LocationBarViewMac::PostNotification(NSString* notification) {
632   [[NSNotificationCenter defaultCenter] postNotificationName:notification
633                                         object:[NSValue valueWithPointer:this]];
634 }
635
636 PageActionDecoration* LocationBarViewMac::GetPageActionDecoration(
637     ExtensionAction* page_action) {
638   DCHECK(page_action);
639   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
640     if (page_action_decorations_[i]->GetPageAction() == page_action)
641       return page_action_decorations_[i];
642   }
643   // If |page_action| is the browser action of an extension, no element in
644   // |page_action_decorations_| will match.
645   NOTREACHED();
646   return NULL;
647 }
648
649 void LocationBarViewMac::DeletePageActionDecorations() {
650   // TODO(shess): Deleting these decorations could result in the cell
651   // refering to them before things are laid out again.  Meanwhile, at
652   // least fail safe.
653   [[field_ cell] clearDecorations];
654
655   page_action_decorations_.clear();
656 }
657
658 void LocationBarViewMac::OnEditBookmarksEnabledChanged() {
659   UpdateBookmarkStarVisibility();
660   OnChanged();
661 }
662
663 void LocationBarViewMac::RefreshPageActionDecorations() {
664   if (!IsEditable()) {
665     DeletePageActionDecorations();
666     return;
667   }
668
669   WebContents* web_contents = GetWebContents();
670   if (!web_contents) {
671     DeletePageActionDecorations();  // Necessary?
672     return;
673   }
674
675   std::vector<ExtensionAction*> new_page_actions =
676       extensions::TabHelper::FromWebContents(web_contents)->
677           location_bar_controller()->GetCurrentActions();
678
679   if (new_page_actions != page_actions_) {
680     page_actions_.swap(new_page_actions);
681     DeletePageActionDecorations();
682     for (size_t i = 0; i < page_actions_.size(); ++i) {
683       page_action_decorations_.push_back(
684           new PageActionDecoration(this, browser_, page_actions_[i]));
685     }
686
687     // Move rightmost extensions to the start.
688     std::stable_partition(page_action_decorations_.begin(),
689                           page_action_decorations_.end(),
690                           PageActionHasBookmarkManagerPrivate);
691   }
692
693   GURL url = GetToolbarModel()->GetURL();
694   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
695     page_action_decorations_[i]->UpdateVisibility(
696         GetToolbarModel()->input_in_progress() ? NULL : web_contents);
697   }
698 }
699
700 bool LocationBarViewMac::RefreshContentSettingsDecorations() {
701   const bool input_in_progress = GetToolbarModel()->input_in_progress();
702   WebContents* web_contents = input_in_progress ?
703       NULL : browser_->tab_strip_model()->GetActiveWebContents();
704   bool icons_updated = false;
705   for (size_t i = 0; i < content_setting_decorations_.size(); ++i) {
706     icons_updated |=
707         content_setting_decorations_[i]->UpdateFromWebContents(web_contents);
708   }
709   return icons_updated;
710 }
711
712 void LocationBarViewMac::ShowFirstRunBubbleInternal() {
713   if (!field_ || ![field_ window])
714     return;
715
716   // The first run bubble's left edge should line up with the left edge of the
717   // omnibox. This is different from other bubbles, which line up at a point
718   // set by their top arrow. Because the BaseBubbleController adjusts the
719   // window origin left to account for the arrow spacing, the first run bubble
720   // moves the window origin right by this spacing, so that the
721   // BaseBubbleController will move it back to the correct position.
722   const NSPoint kOffset = NSMakePoint(
723       info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth/2.0,
724       kFirstRunBubbleYOffset);
725   [FirstRunBubbleController showForView:field_
726                                  offset:kOffset
727                                 browser:browser_
728                                 profile:profile()];
729 }
730
731 void LocationBarViewMac::UpdateTranslateDecoration() {
732   if (!TranslateService::IsTranslateBubbleEnabled())
733     return;
734
735   WebContents* web_contents = GetWebContents();
736   if (!web_contents)
737     return;
738   translate::LanguageState& language_state =
739       ChromeTranslateClient::FromWebContents(web_contents)->GetLanguageState();
740   bool enabled = language_state.translate_enabled();
741   command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE, enabled);
742   translate_decoration_->SetVisible(enabled);
743   translate_decoration_->SetLit(language_state.IsPageTranslated());
744 }
745
746 bool LocationBarViewMac::UpdateZoomDecoration() {
747   WebContents* web_contents = GetWebContents();
748   if (!web_contents)
749     return false;
750
751   return zoom_decoration_->UpdateIfNecessary(
752       ZoomController::FromWebContents(web_contents));
753 }
754
755 bool LocationBarViewMac::UpdateMicSearchDecorationVisibility() {
756   bool is_visible = !GetToolbarModel()->input_in_progress() &&
757                     browser_->search_model()->voice_search_supported();
758   if (mic_search_decoration_->IsVisible() == is_visible)
759     return false;
760   mic_search_decoration_->SetVisible(is_visible);
761   return true;
762 }