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