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 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
      6 
      7 #if defined(OS_LINUX)
      8 #include <gtk/gtk.h>
      9 #endif
     10 
     11 #include "base/command_line.h"
     12 #include "base/stl_util-inl.h"
     13 #include "base/utf_string_conversions.h"
     14 #include "chrome/app/chrome_command_ids.h"
     15 #include "chrome/browser/alternate_nav_url_fetcher.h"
     16 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
     17 #include "chrome/browser/defaults.h"
     18 #include "chrome/browser/extensions/extension_browser_event_router.h"
     19 #include "chrome/browser/extensions/extension_service.h"
     20 #include "chrome/browser/instant/instant_controller.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/search_engines/template_url.h"
     23 #include "chrome/browser/search_engines/template_url_model.h"
     24 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     25 #include "chrome/browser/ui/view_ids.h"
     26 #include "chrome/browser/ui/views/browser_dialogs.h"
     27 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
     28 #include "chrome/browser/ui/views/location_bar/ev_bubble_view.h"
     29 #include "chrome/browser/ui/views/location_bar/keyword_hint_view.h"
     30 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
     31 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
     32 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
     33 #include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
     34 #include "chrome/browser/ui/views/location_bar/star_view.h"
     35 #include "chrome/common/chrome_switches.h"
     36 #include "chrome/common/pref_names.h"
     37 #include "content/browser/renderer_host/render_widget_host_view.h"
     38 #include "content/common/notification_service.h"
     39 #include "grit/generated_resources.h"
     40 #include "grit/theme_resources.h"
     41 #include "ui/base/accessibility/accessible_view_state.h"
     42 #include "ui/base/dragdrop/drag_drop_types.h"
     43 #include "ui/base/l10n/l10n_util.h"
     44 #include "ui/base/resource/resource_bundle.h"
     45 #include "ui/base/theme_provider.h"
     46 #include "ui/gfx/canvas_skia.h"
     47 #include "ui/gfx/color_utils.h"
     48 #include "ui/gfx/skia_util.h"
     49 #include "views/controls/label.h"
     50 #include "views/drag_utils.h"
     51 
     52 #if defined(OS_WIN)
     53 #include "chrome/browser/ui/views/first_run_bubble.h"
     54 #include "chrome/browser/ui/views/location_bar/suggested_text_view.h"
     55 #endif
     56 
     57 using views::View;
     58 
     59 namespace {
     60 
     61 TabContents* GetTabContentsFromDelegate(LocationBarView::Delegate* delegate) {
     62   const TabContentsWrapper* wrapper = delegate->GetTabContentsWrapper();
     63   return wrapper ? wrapper->tab_contents() : NULL;
     64 }
     65 
     66 }  // namespace
     67 
     68 // static
     69 const int LocationBarView::kNormalHorizontalEdgeThickness = 1;
     70 const int LocationBarView::kVerticalEdgeThickness = 2;
     71 const int LocationBarView::kItemPadding = 3;
     72 const int LocationBarView::kIconInternalPadding = 2;
     73 const int LocationBarView::kEdgeItemPadding = kItemPadding;
     74 const int LocationBarView::kBubbleHorizontalPadding = 1;
     75 const char LocationBarView::kViewClassName[] =
     76     "browser/ui/views/location_bar/LocationBarView";
     77 
     78 static const int kEVBubbleBackgroundImages[] = {
     79   IDR_OMNIBOX_EV_BUBBLE_BACKGROUND_L,
     80   IDR_OMNIBOX_EV_BUBBLE_BACKGROUND_C,
     81   IDR_OMNIBOX_EV_BUBBLE_BACKGROUND_R,
     82 };
     83 
     84 static const int kSelectedKeywordBackgroundImages[] = {
     85   IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_L,
     86   IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_C,
     87   IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_R,
     88 };
     89 
     90 static const int kNormalModeBackgroundImages[] = {
     91   IDR_LOCATIONBG_L,
     92   IDR_LOCATIONBG_C,
     93   IDR_LOCATIONBG_R,
     94 };
     95 
     96 // LocationBarView -----------------------------------------------------------
     97 
     98 LocationBarView::LocationBarView(Profile* profile,
     99                                  CommandUpdater* command_updater,
    100                                  ToolbarModel* model,
    101                                  Delegate* delegate,
    102                                  Mode mode)
    103     : profile_(profile),
    104       command_updater_(command_updater),
    105       model_(model),
    106       delegate_(delegate),
    107       disposition_(CURRENT_TAB),
    108       transition_(PageTransition::LINK),
    109       location_icon_view_(NULL),
    110       ev_bubble_view_(NULL),
    111       location_entry_view_(NULL),
    112       selected_keyword_view_(NULL),
    113 #if defined(OS_WIN)
    114       suggested_text_view_(NULL),
    115 #endif
    116       keyword_hint_view_(NULL),
    117       star_view_(NULL),
    118       mode_(mode),
    119       show_focus_rect_(false),
    120       bubble_type_(FirstRun::MINIMAL_BUBBLE),
    121       template_url_model_(NULL) {
    122   DCHECK(profile_);
    123   SetID(VIEW_ID_LOCATION_BAR);
    124   SetFocusable(true);
    125 
    126   if (mode_ == NORMAL)
    127     painter_.reset(new views::HorizontalPainter(kNormalModeBackgroundImages));
    128 
    129   edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled,
    130                                profile_->GetPrefs(), this);
    131 }
    132 
    133 LocationBarView::~LocationBarView() {
    134   if (template_url_model_)
    135     template_url_model_->RemoveObserver(this);
    136 }
    137 
    138 void LocationBarView::Init() {
    139   if (mode_ == POPUP) {
    140     font_ = ResourceBundle::GetSharedInstance().GetFont(
    141         ResourceBundle::BaseFont);
    142   } else {
    143     // Use a larger version of the system font.
    144     font_ = ResourceBundle::GetSharedInstance().GetFont(
    145         ResourceBundle::MediumFont);
    146   }
    147 
    148   // If this makes the font too big, try to make it smaller so it will fit.
    149   const int height =
    150       std::max(GetPreferredSize().height() - (kVerticalEdgeThickness * 2), 0);
    151   while ((font_.GetHeight() > height) && (font_.GetFontSize() > 1))
    152     font_ = font_.DeriveFont(-1);
    153 
    154   location_icon_view_ = new LocationIconView(this);
    155   AddChildView(location_icon_view_);
    156   location_icon_view_->SetVisible(true);
    157   location_icon_view_->SetDragController(this);
    158 
    159   ev_bubble_view_ =
    160       new EVBubbleView(kEVBubbleBackgroundImages, IDR_OMNIBOX_HTTPS_VALID,
    161                        GetColor(ToolbarModel::EV_SECURE, SECURITY_TEXT), this);
    162   AddChildView(ev_bubble_view_);
    163   ev_bubble_view_->SetVisible(false);
    164   ev_bubble_view_->SetDragController(this);
    165 
    166   // URL edit field.
    167   // View container for URL edit field.
    168 #if defined(OS_WIN)
    169   location_entry_.reset(new AutocompleteEditViewWin(font_, this, model_, this,
    170       GetWidget()->GetNativeView(), profile_, command_updater_,
    171       mode_ == POPUP, this));
    172 #else
    173   location_entry_.reset(
    174       AutocompleteEditViewGtk::Create(
    175           this, model_, profile_,
    176           command_updater_, mode_ == POPUP, this));
    177 #endif
    178 
    179   location_entry_view_ = location_entry_->AddToView(this);
    180   location_entry_view_->SetID(VIEW_ID_AUTOCOMPLETE);
    181 
    182   selected_keyword_view_ = new SelectedKeywordView(
    183       kSelectedKeywordBackgroundImages, IDR_KEYWORD_SEARCH_MAGNIFIER,
    184       GetColor(ToolbarModel::NONE, TEXT), profile_),
    185   AddChildView(selected_keyword_view_);
    186   selected_keyword_view_->SetFont(font_);
    187   selected_keyword_view_->SetVisible(false);
    188 
    189   SkColor dimmed_text = GetColor(ToolbarModel::NONE, DEEMPHASIZED_TEXT);
    190 
    191   keyword_hint_view_ = new KeywordHintView(profile_);
    192   AddChildView(keyword_hint_view_);
    193   keyword_hint_view_->SetVisible(false);
    194   keyword_hint_view_->SetFont(font_);
    195   keyword_hint_view_->SetColor(dimmed_text);
    196 
    197   for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
    198     ContentSettingImageView* content_blocked_view = new ContentSettingImageView(
    199         static_cast<ContentSettingsType>(i), this, profile_);
    200     content_setting_views_.push_back(content_blocked_view);
    201     AddChildView(content_blocked_view);
    202     content_blocked_view->SetVisible(false);
    203   }
    204 
    205   // The star is not visible in popups and in the app launcher.
    206   if (browser_defaults::bookmarks_enabled && (mode_ == NORMAL)) {
    207     star_view_ = new StarView(command_updater_);
    208     AddChildView(star_view_);
    209     star_view_->SetVisible(true);
    210   }
    211 
    212   // Initialize the location entry. We do this to avoid a black flash which is
    213   // visible when the location entry has just been initialized.
    214   Update(NULL);
    215 
    216   OnChanged();
    217 }
    218 
    219 bool LocationBarView::IsInitialized() const {
    220   return location_entry_view_ != NULL;
    221 }
    222 
    223 // static
    224 SkColor LocationBarView::GetColor(ToolbarModel::SecurityLevel security_level,
    225                                   ColorKind kind) {
    226   switch (kind) {
    227 #if defined(OS_WIN)
    228     case BACKGROUND:    return color_utils::GetSysSkColor(COLOR_WINDOW);
    229     case TEXT:          return color_utils::GetSysSkColor(COLOR_WINDOWTEXT);
    230     case SELECTED_TEXT: return color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT);
    231 #else
    232     // TODO(beng): source from theme provider.
    233     case BACKGROUND:    return SK_ColorWHITE;
    234     case TEXT:          return SK_ColorBLACK;
    235     case SELECTED_TEXT: return SK_ColorWHITE;
    236 #endif
    237 
    238     case DEEMPHASIZED_TEXT:
    239       return color_utils::AlphaBlend(GetColor(security_level, TEXT),
    240                                      GetColor(security_level, BACKGROUND), 128);
    241 
    242     case SECURITY_TEXT: {
    243       SkColor color;
    244       switch (security_level) {
    245         case ToolbarModel::EV_SECURE:
    246         case ToolbarModel::SECURE:
    247           color = SkColorSetRGB(7, 149, 0);
    248           break;
    249 
    250         case ToolbarModel::SECURITY_WARNING:
    251           return GetColor(security_level, DEEMPHASIZED_TEXT);
    252           break;
    253 
    254         case ToolbarModel::SECURITY_ERROR:
    255           color = SkColorSetRGB(162, 0, 0);
    256           break;
    257 
    258         default:
    259           NOTREACHED();
    260           return GetColor(security_level, TEXT);
    261       }
    262       return color_utils::GetReadableColor(color, GetColor(security_level,
    263                                                            BACKGROUND));
    264     }
    265 
    266     default:
    267       NOTREACHED();
    268       return GetColor(security_level, TEXT);
    269   }
    270 }
    271 
    272 void LocationBarView::Update(const TabContents* tab_for_state_restoring) {
    273   bool star_enabled = star_view_ && !model_->input_in_progress() &&
    274                       edit_bookmarks_enabled_.GetValue();
    275   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
    276   if (star_view_)
    277     star_view_->SetVisible(star_enabled);
    278   RefreshContentSettingViews();
    279   RefreshPageActionViews();
    280   // Don't Update in app launcher mode so that the location entry does not show
    281   // a URL or security background.
    282   if (mode_ != APP_LAUNCHER)
    283     location_entry_->Update(tab_for_state_restoring);
    284   OnChanged();
    285 }
    286 
    287 void LocationBarView::UpdateContentSettingsIcons() {
    288   RefreshContentSettingViews();
    289 
    290   Layout();
    291   SchedulePaint();
    292 }
    293 
    294 void LocationBarView::UpdatePageActions() {
    295   size_t count_before = page_action_views_.size();
    296   RefreshPageActionViews();
    297   if (page_action_views_.size() != count_before) {
    298     NotificationService::current()->Notify(
    299         NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
    300         Source<LocationBar>(this),
    301         NotificationService::NoDetails());
    302   }
    303 
    304   Layout();
    305   SchedulePaint();
    306 }
    307 
    308 void LocationBarView::InvalidatePageActions() {
    309   size_t count_before = page_action_views_.size();
    310   DeletePageActionViews();
    311   if (page_action_views_.size() != count_before) {
    312     NotificationService::current()->Notify(
    313         NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
    314         Source<LocationBar>(this),
    315         NotificationService::NoDetails());
    316   }
    317 }
    318 
    319 void LocationBarView::OnFocus() {
    320   // Focus the location entry native view.
    321   location_entry_->SetFocus();
    322   GetWidget()->NotifyAccessibilityEvent(
    323       this, ui::AccessibilityTypes::EVENT_FOCUS, true);
    324 }
    325 
    326 void LocationBarView::SetProfile(Profile* profile) {
    327   DCHECK(profile);
    328   if (profile_ != profile) {
    329     profile_ = profile;
    330     location_entry_->model()->SetProfile(profile);
    331     selected_keyword_view_->set_profile(profile);
    332     keyword_hint_view_->set_profile(profile);
    333     for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
    334          i != content_setting_views_.end(); ++i)
    335       (*i)->set_profile(profile);
    336   }
    337 }
    338 
    339 void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction* page_action,
    340                                                   bool preview_enabled) {
    341   if (mode_ != NORMAL)
    342     return;
    343 
    344   DCHECK(page_action);
    345   TabContents* contents = GetTabContentsFromDelegate(delegate_);
    346 
    347   RefreshPageActionViews();
    348   PageActionWithBadgeView* page_action_view =
    349       static_cast<PageActionWithBadgeView*>(GetPageActionView(page_action));
    350   DCHECK(page_action_view);
    351   if (!page_action_view)
    352     return;
    353 
    354   page_action_view->image_view()->set_preview_enabled(preview_enabled);
    355   page_action_view->UpdateVisibility(contents,
    356       GURL(WideToUTF8(model_->GetText())));
    357   Layout();
    358   SchedulePaint();
    359 }
    360 
    361 views::View* LocationBarView::GetPageActionView(
    362     ExtensionAction *page_action) {
    363   DCHECK(page_action);
    364   for (PageActionViews::const_iterator i(page_action_views_.begin());
    365        i != page_action_views_.end(); ++i) {
    366     if ((*i)->image_view()->page_action() == page_action)
    367       return *i;
    368   }
    369   return NULL;
    370 }
    371 
    372 void LocationBarView::SetStarToggled(bool on) {
    373   if (star_view_)
    374     star_view_->SetToggled(on);
    375 }
    376 
    377 void LocationBarView::ShowStarBubble(const GURL& url, bool newly_bookmarked) {
    378   gfx::Rect screen_bounds(star_view_->GetImageBounds());
    379   // Compensate for some built-in padding in the Star image.
    380   screen_bounds.Inset(1, 1, 1, 2);
    381   gfx::Point origin(screen_bounds.origin());
    382   views::View::ConvertPointToScreen(star_view_, &origin);
    383   screen_bounds.set_origin(origin);
    384   browser::ShowBookmarkBubbleView(GetWindow(), screen_bounds, star_view_,
    385                                   profile_, url, newly_bookmarked);
    386 }
    387 
    388 gfx::Point LocationBarView::GetLocationEntryOrigin() const {
    389   gfx::Point origin(location_entry_view_->bounds().origin());
    390   // If the UI layout is RTL, the coordinate system is not transformed and
    391   // therefore we need to adjust the X coordinate so that bubble appears on the
    392   // right hand side of the location bar.
    393   if (base::i18n::IsRTL())
    394     origin.set_x(width() - origin.x());
    395   views::View::ConvertPointToScreen(this, &origin);
    396   return origin;
    397 }
    398 
    399 #if defined(OS_WIN)
    400 void LocationBarView::SetInstantSuggestion(const string16& text,
    401                                            bool animate_to_complete) {
    402   // Don't show the suggested text if inline autocomplete is prevented.
    403   if (!text.empty()) {
    404     if (!suggested_text_view_) {
    405       suggested_text_view_ = new SuggestedTextView(location_entry_->model());
    406       suggested_text_view_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    407       suggested_text_view_->SetColor(
    408           GetColor(ToolbarModel::NONE,
    409                    LocationBarView::DEEMPHASIZED_TEXT));
    410       suggested_text_view_->SetText(UTF16ToWide(text));
    411       suggested_text_view_->SetFont(location_entry_->GetFont());
    412       AddChildView(suggested_text_view_);
    413     } else if (suggested_text_view_->GetText() != UTF16ToWide(text)) {
    414       suggested_text_view_->SetText(UTF16ToWide(text));
    415     }
    416     if (animate_to_complete && !location_entry_->IsImeComposing())
    417       suggested_text_view_->StartAnimation();
    418   } else if (suggested_text_view_) {
    419     delete suggested_text_view_;
    420     suggested_text_view_ = NULL;
    421   } else {
    422     return;
    423   }
    424 
    425   Layout();
    426   SchedulePaint();
    427 }
    428 
    429 string16 LocationBarView::GetInstantSuggestion() const {
    430   return HasValidSuggestText() ? suggested_text_view_->GetText() : string16();
    431 }
    432 #endif
    433 
    434 gfx::Size LocationBarView::GetPreferredSize() {
    435   return gfx::Size(0, GetThemeProvider()->GetBitmapNamed(mode_ == POPUP ?
    436       IDR_LOCATIONBG_POPUPMODE_CENTER : IDR_LOCATIONBG_C)->height());
    437 }
    438 
    439 void LocationBarView::Layout() {
    440   if (!location_entry_.get())
    441     return;
    442 
    443   // TODO(sky): baseline layout.
    444   int location_y = kVerticalEdgeThickness;
    445   // In some cases (e.g. fullscreen mode) we may have 0 height.  We still want
    446   // to position our child views in this case, because other things may be
    447   // positioned relative to them (e.g. the "bookmark added" bubble if the user
    448   // hits ctrl-d).
    449   int location_height = std::max(height() - (kVerticalEdgeThickness * 2), 0);
    450 
    451   // The edge stroke is 1 px thick.  In popup mode, the edges are drawn by the
    452   // omnibox' parent, so there isn't any edge to account for at all.
    453   const int kEdgeThickness = (mode_ == NORMAL) ?
    454       kNormalHorizontalEdgeThickness : 0;
    455   // The edit has 1 px of horizontal whitespace inside it before the text.
    456   const int kEditInternalSpace = 1;
    457   // The space between an item and the edit is the normal item space, minus the
    458   // edit's built-in space (so the apparent space will be the same).
    459   const int kItemEditPadding =
    460       LocationBarView::kItemPadding - kEditInternalSpace;
    461   const int kEdgeEditPadding =
    462       LocationBarView::kEdgeItemPadding - kEditInternalSpace;
    463   const int kBubbleVerticalPadding = (mode_ == POPUP) ?
    464       -1 : kBubbleHorizontalPadding;
    465 
    466   // Start by reserving the padding at the right edge.
    467   int entry_width = width() - kEdgeThickness - kEdgeItemPadding;
    468 
    469   // |location_icon_view_| is visible except when |ev_bubble_view_| or
    470   // |selected_keyword_view_| are visible.
    471   int location_icon_width = 0;
    472   int ev_bubble_width = 0;
    473   location_icon_view_->SetVisible(false);
    474   ev_bubble_view_->SetVisible(false);
    475   const string16 keyword(location_entry_->model()->keyword());
    476   const bool is_keyword_hint(location_entry_->model()->is_keyword_hint());
    477   const bool show_selected_keyword = !keyword.empty() && !is_keyword_hint;
    478   if (show_selected_keyword) {
    479     // Assume the keyword might be hidden.
    480     entry_width -= (kEdgeThickness + kEdgeEditPadding);
    481   } else if (model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
    482     ev_bubble_view_->SetVisible(true);
    483     ev_bubble_view_->SetLabel(model_->GetEVCertName());
    484     ev_bubble_width = ev_bubble_view_->GetPreferredSize().width();
    485     // We'll adjust this width and take it out of |entry_width| below.
    486   } else {
    487     location_icon_view_->SetVisible(true);
    488     location_icon_width = location_icon_view_->GetPreferredSize().width();
    489     entry_width -= (kEdgeThickness + kEdgeItemPadding + location_icon_width +
    490         kItemEditPadding);
    491   }
    492 
    493   if (star_view_ && star_view_->IsVisible())
    494     entry_width -= star_view_->GetPreferredSize().width() + kItemPadding;
    495   for (PageActionViews::const_iterator i(page_action_views_.begin());
    496        i != page_action_views_.end(); ++i) {
    497     if ((*i)->IsVisible())
    498       entry_width -= ((*i)->GetPreferredSize().width() + kItemPadding);
    499   }
    500   for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
    501        i != content_setting_views_.end(); ++i) {
    502     if ((*i)->IsVisible())
    503       entry_width -= ((*i)->GetPreferredSize().width() + kItemPadding);
    504   }
    505   // The gap between the edit and whatever is to its right is shortened.
    506   entry_width += kEditInternalSpace;
    507 
    508   // Size the EV bubble.  We do this after taking the star/page actions/content
    509   // settings out of |entry_width| so we won't take too much space.
    510   if (ev_bubble_width) {
    511     // Try to elide the bubble to be no larger than half the total available
    512     // space, but never elide it any smaller than 150 px.
    513     static const int kMinElidedBubbleWidth = 150;
    514     static const double kMaxBubbleFraction = 0.5;
    515     const int total_padding =
    516         kEdgeThickness + kBubbleHorizontalPadding + kItemEditPadding;
    517     ev_bubble_width = std::min(ev_bubble_width, std::max(kMinElidedBubbleWidth,
    518         static_cast<int>((entry_width - total_padding) * kMaxBubbleFraction)));
    519     entry_width -= (total_padding + ev_bubble_width);
    520   }
    521 
    522 #if defined(OS_WIN)
    523   RECT formatting_rect;
    524   location_entry_->GetRect(&formatting_rect);
    525   RECT edit_bounds;
    526   location_entry_->GetClientRect(&edit_bounds);
    527   int max_edit_width = entry_width - formatting_rect.left -
    528                        (edit_bounds.right - formatting_rect.right);
    529 #else
    530   int max_edit_width = entry_width;
    531 #endif
    532 
    533   if (max_edit_width < 0)
    534     return;
    535   const int available_width = AvailableWidth(max_edit_width);
    536 
    537   const bool show_keyword_hint = !keyword.empty() && is_keyword_hint;
    538   selected_keyword_view_->SetVisible(show_selected_keyword);
    539   keyword_hint_view_->SetVisible(show_keyword_hint);
    540   if (show_selected_keyword) {
    541     if (selected_keyword_view_->keyword() != keyword) {
    542       selected_keyword_view_->SetKeyword(keyword);
    543       const TemplateURL* template_url =
    544           profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
    545       if (template_url && template_url->IsExtensionKeyword()) {
    546         const SkBitmap& bitmap = profile_->GetExtensionService()->
    547             GetOmniboxIcon(template_url->GetExtensionId());
    548         selected_keyword_view_->SetImage(bitmap);
    549         selected_keyword_view_->set_is_extension_icon(true);
    550       } else {
    551         selected_keyword_view_->SetImage(*ResourceBundle::GetSharedInstance().
    552             GetBitmapNamed(IDR_OMNIBOX_SEARCH));
    553         selected_keyword_view_->set_is_extension_icon(false);
    554       }
    555     }
    556   } else if (show_keyword_hint) {
    557     if (keyword_hint_view_->keyword() != keyword)
    558       keyword_hint_view_->SetKeyword(keyword);
    559   }
    560 
    561   // Lay out items to the right of the edit field.
    562   int offset = width() - kEdgeThickness - kEdgeItemPadding;
    563   if (star_view_ && star_view_->IsVisible()) {
    564     int star_width = star_view_->GetPreferredSize().width();
    565     offset -= star_width;
    566     star_view_->SetBounds(offset, location_y, star_width, location_height);
    567     offset -= kItemPadding;
    568   }
    569 
    570   for (PageActionViews::const_iterator i(page_action_views_.begin());
    571        i != page_action_views_.end(); ++i) {
    572     if ((*i)->IsVisible()) {
    573       int page_action_width = (*i)->GetPreferredSize().width();
    574       offset -= page_action_width;
    575       (*i)->SetBounds(offset, location_y, page_action_width, location_height);
    576       offset -= kItemPadding;
    577     }
    578   }
    579   // We use a reverse_iterator here because we're laying out the views from
    580   // right to left but in the vector they're ordered left to right.
    581   for (ContentSettingViews::const_reverse_iterator
    582        i(content_setting_views_.rbegin()); i != content_setting_views_.rend();
    583        ++i) {
    584     if ((*i)->IsVisible()) {
    585       int content_blocked_width = (*i)->GetPreferredSize().width();
    586       offset -= content_blocked_width;
    587       (*i)->SetBounds(offset, location_y, content_blocked_width,
    588                       location_height);
    589       offset -= kItemPadding;
    590     }
    591   }
    592 
    593   // Now lay out items to the left of the edit field.
    594   if (location_icon_view_->IsVisible()) {
    595     location_icon_view_->SetBounds(kEdgeThickness + kEdgeItemPadding,
    596         location_y, location_icon_width, location_height);
    597     offset = location_icon_view_->bounds().right() + kItemEditPadding;
    598   } else if (ev_bubble_view_->IsVisible()) {
    599     ev_bubble_view_->SetBounds(kEdgeThickness + kBubbleHorizontalPadding,
    600         location_y + kBubbleVerticalPadding, ev_bubble_width,
    601         ev_bubble_view_->GetPreferredSize().height());
    602     offset = ev_bubble_view_->bounds().right() + kItemEditPadding;
    603   } else {
    604     offset = kEdgeThickness +
    605         (show_selected_keyword ? kBubbleHorizontalPadding : kEdgeEditPadding);
    606   }
    607 
    608   // Now lay out the edit field and views that autocollapse to give it more
    609   // room.
    610   gfx::Rect location_bounds(offset, location_y, entry_width, location_height);
    611   if (show_selected_keyword) {
    612     selected_keyword_view_->SetBounds(0, location_y + kBubbleVerticalPadding,
    613         0, selected_keyword_view_->GetPreferredSize().height());
    614     LayoutView(selected_keyword_view_, kItemEditPadding, available_width,
    615                true, &location_bounds);
    616     location_bounds.set_x(selected_keyword_view_->IsVisible() ?
    617         (offset + selected_keyword_view_->width() + kItemEditPadding) :
    618         (kEdgeThickness + kEdgeEditPadding));
    619   } else if (show_keyword_hint) {
    620     keyword_hint_view_->SetBounds(0, location_y, 0, location_height);
    621     // Tricky: |entry_width| has already been enlarged by |kEditInternalSpace|.
    622     // But if we add a trailing view, it needs to have that enlargement be to
    623     // its left.  So we undo the enlargement, then include it in the padding for
    624     // the added view.
    625     location_bounds.Inset(0, 0, kEditInternalSpace, 0);
    626     LayoutView(keyword_hint_view_, kItemEditPadding, available_width, false,
    627                &location_bounds);
    628     if (!keyword_hint_view_->IsVisible()) {
    629       // Put back the enlargement that we undid above.
    630       location_bounds.Inset(0, 0, -kEditInternalSpace, 0);
    631     }
    632   }
    633 
    634 #if defined(OS_WIN)
    635   // Layout out the suggested text view right aligned to the location
    636   // entry. Only show the suggested text if we can fit the text from one
    637   // character before the end of the selection to the end of the text and the
    638   // suggested text. If we can't it means either the suggested text is too big,
    639   // or the user has scrolled.
    640 
    641   // TODO(sky): We could potentially combine this with the previous step to
    642   // force using minimum size if necessary, but currently the chance of showing
    643   // keyword hints and suggested text is minimal and we're not confident this
    644   // is the right approach for suggested text.
    645   if (suggested_text_view_) {
    646     // TODO(sky): need to layout when the user changes caret position.
    647     int suggested_text_width = suggested_text_view_->GetPreferredSize().width();
    648     int vis_text_width = location_entry_->WidthOfTextAfterCursor();
    649     if (vis_text_width + suggested_text_width > entry_width) {
    650       // Hide the suggested text if the user has scrolled or we can't fit all
    651       // the suggested text.
    652       suggested_text_view_->SetBounds(0, 0, 0, 0);
    653     } else {
    654       int location_needed_width = location_entry_->TextWidth();
    655       location_bounds.set_width(std::min(location_needed_width,
    656                                          entry_width - suggested_text_width));
    657       // TODO(sky): figure out why this needs the -1.
    658       suggested_text_view_->SetBounds(location_bounds.right() - 1,
    659                                       location_bounds.y(),
    660                                       suggested_text_width,
    661                                       location_bounds.height());
    662     }
    663   }
    664 #endif
    665 
    666   location_entry_view_->SetBoundsRect(location_bounds);
    667 }
    668 
    669 void LocationBarView::OnPaint(gfx::Canvas* canvas) {
    670   View::OnPaint(canvas);
    671 
    672   if (painter_.get()) {
    673     painter_->Paint(width(), height(), canvas);
    674   } else if (mode_ == POPUP) {
    675     canvas->TileImageInt(*GetThemeProvider()->GetBitmapNamed(
    676         IDR_LOCATIONBG_POPUPMODE_CENTER), 0, 0, 0, 0, width(), height());
    677   }
    678   // When used in the app launcher, don't draw a border, the LocationBarView has
    679   // its own views::Border.
    680 
    681   // Draw the background color so that the graphical elements at the edges
    682   // appear over the correct color.  (The edit draws its own background, so this
    683   // isn't important for that.)
    684   // TODO(pkasting): We need images that are transparent in the middle, so we
    685   // can draw the border images over the background color instead of the
    686   // reverse; this antialiases better (see comments in
    687   // AutocompletePopupContentsView::OnPaint()).
    688   gfx::Rect bounds(GetContentsBounds());
    689   bounds.Inset(0, kVerticalEdgeThickness);
    690   SkColor color(GetColor(ToolbarModel::NONE, BACKGROUND));
    691   if (mode_ == NORMAL) {
    692     SkPaint paint;
    693     paint.setColor(color);
    694     paint.setStyle(SkPaint::kFill_Style);
    695     paint.setAntiAlias(true);
    696     // The round corners of the omnibox match the round corners of the dropdown
    697     // below, and all our other bubbles.
    698     const SkScalar radius(SkIntToScalar(BubbleBorder::GetCornerRadius()));
    699     bounds.Inset(kNormalHorizontalEdgeThickness, 0);
    700     canvas->AsCanvasSkia()->drawRoundRect(gfx::RectToSkRect(bounds), radius,
    701                                           radius, paint);
    702   } else {
    703     canvas->FillRectInt(color, bounds.x(), bounds.y(), bounds.width(),
    704                         bounds.height());
    705   }
    706 
    707   if (show_focus_rect_ && HasFocus()) {
    708     gfx::Rect r = location_entry_view_->bounds();
    709 #if defined(OS_WIN)
    710     canvas->DrawFocusRect(r.x() - 1, r.y() - 1, r.width() + 2, r.height() + 2);
    711 #else
    712     canvas->DrawFocusRect(r.x() - 1, r.y(), r.width() + 2, r.height());
    713 #endif
    714   }
    715 }
    716 
    717 void LocationBarView::SetShowFocusRect(bool show) {
    718   show_focus_rect_ = show;
    719   SchedulePaint();
    720 }
    721 
    722 void LocationBarView::SelectAll() {
    723   location_entry_->SelectAll(true);
    724 }
    725 
    726 #if defined(OS_WIN)
    727 bool LocationBarView::OnMousePressed(const views::MouseEvent& event) {
    728   UINT msg;
    729   if (event.IsLeftMouseButton()) {
    730     msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
    731         WM_LBUTTONDBLCLK : WM_LBUTTONDOWN;
    732   } else if (event.IsMiddleMouseButton()) {
    733     msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
    734         WM_MBUTTONDBLCLK : WM_MBUTTONDOWN;
    735   } else if (event.IsRightMouseButton()) {
    736     msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
    737         WM_RBUTTONDBLCLK : WM_RBUTTONDOWN;
    738   } else {
    739     NOTREACHED();
    740     return false;
    741   }
    742   OnMouseEvent(event, msg);
    743   return true;
    744 }
    745 
    746 bool LocationBarView::OnMouseDragged(const views::MouseEvent& event) {
    747   OnMouseEvent(event, WM_MOUSEMOVE);
    748   return true;
    749 }
    750 
    751 void LocationBarView::OnMouseReleased(const views::MouseEvent& event) {
    752   UINT msg;
    753   if (event.IsLeftMouseButton()) {
    754     msg = WM_LBUTTONUP;
    755   } else if (event.IsMiddleMouseButton()) {
    756     msg = WM_MBUTTONUP;
    757   } else if (event.IsRightMouseButton()) {
    758     msg = WM_RBUTTONUP;
    759   } else {
    760     NOTREACHED();
    761     return;
    762   }
    763   OnMouseEvent(event, msg);
    764 }
    765 
    766 void LocationBarView::OnMouseCaptureLost() {
    767   location_entry_->HandleExternalMsg(WM_CAPTURECHANGED, 0, CPoint());
    768 }
    769 #endif
    770 
    771 void LocationBarView::OnAutocompleteAccept(
    772     const GURL& url,
    773     WindowOpenDisposition disposition,
    774     PageTransition::Type transition,
    775     const GURL& alternate_nav_url) {
    776   // WARNING: don't add an early return here. The calls after the if must
    777   // happen.
    778   if (url.is_valid()) {
    779     location_input_ = UTF8ToWide(url.spec());
    780     disposition_ = disposition;
    781     transition_ = transition;
    782 
    783     if (command_updater_) {
    784       if (!alternate_nav_url.is_valid()) {
    785         command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    786       } else {
    787         AlternateNavURLFetcher* fetcher =
    788             new AlternateNavURLFetcher(alternate_nav_url);
    789         // The AlternateNavURLFetcher will listen for the pending navigation
    790         // notification that will be issued as a result of the "open URL." It
    791         // will automatically install itself into that navigation controller.
    792         command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
    793         if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
    794           // I'm not sure this should be reachable, but I'm not also sure enough
    795           // that it shouldn't to stick in a NOTREACHED().  In any case, this is
    796           // harmless.
    797           delete fetcher;
    798         } else {
    799           // The navigation controller will delete the fetcher.
    800         }
    801       }
    802     }
    803   }
    804 }
    805 
    806 void LocationBarView::OnChanged() {
    807   location_icon_view_->SetImage(
    808       ResourceBundle::GetSharedInstance().GetBitmapNamed(
    809           location_entry_->GetIcon()));
    810   location_icon_view_->ShowTooltip(!location_entry()->IsEditingOrEmpty());
    811 
    812   Layout();
    813   SchedulePaint();
    814 }
    815 
    816 void LocationBarView::OnSelectionBoundsChanged() {
    817 #if defined(OS_WIN)
    818   if (suggested_text_view_)
    819     suggested_text_view_->StopAnimation();
    820 #else
    821   NOTREACHED();
    822 #endif
    823 }
    824 
    825 void LocationBarView::OnInputInProgress(bool in_progress) {
    826   delegate_->OnInputInProgress(in_progress);
    827 }
    828 
    829 void LocationBarView::OnKillFocus() {
    830 }
    831 
    832 void LocationBarView::OnSetFocus() {
    833   views::FocusManager* focus_manager = GetFocusManager();
    834   if (!focus_manager) {
    835     NOTREACHED();
    836     return;
    837   }
    838   focus_manager->SetFocusedView(this);
    839 }
    840 
    841 SkBitmap LocationBarView::GetFavicon() const {
    842   return GetTabContentsFromDelegate(delegate_)->GetFavicon();
    843 }
    844 
    845 string16 LocationBarView::GetTitle() const {
    846   return GetTabContentsFromDelegate(delegate_)->GetTitle();
    847 }
    848 
    849 InstantController* LocationBarView::GetInstant() {
    850   return delegate_->GetInstant();
    851 }
    852 
    853 TabContentsWrapper* LocationBarView::GetTabContentsWrapper() const {
    854   return delegate_->GetTabContentsWrapper();
    855 }
    856 
    857 int LocationBarView::AvailableWidth(int location_bar_width) {
    858   return location_bar_width - location_entry_->TextWidth();
    859 }
    860 
    861 void LocationBarView::LayoutView(views::View* view,
    862                                  int padding,
    863                                  int available_width,
    864                                  bool leading,
    865                                  gfx::Rect* bounds) {
    866   DCHECK(view && bounds);
    867   gfx::Size view_size = view->GetPreferredSize();
    868   if ((view_size.width() + padding) > available_width)
    869     view_size = view->GetMinimumSize();
    870   int desired_width = view_size.width() + padding;
    871   view->SetVisible(desired_width < bounds->width());
    872   if (view->IsVisible()) {
    873     view->SetBounds(
    874         leading ? bounds->x() : (bounds->right() - view_size.width()),
    875         view->y(), view_size.width(), view->height());
    876     bounds->set_width(bounds->width() - desired_width);
    877   }
    878 }
    879 
    880 void LocationBarView::RefreshContentSettingViews() {
    881   for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
    882        i != content_setting_views_.end(); ++i) {
    883     (*i)->UpdateFromTabContents(model_->input_in_progress() ? NULL :
    884                                 GetTabContentsFromDelegate(delegate_));
    885   }
    886 }
    887 
    888 void LocationBarView::DeletePageActionViews() {
    889   for (PageActionViews::const_iterator i(page_action_views_.begin());
    890        i != page_action_views_.end(); ++i)
    891     RemoveChildView(*i);
    892   STLDeleteElements(&page_action_views_);
    893 }
    894 
    895 void LocationBarView::RefreshPageActionViews() {
    896   if (mode_ != NORMAL)
    897     return;
    898 
    899   ExtensionService* service = profile_->GetExtensionService();
    900   if (!service)
    901     return;
    902 
    903   std::map<ExtensionAction*, bool> old_visibility;
    904   for (PageActionViews::const_iterator i(page_action_views_.begin());
    905        i != page_action_views_.end(); ++i)
    906     old_visibility[(*i)->image_view()->page_action()] = (*i)->IsVisible();
    907 
    908   // Remember the previous visibility of the page actions so that we can
    909   // notify when this changes.
    910   std::vector<ExtensionAction*> page_actions;
    911   for (size_t i = 0; i < service->extensions()->size(); ++i) {
    912     if (service->extensions()->at(i)->page_action())
    913       page_actions.push_back(service->extensions()->at(i)->page_action());
    914   }
    915 
    916   // On startup we sometimes haven't loaded any extensions. This makes sure
    917   // we catch up when the extensions (and any page actions) load.
    918   if (page_actions.size() != page_action_views_.size()) {
    919     DeletePageActionViews();  // Delete the old views (if any).
    920 
    921     page_action_views_.resize(page_actions.size());
    922 
    923     // Add the page actions in reverse order, so that the child views are
    924     // inserted in left-to-right order for accessibility.
    925     for (int i = page_actions.size() - 1; i >= 0; --i) {
    926       page_action_views_[i] = new PageActionWithBadgeView(
    927           new PageActionImageView(this, profile_, page_actions[i]));
    928       page_action_views_[i]->SetVisible(false);
    929       AddChildViewAt(page_action_views_[i], GetIndexOf(star_view_));
    930     }
    931   }
    932 
    933   TabContents* contents = GetTabContentsFromDelegate(delegate_);
    934   if (!page_action_views_.empty() && contents) {
    935     GURL url = GURL(WideToUTF8(model_->GetText()));
    936 
    937     for (PageActionViews::const_iterator i(page_action_views_.begin());
    938          i != page_action_views_.end(); ++i) {
    939       (*i)->UpdateVisibility(model_->input_in_progress() ? NULL : contents,
    940                              url);
    941 
    942       // Check if the visibility of the action changed and notify if it did.
    943       ExtensionAction* action = (*i)->image_view()->page_action();
    944       if (old_visibility.find(action) == old_visibility.end() ||
    945           old_visibility[action] != (*i)->IsVisible()) {
    946         NotificationService::current()->Notify(
    947             NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
    948             Source<ExtensionAction>(action),
    949             Details<TabContents>(contents));
    950       }
    951     }
    952   }
    953 }
    954 
    955 #if defined(OS_WIN)
    956 void LocationBarView::OnMouseEvent(const views::MouseEvent& event, UINT msg) {
    957   UINT flags = event.GetWindowsFlags();
    958   gfx::Point screen_point(event.location());
    959   ConvertPointToScreen(this, &screen_point);
    960   location_entry_->HandleExternalMsg(msg, flags, screen_point.ToPOINT());
    961 }
    962 #endif
    963 
    964 void LocationBarView::ShowFirstRunBubbleInternal(
    965     FirstRun::BubbleType bubble_type) {
    966 #if defined(OS_WIN)  // First run bubble doesn't make sense for Chrome OS.
    967   // Point at the start of the edit control; adjust to look as good as possible.
    968   const int kXOffset = kNormalHorizontalEdgeThickness + kEdgeItemPadding +
    969       ResourceBundle::GetSharedInstance().GetBitmapNamed(
    970       IDR_OMNIBOX_HTTP)->width() + kItemPadding;
    971   const int kYOffset = -(kVerticalEdgeThickness + 2);
    972   gfx::Point origin(location_entry_view_->bounds().x() + kXOffset,
    973                     y() + height() + kYOffset);
    974   // If the UI layout is RTL, the coordinate system is not transformed and
    975   // therefore we need to adjust the X coordinate so that bubble appears on the
    976   // right hand side of the location bar.
    977   if (base::i18n::IsRTL())
    978     origin.set_x(width() - origin.x());
    979   views::View::ConvertPointToScreen(this, &origin);
    980   FirstRunBubble::Show(profile_, GetWidget(), gfx::Rect(origin, gfx::Size()),
    981                        BubbleBorder::TOP_LEFT, bubble_type);
    982 #endif
    983 }
    984 
    985 std::string LocationBarView::GetClassName() const {
    986   return kViewClassName;
    987 }
    988 
    989 bool LocationBarView::SkipDefaultKeyEventProcessing(
    990     const views::KeyEvent& event) {
    991 #if defined(OS_WIN)
    992   if (views::FocusManager::IsTabTraversalKeyEvent(event)) {
    993     if (HasValidSuggestText()) {
    994       // Return true so that the edit sees the tab and commits the suggestion.
    995       return true;
    996     }
    997     if (keyword_hint_view_->IsVisible() && !event.IsShiftDown()) {
    998       // Return true so the edit gets the tab event and enters keyword mode.
    999       return true;
   1000     }
   1001 
   1002     // If the caret is not at the end, then tab moves the caret to the end.
   1003     if (!location_entry_->IsCaretAtEnd())
   1004       return true;
   1005 
   1006     // Tab while showing instant commits instant immediately.
   1007     // Return true so that focus traversal isn't attempted. The edit ends
   1008     // up doing nothing in this case.
   1009     if (location_entry_->model()->AcceptCurrentInstantPreview())
   1010       return true;
   1011   }
   1012 
   1013   return location_entry_->SkipDefaultKeyEventProcessing(event);
   1014 #else
   1015   // This method is not used for Linux ports. See FocusManager::OnKeyEvent() in
   1016   // src/views/focus/focus_manager.cc for details.
   1017   return false;
   1018 #endif
   1019 }
   1020 
   1021 void LocationBarView::GetAccessibleState(ui::AccessibleViewState* state) {
   1022   state->role = ui::AccessibilityTypes::ROLE_GROUPING;
   1023   state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION);
   1024   state->value = location_entry_->GetText();
   1025 
   1026   string16::size_type entry_start;
   1027   string16::size_type entry_end;
   1028   location_entry_->GetSelectionBounds(&entry_start, &entry_end);
   1029   state->selection_start = entry_start;
   1030   state->selection_end = entry_end;
   1031 }
   1032 
   1033 void LocationBarView::WriteDragDataForView(views::View* sender,
   1034                                            const gfx::Point& press_pt,
   1035                                            OSExchangeData* data) {
   1036   DCHECK_NE(GetDragOperationsForView(sender, press_pt),
   1037             ui::DragDropTypes::DRAG_NONE);
   1038 
   1039   TabContents* tab_contents = GetTabContentsFromDelegate(delegate_);
   1040   DCHECK(tab_contents);
   1041   drag_utils::SetURLAndDragImage(tab_contents->GetURL(),
   1042                                  UTF16ToWideHack(tab_contents->GetTitle()),
   1043                                  tab_contents->GetFavicon(), data);
   1044 }
   1045 
   1046 int LocationBarView::GetDragOperationsForView(views::View* sender,
   1047                                               const gfx::Point& p) {
   1048   DCHECK((sender == location_icon_view_) || (sender == ev_bubble_view_));
   1049   TabContents* tab_contents = GetTabContentsFromDelegate(delegate_);
   1050   return (tab_contents && tab_contents->GetURL().is_valid() &&
   1051           !location_entry()->IsEditingOrEmpty()) ?
   1052       (ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK) :
   1053       ui::DragDropTypes::DRAG_NONE;
   1054 }
   1055 
   1056 bool LocationBarView::CanStartDragForView(View* sender,
   1057                                           const gfx::Point& press_pt,
   1058                                           const gfx::Point& p) {
   1059   return true;
   1060 }
   1061 
   1062 ////////////////////////////////////////////////////////////////////////////////
   1063 // LocationBarView, LocationBar implementation:
   1064 
   1065 void LocationBarView::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
   1066   // Wait until search engines have loaded to show the first run bubble.
   1067   if (!profile_->GetTemplateURLModel()->loaded()) {
   1068     bubble_type_ = bubble_type;
   1069     template_url_model_ = profile_->GetTemplateURLModel();
   1070     template_url_model_->AddObserver(this);
   1071     template_url_model_->Load();
   1072     return;
   1073   }
   1074   ShowFirstRunBubbleInternal(bubble_type);
   1075 }
   1076 
   1077 void LocationBarView::SetSuggestedText(const string16& text,
   1078                                        InstantCompleteBehavior behavior) {
   1079   location_entry_->model()->SetSuggestedText(text, behavior);
   1080 }
   1081 
   1082 std::wstring LocationBarView::GetInputString() const {
   1083   return location_input_;
   1084 }
   1085 
   1086 WindowOpenDisposition LocationBarView::GetWindowOpenDisposition() const {
   1087   return disposition_;
   1088 }
   1089 
   1090 PageTransition::Type LocationBarView::GetPageTransition() const {
   1091   return transition_;
   1092 }
   1093 
   1094 void LocationBarView::AcceptInput() {
   1095   location_entry_->model()->AcceptInput(CURRENT_TAB, false);
   1096 }
   1097 
   1098 void LocationBarView::FocusLocation(bool select_all) {
   1099   location_entry_->SetFocus();
   1100   if (select_all)
   1101     location_entry_->SelectAll(true);
   1102 }
   1103 
   1104 void LocationBarView::FocusSearch() {
   1105   location_entry_->SetFocus();
   1106   location_entry_->SetForcedQuery();
   1107 }
   1108 
   1109 void LocationBarView::SaveStateToContents(TabContents* contents) {
   1110   location_entry_->SaveStateToTab(contents);
   1111 }
   1112 
   1113 void LocationBarView::Revert() {
   1114   location_entry_->RevertAll();
   1115 }
   1116 
   1117 const AutocompleteEditView* LocationBarView::location_entry() const {
   1118   return location_entry_.get();
   1119 }
   1120 
   1121 AutocompleteEditView* LocationBarView::location_entry() {
   1122   return location_entry_.get();
   1123 }
   1124 
   1125 LocationBarTesting* LocationBarView::GetLocationBarForTesting() {
   1126   return this;
   1127 }
   1128 
   1129 int LocationBarView::PageActionCount() {
   1130   return page_action_views_.size();
   1131 }
   1132 
   1133 int LocationBarView::PageActionVisibleCount() {
   1134   int result = 0;
   1135   for (size_t i = 0; i < page_action_views_.size(); i++) {
   1136     if (page_action_views_[i]->IsVisible())
   1137       ++result;
   1138   }
   1139   return result;
   1140 }
   1141 
   1142 ExtensionAction* LocationBarView::GetPageAction(size_t index) {
   1143   if (index < page_action_views_.size())
   1144     return page_action_views_[index]->image_view()->page_action();
   1145 
   1146   NOTREACHED();
   1147   return NULL;
   1148 }
   1149 
   1150 ExtensionAction* LocationBarView::GetVisiblePageAction(size_t index) {
   1151   size_t current = 0;
   1152   for (size_t i = 0; i < page_action_views_.size(); ++i) {
   1153     if (page_action_views_[i]->IsVisible()) {
   1154       if (current == index)
   1155         return page_action_views_[i]->image_view()->page_action();
   1156 
   1157       ++current;
   1158     }
   1159   }
   1160 
   1161   NOTREACHED();
   1162   return NULL;
   1163 }
   1164 
   1165 void LocationBarView::TestPageActionPressed(size_t index) {
   1166   size_t current = 0;
   1167   for (size_t i = 0; i < page_action_views_.size(); ++i) {
   1168     if (page_action_views_[i]->IsVisible()) {
   1169       if (current == index) {
   1170         const int kLeftMouseButton = 1;
   1171         page_action_views_[i]->image_view()->ExecuteAction(kLeftMouseButton,
   1172             false);  // inspect_with_devtools
   1173         return;
   1174       }
   1175       ++current;
   1176     }
   1177   }
   1178 
   1179   NOTREACHED();
   1180 }
   1181 
   1182 void LocationBarView::OnTemplateURLModelChanged() {
   1183   template_url_model_->RemoveObserver(this);
   1184   template_url_model_ = NULL;
   1185   // If the browser is no longer active, let's not show the info bubble, as this
   1186   // would make the browser the active window again.
   1187   if (location_entry_view_ && location_entry_view_->GetWidget()->IsActive())
   1188     ShowFirstRunBubble(bubble_type_);
   1189 }
   1190 
   1191 void LocationBarView::Observe(NotificationType type,
   1192                               const NotificationSource& source,
   1193                               const NotificationDetails& details) {
   1194   if (type.value == NotificationType::PREF_CHANGED) {
   1195     std::string* name = Details<std::string>(details).ptr();
   1196     if (*name == prefs::kEditBookmarksEnabled)
   1197       Update(NULL);
   1198   }
   1199 }
   1200 
   1201 #if defined(OS_WIN)
   1202 bool LocationBarView::HasValidSuggestText() const {
   1203   return suggested_text_view_ && !suggested_text_view_->size().IsEmpty() &&
   1204       !suggested_text_view_->GetText().empty();
   1205 }
   1206 #endif
   1207