Home | History | Annotate | Download | only in location_bar
      1 // Copyright (c) 2011 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/stl_util-inl.h"
      8 #include "base/string_util.h"
      9 #include "base/sys_string_conversions.h"
     10 #include "base/utf_string_conversions.h"
     11 #include "chrome/app/chrome_command_ids.h"
     12 #include "chrome/browser/alternate_nav_url_fetcher.h"
     13 #import "chrome/browser/app_controller_mac.h"
     14 #import "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
     15 #import "chrome/browser/autocomplete/autocomplete_popup_model.h"
     16 #include "chrome/browser/command_updater.h"
     17 #include "chrome/browser/content_setting_bubble_model.h"
     18 #include "chrome/browser/content_setting_image_model.h"
     19 #include "chrome/browser/defaults.h"
     20 #include "chrome/browser/extensions/extension_browser_event_router.h"
     21 #include "chrome/browser/extensions/extension_service.h"
     22 #include "chrome/browser/extensions/extension_tabs_module.h"
     23 #include "chrome/browser/instant/instant_controller.h"
     24 #include "chrome/browser/profiles/profile.h"
     25 #include "chrome/browser/search_engines/template_url.h"
     26 #include "chrome/browser/search_engines/template_url_model.h"
     27 #include "chrome/browser/ui/browser_list.h"
     28 #import "chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.h"
     29 #include "chrome/browser/ui/cocoa/event_utils.h"
     30 #import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h"
     31 #import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
     32 #import "chrome/browser/ui/cocoa/first_run_bubble_controller.h"
     33 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
     34 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
     35 #import "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h"
     36 #import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h"
     37 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
     38 #import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
     39 #import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h"
     40 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
     41 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
     42 #include "chrome/browser/ui/omnibox/location_bar_util.h"
     43 #include "chrome/common/extensions/extension.h"
     44 #include "chrome/common/extensions/extension_action.h"
     45 #include "chrome/common/extensions/extension_resource.h"
     46 #include "chrome/common/pref_names.h"
     47 #include "content/browser/tab_contents/navigation_entry.h"
     48 #include "content/browser/tab_contents/tab_contents.h"
     49 #include "content/common/notification_service.h"
     50 #include "grit/generated_resources.h"
     51 #include "grit/theme_resources.h"
     52 #include "net/base/net_util.h"
     53 #include "skia/ext/skia_utils_mac.h"
     54 #include "third_party/skia/include/core/SkBitmap.h"
     55 #include "ui/base/l10n/l10n_util_mac.h"
     56 #include "ui/base/resource/resource_bundle.h"
     57 
     58 namespace {
     59 
     60 // Vertical space between the bottom edge of the location_bar and the first run
     61 // bubble arrow point.
     62 const static int kFirstRunBubbleYOffset = 1;
     63 
     64 }
     65 
     66 // TODO(shess): This code is mostly copied from the gtk
     67 // implementation.  Make sure it's all appropriate and flesh it out.
     68 
     69 LocationBarViewMac::LocationBarViewMac(
     70     AutocompleteTextField* field,
     71     CommandUpdater* command_updater,
     72     ToolbarModel* toolbar_model,
     73     Profile* profile,
     74     Browser* browser)
     75     : edit_view_(new AutocompleteEditViewMac(this, toolbar_model, profile,
     76                                              command_updater, field)),
     77       command_updater_(command_updater),
     78       field_(field),
     79       disposition_(CURRENT_TAB),
     80       location_icon_decoration_(new LocationIconDecoration(this)),
     81       selected_keyword_decoration_(
     82           new SelectedKeywordDecoration(
     83               AutocompleteEditViewMac::GetFieldFont())),
     84       ev_bubble_decoration_(
     85           new EVBubbleDecoration(location_icon_decoration_.get(),
     86                                  AutocompleteEditViewMac::GetFieldFont())),
     87       star_decoration_(new StarDecoration(command_updater)),
     88       keyword_hint_decoration_(
     89           new KeywordHintDecoration(AutocompleteEditViewMac::GetFieldFont())),
     90       profile_(profile),
     91       browser_(browser),
     92       toolbar_model_(toolbar_model),
     93       transition_(PageTransition::TYPED),
     94       first_run_bubble_(this) {
     95   for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
     96     DCHECK_EQ(i, content_setting_decorations_.size());
     97     ContentSettingsType type = static_cast<ContentSettingsType>(i);
     98     content_setting_decorations_.push_back(
     99         new ContentSettingDecoration(type, this, profile_));
    100   }
    101 
    102   registrar_.Add(this,
    103       NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
    104       NotificationService::AllSources());
    105 
    106   edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled,
    107                                profile_->GetPrefs(), this);
    108 }
    109 
    110 LocationBarViewMac::~LocationBarViewMac() {
    111   // Disconnect from cell in case it outlives us.
    112   [[field_ cell] clearDecorations];
    113 }
    114 
    115 void LocationBarViewMac::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
    116   // We need the browser window to be shown before we can show the bubble, but
    117   // we get called before that's happened.
    118   Task* task = first_run_bubble_.NewRunnableMethod(
    119       &LocationBarViewMac::ShowFirstRunBubbleInternal, bubble_type);
    120   MessageLoop::current()->PostTask(FROM_HERE, task);
    121 }
    122 
    123 void LocationBarViewMac::ShowFirstRunBubbleInternal(
    124     FirstRun::BubbleType bubble_type) {
    125   if (!field_ || ![field_ window])
    126     return;
    127 
    128   // The first run bubble's left edge should line up with the left edge of the
    129   // omnibox. This is different from other bubbles, which line up at a point
    130   // set by their top arrow. Because the BaseBubbleController adjusts the
    131   // window origin left to account for the arrow spacing, the first run bubble
    132   // moves the window origin right by this spacing, so that the
    133   // BaseBubbleController will move it back to the correct position.
    134   const NSPoint kOffset = NSMakePoint(
    135       info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth/2.0,
    136       kFirstRunBubbleYOffset);
    137   [FirstRunBubbleController showForView:field_ offset:kOffset profile:profile_];
    138 }
    139 
    140 std::wstring LocationBarViewMac::GetInputString() const {
    141   return location_input_;
    142 }
    143 
    144 void LocationBarViewMac::SetSuggestedText(const string16& text,
    145                                           InstantCompleteBehavior behavior) {
    146   edit_view_->model()->SetSuggestedText(text, behavior);
    147 }
    148 
    149 WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const {
    150   return disposition_;
    151 }
    152 
    153 PageTransition::Type LocationBarViewMac::GetPageTransition() const {
    154   return transition_;
    155 }
    156 
    157 void LocationBarViewMac::AcceptInput() {
    158   WindowOpenDisposition disposition =
    159       event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
    160   edit_view_->model()->AcceptInput(disposition, false);
    161 }
    162 
    163 void LocationBarViewMac::FocusLocation(bool select_all) {
    164   edit_view_->FocusLocation(select_all);
    165 }
    166 
    167 void LocationBarViewMac::FocusSearch() {
    168   edit_view_->SetForcedQuery();
    169 }
    170 
    171 void LocationBarViewMac::UpdateContentSettingsIcons() {
    172   if (RefreshContentSettingsDecorations()) {
    173     [field_ updateCursorAndToolTipRects];
    174     [field_ setNeedsDisplay:YES];
    175   }
    176 }
    177 
    178 void LocationBarViewMac::UpdatePageActions() {
    179   size_t count_before = page_action_decorations_.size();
    180   RefreshPageActionDecorations();
    181   Layout();
    182   if (page_action_decorations_.size() != count_before) {
    183     NotificationService::current()->Notify(
    184         NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
    185         Source<LocationBar>(this),
    186         NotificationService::NoDetails());
    187   }
    188 }
    189 
    190 void LocationBarViewMac::InvalidatePageActions() {
    191   size_t count_before = page_action_decorations_.size();
    192   DeletePageActionDecorations();
    193   Layout();
    194   if (page_action_decorations_.size() != count_before) {
    195     NotificationService::current()->Notify(
    196         NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
    197         Source<LocationBar>(this),
    198         NotificationService::NoDetails());
    199   }
    200 }
    201 
    202 void LocationBarViewMac::SaveStateToContents(TabContents* contents) {
    203   // TODO(shess): Why SaveStateToContents vs SaveStateToTab?
    204   edit_view_->SaveStateToTab(contents);
    205 }
    206 
    207 void LocationBarViewMac::Update(const TabContents* contents,
    208                                 bool should_restore_state) {
    209   bool star_enabled = IsStarEnabled();
    210   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
    211   star_decoration_->SetVisible(star_enabled);
    212   RefreshPageActionDecorations();
    213   RefreshContentSettingsDecorations();
    214   // AutocompleteEditView restores state if the tab is non-NULL.
    215   edit_view_->Update(should_restore_state ? contents : NULL);
    216   OnChanged();
    217 }
    218 
    219 void LocationBarViewMac::OnAutocompleteAccept(const GURL& url,
    220                                               WindowOpenDisposition disposition,
    221                                               PageTransition::Type transition,
    222                                               const GURL& alternate_nav_url) {
    223   // WARNING: don't add an early return here. The calls after the if must
    224   // happen.
    225   if (url.is_valid()) {
    226     location_input_ = UTF8ToWide(url.spec());
    227     disposition_ = disposition;
    228     transition_ = transition;
    229 
    230     if (command_updater_) {
    231       if (!alternate_nav_url.is_valid()) {
    232         command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    233       } else {
    234         AlternateNavURLFetcher* fetcher =
    235             new AlternateNavURLFetcher(alternate_nav_url);
    236         // The AlternateNavURLFetcher will listen for the pending navigation
    237         // notification that will be issued as a result of the "open URL." It
    238         // will automatically install itself into that navigation controller.
    239         command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    240         if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
    241           // I'm not sure this should be reachable, but I'm not also sure enough
    242           // that it shouldn't to stick in a NOTREACHED().  In any case, this is
    243           // harmless.
    244           delete fetcher;
    245         } else {
    246           // The navigation controller will delete the fetcher.
    247         }
    248       }
    249     }
    250   }
    251 }
    252 
    253 void LocationBarViewMac::OnChanged() {
    254   // Update the location-bar icon.
    255   const int resource_id = edit_view_->GetIcon();
    256   NSImage* image = AutocompleteEditViewMac::ImageForResource(resource_id);
    257   location_icon_decoration_->SetImage(image);
    258   ev_bubble_decoration_->SetImage(image);
    259   Layout();
    260 }
    261 
    262 void LocationBarViewMac::OnSelectionBoundsChanged() {
    263   NOTIMPLEMENTED();
    264 }
    265 
    266 void LocationBarViewMac::OnInputInProgress(bool in_progress) {
    267   toolbar_model_->set_input_in_progress(in_progress);
    268   Update(NULL, false);
    269 }
    270 
    271 void LocationBarViewMac::OnSetFocus() {
    272   // Update the keyword and search hint states.
    273   OnChanged();
    274 }
    275 
    276 void LocationBarViewMac::OnKillFocus() {
    277   // Do nothing.
    278 }
    279 
    280 SkBitmap LocationBarViewMac::GetFavicon() const {
    281   NOTIMPLEMENTED();
    282   return SkBitmap();
    283 }
    284 
    285 string16 LocationBarViewMac::GetTitle() const {
    286   NOTIMPLEMENTED();
    287   return string16();
    288 }
    289 
    290 InstantController* LocationBarViewMac::GetInstant() {
    291   return browser_->instant();
    292 }
    293 
    294 TabContentsWrapper* LocationBarViewMac::GetTabContentsWrapper() const {
    295   return browser_->GetSelectedTabContentsWrapper();
    296 }
    297 
    298 void LocationBarViewMac::Revert() {
    299   edit_view_->RevertAll();
    300 }
    301 
    302 const AutocompleteEditView* LocationBarViewMac::location_entry() const {
    303     return edit_view_.get();
    304   }
    305 
    306 AutocompleteEditView* LocationBarViewMac::location_entry() {
    307     return edit_view_.get();
    308   }
    309 
    310 LocationBarTesting* LocationBarViewMac::GetLocationBarForTesting() {
    311   return this;
    312 }
    313 
    314 // TODO(pamg): Change all these, here and for other platforms, to size_t.
    315 int LocationBarViewMac::PageActionCount() {
    316   return static_cast<int>(page_action_decorations_.size());
    317 }
    318 
    319 int LocationBarViewMac::PageActionVisibleCount() {
    320   int result = 0;
    321   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
    322     if (page_action_decorations_[i]->IsVisible())
    323       ++result;
    324   }
    325   return result;
    326 }
    327 
    328 TabContents* LocationBarViewMac::GetTabContents() const {
    329   return browser_->GetSelectedTabContents();
    330 }
    331 
    332 PageActionDecoration* LocationBarViewMac::GetPageActionDecoration(
    333     ExtensionAction* page_action) {
    334   DCHECK(page_action);
    335   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
    336     if (page_action_decorations_[i]->page_action() == page_action)
    337       return page_action_decorations_[i];
    338   }
    339   // If |page_action| is the browser action of an extension, no element in
    340   // |page_action_decorations_| will match.
    341   NOTREACHED();
    342   return NULL;
    343 }
    344 
    345 void LocationBarViewMac::SetPreviewEnabledPageAction(
    346     ExtensionAction* page_action, bool preview_enabled) {
    347   DCHECK(page_action);
    348   TabContents* contents = GetTabContents();
    349   if (!contents)
    350     return;
    351   RefreshPageActionDecorations();
    352   Layout();
    353 
    354   PageActionDecoration* decoration = GetPageActionDecoration(page_action);
    355   DCHECK(decoration);
    356   if (!decoration)
    357     return;
    358 
    359   decoration->set_preview_enabled(preview_enabled);
    360   decoration->UpdateVisibility(contents,
    361       GURL(WideToUTF8(toolbar_model_->GetText())));
    362 }
    363 
    364 NSPoint LocationBarViewMac::GetPageActionBubblePoint(
    365     ExtensionAction* page_action) {
    366   PageActionDecoration* decoration = GetPageActionDecoration(page_action);
    367   if (!decoration)
    368     return NSZeroPoint;
    369 
    370   AutocompleteTextFieldCell* cell = [field_ cell];
    371   NSRect frame = [cell frameForDecoration:decoration inFrame:[field_ bounds]];
    372   DCHECK(!NSIsEmptyRect(frame));
    373   if (NSIsEmptyRect(frame))
    374     return NSZeroPoint;
    375 
    376   NSPoint bubble_point = decoration->GetBubblePointInFrame(frame);
    377   return [field_ convertPoint:bubble_point toView:nil];
    378 }
    379 
    380 NSRect LocationBarViewMac::GetBlockedPopupRect() const {
    381   const size_t kPopupIndex = CONTENT_SETTINGS_TYPE_POPUPS;
    382   const LocationBarDecoration* decoration =
    383       content_setting_decorations_[kPopupIndex];
    384   if (!decoration || !decoration->IsVisible())
    385     return NSZeroRect;
    386 
    387   AutocompleteTextFieldCell* cell = [field_ cell];
    388   const NSRect frame = [cell frameForDecoration:decoration
    389                                         inFrame:[field_ bounds]];
    390   return [field_ convertRect:frame toView:nil];
    391 }
    392 
    393 ExtensionAction* LocationBarViewMac::GetPageAction(size_t index) {
    394   if (index < page_action_decorations_.size())
    395     return page_action_decorations_[index]->page_action();
    396   NOTREACHED();
    397   return NULL;
    398 }
    399 
    400 ExtensionAction* LocationBarViewMac::GetVisiblePageAction(size_t index) {
    401   size_t current = 0;
    402   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
    403     if (page_action_decorations_[i]->IsVisible()) {
    404       if (current == index)
    405         return page_action_decorations_[i]->page_action();
    406 
    407       ++current;
    408     }
    409   }
    410 
    411   NOTREACHED();
    412   return NULL;
    413 }
    414 
    415 void LocationBarViewMac::TestPageActionPressed(size_t index) {
    416   DCHECK_LT(index, page_action_decorations_.size());
    417   if (index < page_action_decorations_.size())
    418     page_action_decorations_[index]->OnMousePressed(NSZeroRect);
    419 }
    420 
    421 void LocationBarViewMac::SetEditable(bool editable) {
    422   [field_ setEditable:editable ? YES : NO];
    423   star_decoration_->SetVisible(IsStarEnabled());
    424   UpdatePageActions();
    425   Layout();
    426 }
    427 
    428 bool LocationBarViewMac::IsEditable() {
    429   return [field_ isEditable] ? true : false;
    430 }
    431 
    432 void LocationBarViewMac::SetStarred(bool starred) {
    433   star_decoration_->SetStarred(starred);
    434 
    435   // TODO(shess): The field-editor frame and cursor rects should not
    436   // change, here.
    437   [field_ updateCursorAndToolTipRects];
    438   [field_ resetFieldEditorFrameIfNeeded];
    439   [field_ setNeedsDisplay:YES];
    440 }
    441 
    442 NSPoint LocationBarViewMac::GetBookmarkBubblePoint() const {
    443   AutocompleteTextFieldCell* cell = [field_ cell];
    444   const NSRect frame = [cell frameForDecoration:star_decoration_.get()
    445                                         inFrame:[field_ bounds]];
    446   const NSPoint point = star_decoration_->GetBubblePointInFrame(frame);
    447   return [field_ convertPoint:point toView:nil];
    448 }
    449 
    450 NSPoint LocationBarViewMac::GetPageInfoBubblePoint() const {
    451   AutocompleteTextFieldCell* cell = [field_ cell];
    452   if (ev_bubble_decoration_->IsVisible()) {
    453     const NSRect frame = [cell frameForDecoration:ev_bubble_decoration_.get()
    454                                           inFrame:[field_ bounds]];
    455     const NSPoint point = ev_bubble_decoration_->GetBubblePointInFrame(frame);
    456     return [field_ convertPoint:point toView:nil];
    457   } else {
    458     const NSRect frame =
    459         [cell frameForDecoration:location_icon_decoration_.get()
    460                          inFrame:[field_ bounds]];
    461     const NSPoint point =
    462         location_icon_decoration_->GetBubblePointInFrame(frame);
    463     return [field_ convertPoint:point toView:nil];
    464   }
    465 }
    466 
    467 NSImage* LocationBarViewMac::GetKeywordImage(const string16& keyword) {
    468   const TemplateURL* template_url =
    469       profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
    470   if (template_url && template_url->IsExtensionKeyword()) {
    471     const SkBitmap& bitmap = profile_->GetExtensionService()->
    472         GetOmniboxIcon(template_url->GetExtensionId());
    473     return gfx::SkBitmapToNSImage(bitmap);
    474   }
    475 
    476   return AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH);
    477 }
    478 
    479 void LocationBarViewMac::Observe(NotificationType type,
    480                                  const NotificationSource& source,
    481                                  const NotificationDetails& details) {
    482   switch (type.value) {
    483     case NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED: {
    484       TabContents* contents = GetTabContents();
    485       if (Details<TabContents>(contents) != details)
    486         return;
    487 
    488       [field_ updateCursorAndToolTipRects];
    489       [field_ setNeedsDisplay:YES];
    490       break;
    491     }
    492 
    493     case NotificationType::PREF_CHANGED:
    494       star_decoration_->SetVisible(IsStarEnabled());
    495       OnChanged();
    496       break;
    497 
    498     default:
    499       NOTREACHED() << "Unexpected notification";
    500       break;
    501   }
    502 }
    503 
    504 void LocationBarViewMac::PostNotification(NSString* notification) {
    505   [[NSNotificationCenter defaultCenter] postNotificationName:notification
    506                                         object:[NSValue valueWithPointer:this]];
    507 }
    508 
    509 bool LocationBarViewMac::RefreshContentSettingsDecorations() {
    510   const bool input_in_progress = toolbar_model_->input_in_progress();
    511   TabContents* tab_contents =
    512       input_in_progress ? NULL : browser_->GetSelectedTabContents();
    513   bool icons_updated = false;
    514   for (size_t i = 0; i < content_setting_decorations_.size(); ++i) {
    515     icons_updated |=
    516         content_setting_decorations_[i]->UpdateFromTabContents(tab_contents);
    517   }
    518   return icons_updated;
    519 }
    520 
    521 void LocationBarViewMac::DeletePageActionDecorations() {
    522   // TODO(shess): Deleting these decorations could result in the cell
    523   // refering to them before things are laid out again.  Meanwhile, at
    524   // least fail safe.
    525   [[field_ cell] clearDecorations];
    526 
    527   page_action_decorations_.reset();
    528 }
    529 
    530 void LocationBarViewMac::RefreshPageActionDecorations() {
    531   if (!IsEditable()) {
    532     DeletePageActionDecorations();
    533     return;
    534   }
    535 
    536   ExtensionService* service = profile_->GetExtensionService();
    537   if (!service)
    538     return;
    539 
    540   std::vector<ExtensionAction*> page_actions;
    541   for (size_t i = 0; i < service->extensions()->size(); ++i) {
    542     if (service->extensions()->at(i)->page_action())
    543       page_actions.push_back(service->extensions()->at(i)->page_action());
    544   }
    545 
    546   // On startup we sometimes haven't loaded any extensions. This makes sure
    547   // we catch up when the extensions (and any Page Actions) load.
    548   if (page_actions.size() != page_action_decorations_.size()) {
    549     DeletePageActionDecorations();  // Delete the old views (if any).
    550 
    551     for (size_t i = 0; i < page_actions.size(); ++i) {
    552       page_action_decorations_.push_back(
    553           new PageActionDecoration(this, profile_, page_actions[i]));
    554     }
    555   }
    556 
    557   if (page_action_decorations_.empty())
    558     return;
    559 
    560   TabContents* contents = GetTabContents();
    561   if (!contents)
    562     return;
    563 
    564   GURL url = GURL(WideToUTF8(toolbar_model_->GetText()));
    565   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
    566     page_action_decorations_[i]->UpdateVisibility(
    567         toolbar_model_->input_in_progress() ? NULL : contents, url);
    568   }
    569 }
    570 
    571 // TODO(shess): This function should over time grow to closely match
    572 // the views Layout() function.
    573 void LocationBarViewMac::Layout() {
    574   AutocompleteTextFieldCell* cell = [field_ cell];
    575 
    576   // Reset the left-hand decorations.
    577   // TODO(shess): Shortly, this code will live somewhere else, like in
    578   // the constructor.  I am still wrestling with how best to deal with
    579   // right-hand decorations, which are not a static set.
    580   [cell clearDecorations];
    581   [cell addLeftDecoration:location_icon_decoration_.get()];
    582   [cell addLeftDecoration:selected_keyword_decoration_.get()];
    583   [cell addLeftDecoration:ev_bubble_decoration_.get()];
    584   [cell addRightDecoration:star_decoration_.get()];
    585 
    586   // Note that display order is right to left.
    587   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
    588     [cell addRightDecoration:page_action_decorations_[i]];
    589   }
    590   for (size_t i = 0; i < content_setting_decorations_.size(); ++i) {
    591     [cell addRightDecoration:content_setting_decorations_[i]];
    592   }
    593 
    594   [cell addRightDecoration:keyword_hint_decoration_.get()];
    595 
    596   // By default only the location icon is visible.
    597   location_icon_decoration_->SetVisible(true);
    598   selected_keyword_decoration_->SetVisible(false);
    599   ev_bubble_decoration_->SetVisible(false);
    600   keyword_hint_decoration_->SetVisible(false);
    601 
    602   // Get the keyword to use for keyword-search and hinting.
    603   const string16 keyword = edit_view_->model()->keyword();
    604   string16 short_name;
    605   bool is_extension_keyword = false;
    606   if (!keyword.empty()) {
    607     short_name = profile_->GetTemplateURLModel()->
    608         GetKeywordShortName(keyword, &is_extension_keyword);
    609   }
    610 
    611   const bool is_keyword_hint = edit_view_->model()->is_keyword_hint();
    612 
    613   if (!keyword.empty() && !is_keyword_hint) {
    614     // Switch from location icon to keyword mode.
    615     location_icon_decoration_->SetVisible(false);
    616     selected_keyword_decoration_->SetVisible(true);
    617     selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword);
    618     selected_keyword_decoration_->SetImage(GetKeywordImage(keyword));
    619   } else if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
    620     // Switch from location icon to show the EV bubble instead.
    621     location_icon_decoration_->SetVisible(false);
    622     ev_bubble_decoration_->SetVisible(true);
    623 
    624     std::wstring label(toolbar_model_->GetEVCertName());
    625     ev_bubble_decoration_->SetFullLabel(base::SysWideToNSString(label));
    626   } else if (!keyword.empty() && is_keyword_hint) {
    627     keyword_hint_decoration_->SetKeyword(short_name,
    628                                          is_extension_keyword);
    629     keyword_hint_decoration_->SetVisible(true);
    630   }
    631 
    632   // These need to change anytime the layout changes.
    633   // TODO(shess): Anytime the field editor might have changed, the
    634   // cursor rects almost certainly should have changed.  The tooltips
    635   // might change even when the rects don't change.
    636   [field_ resetFieldEditorFrameIfNeeded];
    637   [field_ updateCursorAndToolTipRects];
    638 
    639   [field_ setNeedsDisplay:YES];
    640 }
    641 
    642 bool LocationBarViewMac::IsStarEnabled() {
    643   return [field_ isEditable] &&
    644          browser_defaults::bookmarks_enabled &&
    645          !toolbar_model_->input_in_progress() &&
    646          edit_bookmarks_enabled_.GetValue();
    647 }
    648