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