location_bar_view.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright (c) 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#include "chrome/browser/ui/views/location_bar/location_bar_view.h" 6 7#include <algorithm> 8#include <map> 9 10#include "base/command_line.h" 11#include "base/i18n/rtl.h" 12#include "base/prefs/pref_service.h" 13#include "base/stl_util.h" 14#include "base/strings/utf_string_conversions.h" 15#include "chrome/app/chrome_command_ids.h" 16#include "chrome/browser/chrome_notification_types.h" 17#include "chrome/browser/command_updater.h" 18#include "chrome/browser/defaults.h" 19#include "chrome/browser/extensions/api/omnibox/omnibox_api.h" 20#include "chrome/browser/extensions/extension_service.h" 21#include "chrome/browser/extensions/location_bar_controller.h" 22#include "chrome/browser/extensions/tab_helper.h" 23#include "chrome/browser/favicon/favicon_tab_helper.h" 24#include "chrome/browser/profiles/profile.h" 25#include "chrome/browser/search/instant_service.h" 26#include "chrome/browser/search/instant_service_factory.h" 27#include "chrome/browser/search/search.h" 28#include "chrome/browser/search_engines/template_url_service_factory.h" 29#include "chrome/browser/translate/chrome_translate_client.h" 30#include "chrome/browser/translate/translate_service.h" 31#include "chrome/browser/ui/browser.h" 32#include "chrome/browser/ui/browser_finder.h" 33#include "chrome/browser/ui/browser_instant_controller.h" 34#include "chrome/browser/ui/browser_window.h" 35#include "chrome/browser/ui/omnibox/omnibox_popup_model.h" 36#include "chrome/browser/ui/omnibox/omnibox_popup_view.h" 37#include "chrome/browser/ui/passwords/manage_passwords_icon.h" 38#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h" 39#include "chrome/browser/ui/tabs/tab_strip_model.h" 40#include "chrome/browser/ui/view_ids.h" 41#include "chrome/browser/ui/views/browser_dialogs.h" 42#include "chrome/browser/ui/views/location_bar/add_to_app_launcher_view.h" 43#include "chrome/browser/ui/views/location_bar/content_setting_image_view.h" 44#include "chrome/browser/ui/views/location_bar/ev_bubble_view.h" 45#include "chrome/browser/ui/views/location_bar/generated_credit_card_view.h" 46#include "chrome/browser/ui/views/location_bar/keyword_hint_view.h" 47#include "chrome/browser/ui/views/location_bar/location_bar_layout.h" 48#include "chrome/browser/ui/views/location_bar/location_icon_view.h" 49#include "chrome/browser/ui/views/location_bar/open_pdf_in_reader_view.h" 50#include "chrome/browser/ui/views/location_bar/origin_chip_view.h" 51#include "chrome/browser/ui/views/location_bar/page_action_image_view.h" 52#include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h" 53#include "chrome/browser/ui/views/location_bar/search_button.h" 54#include "chrome/browser/ui/views/location_bar/selected_keyword_view.h" 55#include "chrome/browser/ui/views/location_bar/star_view.h" 56#include "chrome/browser/ui/views/location_bar/translate_icon_view.h" 57#include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h" 58#include "chrome/browser/ui/views/location_bar/zoom_view.h" 59#include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h" 60#include "chrome/browser/ui/views/passwords/manage_passwords_icon_view.h" 61#include "chrome/browser/ui/zoom/zoom_controller.h" 62#include "chrome/common/chrome_switches.h" 63#include "chrome/common/pref_names.h" 64#include "components/search_engines/template_url.h" 65#include "components/search_engines/template_url_service.h" 66#include "components/translate/core/browser/language_state.h" 67#include "content/public/browser/notification_service.h" 68#include "content/public/browser/render_widget_host_view.h" 69#include "content/public/browser/web_contents.h" 70#include "extensions/browser/extension_system.h" 71#include "extensions/common/feature_switch.h" 72#include "extensions/common/permissions/permissions_data.h" 73#include "grit/generated_resources.h" 74#include "grit/theme_resources.h" 75#include "ui/accessibility/ax_view_state.h" 76#include "ui/base/dragdrop/drag_drop_types.h" 77#include "ui/base/l10n/l10n_util.h" 78#include "ui/base/resource/resource_bundle.h" 79#include "ui/base/theme_provider.h" 80#include "ui/events/event.h" 81#include "ui/gfx/animation/slide_animation.h" 82#include "ui/gfx/canvas.h" 83#include "ui/gfx/color_utils.h" 84#include "ui/gfx/image/image.h" 85#include "ui/gfx/image/image_skia_operations.h" 86#include "ui/gfx/scoped_canvas.h" 87#include "ui/gfx/skia_util.h" 88#include "ui/gfx/text_utils.h" 89#include "ui/native_theme/native_theme.h" 90#include "ui/views/background.h" 91#include "ui/views/border.h" 92#include "ui/views/button_drag_utils.h" 93#include "ui/views/controls/button/image_button.h" 94#include "ui/views/controls/label.h" 95#include "ui/views/widget/widget.h" 96 97#if !defined(OS_CHROMEOS) 98#include "chrome/browser/ui/views/first_run_bubble.h" 99#endif 100 101using content::WebContents; 102using views::View; 103 104namespace { 105 106const gfx::Tween::Type kShowTweenType = gfx::Tween::LINEAR_OUT_SLOW_IN; 107const gfx::Tween::Type kHideTweenType = gfx::Tween::FAST_OUT_LINEAR_IN; 108 109// The search button images are made to look as if they overlay the normal edge 110// images, but to align things, the search button needs to be inset horizontally 111// by 1 px. 112const int kSearchButtonInset = 1; 113 114// Given a containing |height| and a |base_font_list|, shrinks the font size 115// until the font list will fit within |height| while having its cap height 116// vertically centered. Returns the correctly-sized font list. 117// 118// The expected layout: 119// +--------+-----------------------------------------------+------------+ 120// | | y offset | space | 121// | +--------+-------------------+------------------+ above | 122// | | | | internal leading | cap height | 123// | box | font | ascent (baseline) +------------------+------------+ 124// | height | height | | cap height | 125// | | |-------------------+------------------+------------+ 126// | | | descent (height - baseline) | space | 127// | +--------+--------------------------------------+ below | 128// | | space at bottom | cap height | 129// +--------+-----------------------------------------------+------------+ 130// Goal: 131// center of box height == center of cap height 132// (i.e. space above cap height == space below cap height) 133// Restrictions: 134// y offset >= 0 135// space at bottom >= 0 136// (i.e. Entire font must be visible inside the box.) 137gfx::FontList GetLargestFontListWithHeightBound( 138 const gfx::FontList& base_font_list, 139 int height) { 140 gfx::FontList font_list = base_font_list; 141 for (int font_size = font_list.GetFontSize(); font_size > 1; --font_size) { 142 const int internal_leading = 143 font_list.GetBaseline() - font_list.GetCapHeight(); 144 // Some platforms don't support getting the cap height, and simply return 145 // the entire font ascent from GetCapHeight(). Centering the ascent makes 146 // the font look too low, so if GetCapHeight() returns the ascent, center 147 // the entire font height instead. 148 const int space = 149 height - ((internal_leading != 0) ? 150 font_list.GetCapHeight() : font_list.GetHeight()); 151 const int y_offset = space / 2 - internal_leading; 152 const int space_at_bottom = height - (y_offset + font_list.GetHeight()); 153 if ((y_offset >= 0) && (space_at_bottom >= 0)) 154 break; 155 font_list = font_list.DeriveWithSizeDelta(-1); 156 } 157 return font_list; 158} 159 160int GetEditLeadingInternalSpace() { 161 // The textfield has 1 px of whitespace before the text in the RTL case only. 162 return base::i18n::IsRTL() ? 1 : 0; 163} 164 165// Functor for moving BookmarkManagerPrivate page actions to the right via 166// stable_partition. 167class IsPageActionViewRightAligned { 168 public: 169 explicit IsPageActionViewRightAligned(ExtensionService* extension_service) 170 : extension_service_(extension_service) {} 171 172 bool operator()(PageActionWithBadgeView* page_action_view) { 173 return extension_service_ 174 ->GetExtensionById( 175 page_action_view->image_view()->page_action()->extension_id(), 176 false) 177 ->permissions_data() 178 ->HasAPIPermission(extensions::APIPermission::kBookmarkManagerPrivate); 179 } 180 181 private: 182 ExtensionService* extension_service_; 183 184 // NOTE: Can't DISALLOW_COPY_AND_ASSIGN as we pass this object by value to 185 // std::stable_partition(). 186}; 187 188} // namespace 189 190 191// LocationBarView ----------------------------------------------------------- 192 193// static 194const int LocationBarView::kNormalEdgeThickness = 2; 195const int LocationBarView::kPopupEdgeThickness = 1; 196const int LocationBarView::kItemPadding = 3; 197const int LocationBarView::kIconInternalPadding = 2; 198const int LocationBarView::kBubblePadding = 1; 199const char LocationBarView::kViewClassName[] = "LocationBarView"; 200 201LocationBarView::LocationBarView(Browser* browser, 202 Profile* profile, 203 CommandUpdater* command_updater, 204 Delegate* delegate, 205 bool is_popup_mode) 206 : LocationBar(profile), 207 OmniboxEditController(command_updater), 208 browser_(browser), 209 omnibox_view_(NULL), 210 delegate_(delegate), 211 origin_chip_view_(NULL), 212 location_icon_view_(NULL), 213 ev_bubble_view_(NULL), 214 ime_inline_autocomplete_view_(NULL), 215 selected_keyword_view_(NULL), 216 suggested_text_view_(NULL), 217 keyword_hint_view_(NULL), 218 mic_search_view_(NULL), 219 zoom_view_(NULL), 220 generated_credit_card_view_(NULL), 221 open_pdf_in_reader_view_(NULL), 222 manage_passwords_icon_view_(NULL), 223 translate_icon_view_(NULL), 224 add_to_app_launcher_view_(NULL), 225 star_view_(NULL), 226 search_button_(NULL), 227 is_popup_mode_(is_popup_mode), 228 show_focus_rect_(false), 229 template_url_service_(NULL), 230 dropdown_animation_offset_(0), 231 starting_omnibox_offset_(0), 232 current_omnibox_offset_(0), 233 starting_omnibox_leading_inset_(0), 234 current_omnibox_leading_inset_(0), 235 current_omnibox_width_(0), 236 ending_omnibox_width_(0), 237 weak_ptr_factory_(this) { 238 edit_bookmarks_enabled_.Init( 239 prefs::kEditBookmarksEnabled, profile->GetPrefs(), 240 base::Bind(&LocationBarView::Update, base::Unretained(this), 241 static_cast<content::WebContents*>(NULL))); 242 243 if (browser_) 244 browser_->search_model()->AddObserver(this); 245} 246 247LocationBarView::~LocationBarView() { 248 if (template_url_service_) 249 template_url_service_->RemoveObserver(this); 250 if (browser_) 251 browser_->search_model()->RemoveObserver(this); 252} 253 254//////////////////////////////////////////////////////////////////////////////// 255// LocationBarView, public: 256 257void LocationBarView::Init() { 258 // We need to be in a Widget, otherwise GetNativeTheme() may change and we're 259 // not prepared for that. 260 DCHECK(GetWidget()); 261 262 const int kOmniboxPopupBorderImages[] = 263 IMAGE_GRID(IDR_OMNIBOX_POPUP_BORDER_AND_SHADOW); 264 const int kOmniboxBorderImages[] = IMAGE_GRID(IDR_TEXTFIELD); 265 border_painter_.reset(views::Painter::CreateImageGridPainter( 266 is_popup_mode_ ? kOmniboxPopupBorderImages : kOmniboxBorderImages)); 267 268 location_icon_view_ = new LocationIconView(this); 269 location_icon_view_->set_drag_controller(this); 270 AddChildView(location_icon_view_); 271 272 // Determine the main font. 273 gfx::FontList font_list = ResourceBundle::GetSharedInstance().GetFontList( 274 ResourceBundle::BaseFont); 275 const int current_font_size = font_list.GetFontSize(); 276 const int desired_font_size = browser_defaults::kOmniboxFontPixelSize; 277 if (current_font_size != desired_font_size) { 278 font_list = 279 font_list.DeriveWithSizeDelta(desired_font_size - current_font_size); 280 } 281 // Shrink large fonts to make them fit. 282 // TODO(pkasting): Stretch the location bar instead in this case. 283 const int location_height = GetInternalHeight(true); 284 font_list = GetLargestFontListWithHeightBound(font_list, location_height); 285 286 // Determine the font for use inside the bubbles. The bubble background 287 // images have 1 px thick edges, which we don't want to overlap. 288 const int kBubbleInteriorVerticalPadding = 1; 289 const int bubble_vertical_padding = 290 (kBubblePadding + kBubbleInteriorVerticalPadding) * 2; 291 const gfx::FontList bubble_font_list( 292 GetLargestFontListWithHeightBound( 293 font_list, location_height - bubble_vertical_padding)); 294 295 const SkColor background_color = 296 GetColor(ToolbarModel::NONE, LocationBarView::BACKGROUND); 297 ev_bubble_view_ = new EVBubbleView( 298 bubble_font_list, GetColor(ToolbarModel::EV_SECURE, SECURITY_TEXT), 299 background_color, this); 300 ev_bubble_view_->set_drag_controller(this); 301 AddChildView(ev_bubble_view_); 302 303 // Initialize the Omnibox view. 304 omnibox_view_ = new OmniboxViewViews( 305 this, profile(), command_updater(), 306 is_popup_mode_ || 307 (browser_->is_app() && CommandLine::ForCurrentProcess()-> 308 HasSwitch(switches::kEnableStreamlinedHostedApps)), 309 this, font_list); 310 omnibox_view_->Init(); 311 omnibox_view_->SetFocusable(true); 312 AddChildView(omnibox_view_); 313 314 // Initialize the inline autocomplete view which is visible only when IME is 315 // turned on. Use the same font with the omnibox and highlighted background. 316 ime_inline_autocomplete_view_ = new views::Label(base::string16(), font_list); 317 ime_inline_autocomplete_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 318 ime_inline_autocomplete_view_->SetAutoColorReadabilityEnabled(false); 319 ime_inline_autocomplete_view_->set_background( 320 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor( 321 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused))); 322 ime_inline_autocomplete_view_->SetEnabledColor( 323 GetNativeTheme()->GetSystemColor( 324 ui::NativeTheme::kColorId_TextfieldSelectionColor)); 325 ime_inline_autocomplete_view_->SetVisible(false); 326 AddChildView(ime_inline_autocomplete_view_); 327 328 origin_chip_view_ = new OriginChipView(this, profile(), font_list); 329 origin_chip_view_->SetFocusable(false); 330 origin_chip_view_->set_drag_controller(this); 331 AddChildView(origin_chip_view_); 332 333 const SkColor text_color = GetColor(ToolbarModel::NONE, TEXT); 334 selected_keyword_view_ = new SelectedKeywordView( 335 bubble_font_list, text_color, background_color, profile()); 336 AddChildView(selected_keyword_view_); 337 338 suggested_text_view_ = new views::Label(base::string16(), font_list); 339 suggested_text_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 340 suggested_text_view_->SetAutoColorReadabilityEnabled(false); 341 suggested_text_view_->SetEnabledColor(GetColor( 342 ToolbarModel::NONE, LocationBarView::DEEMPHASIZED_TEXT)); 343 suggested_text_view_->SetVisible(false); 344 AddChildView(suggested_text_view_); 345 346 keyword_hint_view_ = new KeywordHintView( 347 profile(), font_list, 348 GetColor(ToolbarModel::NONE, LocationBarView::DEEMPHASIZED_TEXT), 349 background_color); 350 AddChildView(keyword_hint_view_); 351 352 mic_search_view_ = new views::ImageButton(this); 353 mic_search_view_->set_id(VIEW_ID_MIC_SEARCH_BUTTON); 354 mic_search_view_->SetAccessibilityFocusable(true); 355 mic_search_view_->SetTooltipText( 356 l10n_util::GetStringUTF16(IDS_TOOLTIP_MIC_SEARCH)); 357 mic_search_view_->SetImage( 358 views::Button::STATE_NORMAL, 359 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 360 IDR_OMNIBOX_MIC_SEARCH)); 361 mic_search_view_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, 362 views::ImageButton::ALIGN_MIDDLE); 363 mic_search_view_->SetVisible(false); 364 AddChildView(mic_search_view_); 365 366 for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { 367 ContentSettingImageView* content_blocked_view = 368 new ContentSettingImageView(static_cast<ContentSettingsType>(i), this, 369 bubble_font_list, text_color, 370 background_color); 371 content_setting_views_.push_back(content_blocked_view); 372 content_blocked_view->SetVisible(false); 373 AddChildView(content_blocked_view); 374 } 375 376 generated_credit_card_view_ = new GeneratedCreditCardView(delegate_); 377 AddChildView(generated_credit_card_view_); 378 379 zoom_view_ = new ZoomView(delegate_); 380 zoom_view_->set_id(VIEW_ID_ZOOM_BUTTON); 381 AddChildView(zoom_view_); 382 383 open_pdf_in_reader_view_ = new OpenPDFInReaderView(); 384 AddChildView(open_pdf_in_reader_view_); 385 386 manage_passwords_icon_view_ = new ManagePasswordsIconView(command_updater()); 387 AddChildView(manage_passwords_icon_view_); 388 389 translate_icon_view_ = new TranslateIconView(command_updater()); 390 translate_icon_view_->SetVisible(false); 391 AddChildView(translate_icon_view_); 392 393 add_to_app_launcher_view_ = new AddToAppLauncherView( 394 this, bubble_font_list, text_color, background_color); 395 add_to_app_launcher_view_->SetVisible(false); 396 AddChildView(add_to_app_launcher_view_); 397 398 star_view_ = new StarView(command_updater()); 399 star_view_->SetVisible(false); 400 AddChildView(star_view_); 401 402 search_button_ = new SearchButton(this); 403 search_button_->SetVisible(false); 404 AddChildView(search_button_); 405 406 show_url_animation_.reset(new gfx::SlideAnimation(this)); 407 show_url_animation_->SetTweenType(kShowTweenType); 408 show_url_animation_->SetSlideDuration(200); 409 410 hide_url_animation_.reset(new gfx::SlideAnimation(this)); 411 hide_url_animation_->SetTweenType(kHideTweenType); 412 hide_url_animation_->SetSlideDuration(175); 413 414 content::Source<Profile> profile_source = content::Source<Profile>(profile()); 415 registrar_.Add( 416 this, chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, profile_source); 417 registrar_.Add(this, 418 chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, 419 profile_source); 420 421 // Initialize the location entry. We do this to avoid a black flash which is 422 // visible when the location entry has just been initialized. 423 Update(NULL); 424} 425 426bool LocationBarView::IsInitialized() const { 427 return omnibox_view_ != NULL; 428} 429 430SkColor LocationBarView::GetColor(ToolbarModel::SecurityLevel security_level, 431 ColorKind kind) const { 432 const ui::NativeTheme* native_theme = GetNativeTheme(); 433 switch (kind) { 434 case BACKGROUND: 435 return native_theme->GetSystemColor( 436 ui::NativeTheme::kColorId_TextfieldDefaultBackground); 437 438 case TEXT: 439 return native_theme->GetSystemColor( 440 ui::NativeTheme::kColorId_TextfieldDefaultColor); 441 442 case SELECTED_TEXT: 443 return native_theme->GetSystemColor( 444 ui::NativeTheme::kColorId_TextfieldSelectionColor); 445 446 case DEEMPHASIZED_TEXT: 447 return color_utils::AlphaBlend( 448 GetColor(security_level, TEXT), 449 GetColor(security_level, BACKGROUND), 450 128); 451 452 case SECURITY_TEXT: { 453 SkColor color; 454 switch (security_level) { 455 case ToolbarModel::EV_SECURE: 456 case ToolbarModel::SECURE: 457 color = SkColorSetRGB(7, 149, 0); 458 break; 459 460 case ToolbarModel::SECURITY_WARNING: 461 case ToolbarModel::SECURITY_POLICY_WARNING: 462 return GetColor(security_level, DEEMPHASIZED_TEXT); 463 break; 464 465 case ToolbarModel::SECURITY_ERROR: 466 color = SkColorSetRGB(162, 0, 0); 467 break; 468 469 default: 470 NOTREACHED(); 471 return GetColor(security_level, TEXT); 472 } 473 return color_utils::GetReadableColor( 474 color, GetColor(security_level, BACKGROUND)); 475 } 476 477 default: 478 NOTREACHED(); 479 return GetColor(security_level, TEXT); 480 } 481} 482 483void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble) { 484 DCHECK(zoom_view_); 485 if (RefreshZoomView()) { 486 Layout(); 487 SchedulePaint(); 488 } 489 490 WebContents* web_contents = GetWebContents(); 491 if (can_show_bubble && zoom_view_->visible() && web_contents) 492 ZoomBubbleView::ShowBubble(web_contents, true); 493} 494 495void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction* page_action, 496 bool preview_enabled) { 497 if (is_popup_mode_) 498 return; 499 500 DCHECK(page_action); 501 WebContents* web_contents = GetWebContents(); 502 503 RefreshPageActionViews(); 504 PageActionWithBadgeView* page_action_view = 505 static_cast<PageActionWithBadgeView*>(GetPageActionView(page_action)); 506 DCHECK(page_action_view); 507 if (!page_action_view) 508 return; 509 510 page_action_view->image_view()->set_preview_enabled(preview_enabled); 511 page_action_view->UpdateVisibility(web_contents, GetToolbarModel()->GetURL()); 512 Layout(); 513 SchedulePaint(); 514} 515 516PageActionWithBadgeView* LocationBarView::GetPageActionView( 517 ExtensionAction* page_action) { 518 DCHECK(page_action); 519 for (PageActionViews::const_iterator i(page_action_views_.begin()); 520 i != page_action_views_.end(); ++i) { 521 if ((*i)->image_view()->page_action() == page_action) 522 return *i; 523 } 524 return NULL; 525} 526 527void LocationBarView::SetStarToggled(bool on) { 528 if (star_view_) 529 star_view_->SetToggled(on); 530} 531 532void LocationBarView::SetTranslateIconToggled(bool on) { 533 translate_icon_view_->SetToggled(on); 534} 535 536gfx::Point LocationBarView::GetOmniboxViewOrigin() const { 537 gfx::Point origin(omnibox_view_->bounds().origin()); 538 origin.set_x(GetMirroredXInView(origin.x() - current_omnibox_offset_)); 539 views::View::ConvertPointToScreen(this, &origin); 540 return origin; 541} 542 543void LocationBarView::SetImeInlineAutocompletion(const base::string16& text) { 544 ime_inline_autocomplete_view_->SetText(text); 545 ime_inline_autocomplete_view_->SetVisible(!text.empty()); 546} 547 548void LocationBarView::SetGrayTextAutocompletion(const base::string16& text) { 549 if (suggested_text_view_->text() != text) { 550 suggested_text_view_->SetText(text); 551 suggested_text_view_->SetVisible(!text.empty()); 552 Layout(); 553 SchedulePaint(); 554 } 555} 556 557base::string16 LocationBarView::GetGrayTextAutocompletion() const { 558 return HasValidSuggestText() ? 559 suggested_text_view_->text() : base::string16(); 560} 561 562void LocationBarView::SetShowFocusRect(bool show) { 563 show_focus_rect_ = show; 564 SchedulePaint(); 565} 566 567void LocationBarView::SelectAll() { 568 omnibox_view_->SelectAll(true); 569} 570 571gfx::Point LocationBarView::GetLocationBarAnchorPoint() const { 572 // The +1 in the next line creates a 1-px gap between icon and arrow tip. 573 gfx::Point icon_bottom(0, location_icon_view_->GetImageBounds().bottom() - 574 LocationBarView::kIconInternalPadding + 1); 575 gfx::Point icon_center(location_icon_view_->GetImageBounds().CenterPoint()); 576 gfx::Point point(icon_center.x(), icon_bottom.y()); 577 ConvertPointToTarget(location_icon_view_, this, &point); 578 return point; 579} 580 581views::View* LocationBarView::generated_credit_card_view() { 582 return generated_credit_card_view_; 583} 584 585int LocationBarView::GetInternalHeight(bool use_preferred_size) { 586 int total_height = 587 use_preferred_size ? GetPreferredSize().height() : height(); 588 return std::max(total_height - (vertical_edge_thickness() * 2), 0); 589} 590 591void LocationBarView::GetOmniboxPopupPositioningInfo( 592 gfx::Point* top_left_screen_coord, 593 int* popup_width, 594 int* left_margin, 595 int* right_margin) { 596 // Because the popup might appear atop the attached bookmark bar, there won't 597 // necessarily be a client edge separating it from the rest of the toolbar. 598 // Therefore we position the popup high enough so it can draw its own client 599 // edge at the top, in the same place the toolbar would normally draw the 600 // client edge. 601 *top_left_screen_coord = gfx::Point( 602 0, 603 parent()->height() - views::NonClientFrameView::kClientEdgeThickness); 604 views::View::ConvertPointToScreen(parent(), top_left_screen_coord); 605 *popup_width = parent()->width(); 606 607 gfx::Rect location_bar_bounds(bounds()); 608 location_bar_bounds.Inset(kNormalEdgeThickness, 0); 609 *left_margin = location_bar_bounds.x(); 610 *right_margin = *popup_width - location_bar_bounds.right(); 611} 612 613//////////////////////////////////////////////////////////////////////////////// 614// LocationBarView, public LocationBar implementation: 615 616void LocationBarView::FocusLocation(bool select_all) { 617 omnibox_view_->SetFocus(); 618 if (select_all) 619 omnibox_view_->SelectAll(true); 620} 621 622void LocationBarView::Revert() { 623 omnibox_view_->RevertAll(); 624} 625 626OmniboxView* LocationBarView::GetOmniboxView() { 627 return omnibox_view_; 628} 629 630//////////////////////////////////////////////////////////////////////////////// 631// LocationBarView, public views::View implementation: 632 633bool LocationBarView::HasFocus() const { 634 return omnibox_view_->model()->has_focus(); 635} 636 637void LocationBarView::GetAccessibleState(ui::AXViewState* state) { 638 if (!IsInitialized()) 639 return; 640 641 state->role = ui::AX_ROLE_LOCATION_BAR; 642 state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION); 643 state->value = omnibox_view_->GetText(); 644 645 base::string16::size_type entry_start; 646 base::string16::size_type entry_end; 647 omnibox_view_->GetSelectionBounds(&entry_start, &entry_end); 648 state->selection_start = entry_start; 649 state->selection_end = entry_end; 650 651 if (is_popup_mode_) { 652 state->AddStateFlag(ui::AX_STATE_READ_ONLY); 653 } else { 654 state->set_value_callback = 655 base::Bind(&LocationBarView::AccessibilitySetValue, 656 weak_ptr_factory_.GetWeakPtr()); 657 } 658} 659 660gfx::Size LocationBarView::GetPreferredSize() const { 661 // Compute minimum height. 662 gfx::Size min_size(border_painter_->GetMinimumSize()); 663 if (!IsInitialized()) 664 return min_size; 665 gfx::Size search_button_min_size(search_button_->GetMinimumSize()); 666 min_size.SetToMax(search_button_min_size); 667 668 // Compute width of omnibox-leading content. 669 const int horizontal_edge_thickness = GetHorizontalEdgeThickness(); 670 int leading_width = horizontal_edge_thickness; 671 // TODO(pkasting): Make the origin chip min width sane, and make the chip 672 // handle being shrunken down more gracefully; then uncomment this. 673 /*if (GetToolbarModel()->ShouldShowOriginChip()) 674 leading_width += origin_chip_view_->GetMinimumSize().width();*/ 675 if (ShouldShowKeywordBubble()) { 676 // The selected keyword view can collapse completely. 677 } else if (ShouldShowEVBubble()) { 678 leading_width += kBubblePadding + 679 ev_bubble_view_->GetMinimumSizeForLabelText( 680 GetToolbarModel()->GetEVCertName()).width(); 681 } else if (!origin_chip_view_->visible()) { 682 leading_width += 683 kItemPadding + location_icon_view_->GetMinimumSize().width(); 684 } 685 leading_width += kItemPadding - GetEditLeadingInternalSpace(); 686 687 // Compute width of omnibox-trailing content. 688 int trailing_width = search_button_->visible() ? 689 (search_button_->GetMinimumSize().width() + kSearchButtonInset) : 690 horizontal_edge_thickness; 691 trailing_width += IncrementalMinimumWidth(star_view_) + 692 IncrementalMinimumWidth(translate_icon_view_) + 693 IncrementalMinimumWidth(open_pdf_in_reader_view_) + 694 IncrementalMinimumWidth(manage_passwords_icon_view_) + 695 IncrementalMinimumWidth(zoom_view_) + 696 IncrementalMinimumWidth(generated_credit_card_view_) + 697 IncrementalMinimumWidth(mic_search_view_) + 698 IncrementalMinimumWidth(add_to_app_launcher_view_) + kItemPadding; 699 for (PageActionViews::const_iterator i(page_action_views_.begin()); 700 i != page_action_views_.end(); ++i) 701 trailing_width += IncrementalMinimumWidth((*i)); 702 for (ContentSettingViews::const_iterator i(content_setting_views_.begin()); 703 i != content_setting_views_.end(); ++i) 704 trailing_width += IncrementalMinimumWidth((*i)); 705 706 min_size.set_width( 707 leading_width + omnibox_view_->GetMinimumSize().width() + trailing_width); 708 return min_size; 709} 710 711void LocationBarView::Layout() { 712 if (!IsInitialized()) 713 return; 714 715 origin_chip_view_->SetVisible(GetToolbarModel()->ShouldShowOriginChip()); 716 selected_keyword_view_->SetVisible(false); 717 location_icon_view_->SetVisible(false); 718 ev_bubble_view_->SetVisible(false); 719 keyword_hint_view_->SetVisible(false); 720 721 LocationBarLayout leading_decorations( 722 LocationBarLayout::LEFT_EDGE, 723 kItemPadding - GetEditLeadingInternalSpace()); 724 LocationBarLayout trailing_decorations(LocationBarLayout::RIGHT_EDGE, 725 kItemPadding); 726 727 const int origin_chip_preferred_width = 728 origin_chip_view_->GetPreferredSize().width(); 729 const int origin_chip_width = 730 origin_chip_view_->visible() ? origin_chip_preferred_width : 0; 731 // Always give the origin chip view its desired size and lay it out, even when 732 // it's not visible, so we can calculate the correct animation values below 733 // when switching to tabs that have the origin chip hidden. 734 origin_chip_view_->SetBounds(0, 0, origin_chip_preferred_width, height()); 735 origin_chip_view_->Layout(); 736 737 const int bubble_location_y = vertical_edge_thickness() + kBubblePadding; 738 const base::string16 keyword(omnibox_view_->model()->keyword()); 739 // In some cases (e.g. fullscreen mode) we may have 0 height. We still want 740 // to position our child views in this case, because other things may be 741 // positioned relative to them (e.g. the "bookmark added" bubble if the user 742 // hits ctrl-d). 743 const int location_height = GetInternalHeight(false); 744 const int bubble_height = std::max(location_height - (kBubblePadding * 2), 0); 745 if (ShouldShowKeywordBubble()) { 746 leading_decorations.AddDecoration(bubble_location_y, bubble_height, true, 0, 747 kBubblePadding, kItemPadding, 748 selected_keyword_view_); 749 if (selected_keyword_view_->keyword() != keyword) { 750 selected_keyword_view_->SetKeyword(keyword); 751 const TemplateURL* template_url = 752 TemplateURLServiceFactory::GetForProfile(profile())-> 753 GetTemplateURLForKeyword(keyword); 754 if (template_url && 755 (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) { 756 gfx::Image image = extensions::OmniboxAPI::Get(profile())-> 757 GetOmniboxIcon(template_url->GetExtensionId()); 758 selected_keyword_view_->SetImage(image.AsImageSkia()); 759 selected_keyword_view_->set_is_extension_icon(true); 760 } else { 761 selected_keyword_view_->SetImage( 762 *(GetThemeProvider()->GetImageSkiaNamed(IDR_OMNIBOX_SEARCH))); 763 selected_keyword_view_->set_is_extension_icon(false); 764 } 765 } 766 } else if (ShouldShowEVBubble()) { 767 ev_bubble_view_->SetLabel(GetToolbarModel()->GetEVCertName()); 768 // The largest fraction of the omnibox that can be taken by the EV bubble. 769 const double kMaxBubbleFraction = 0.5; 770 leading_decorations.AddDecoration(bubble_location_y, bubble_height, false, 771 kMaxBubbleFraction, kBubblePadding, 772 kItemPadding, ev_bubble_view_); 773 } else if (!origin_chip_view_->visible()) { 774 leading_decorations.AddDecoration( 775 vertical_edge_thickness(), location_height, 776 location_icon_view_); 777 } 778 779 if (star_view_->visible()) { 780 trailing_decorations.AddDecoration( 781 vertical_edge_thickness(), location_height, star_view_); 782 } 783 if (add_to_app_launcher_view_->visible()) { 784 trailing_decorations.AddDecoration( 785 vertical_edge_thickness(), location_height, add_to_app_launcher_view_); 786 } 787 if (translate_icon_view_->visible()) { 788 trailing_decorations.AddDecoration( 789 vertical_edge_thickness(), location_height, translate_icon_view_); 790 } 791 if (open_pdf_in_reader_view_->visible()) { 792 trailing_decorations.AddDecoration( 793 vertical_edge_thickness(), location_height, open_pdf_in_reader_view_); 794 } 795 if (manage_passwords_icon_view_->visible()) { 796 trailing_decorations.AddDecoration(vertical_edge_thickness(), 797 location_height, 798 manage_passwords_icon_view_); 799 } 800 for (PageActionViews::const_iterator i(page_action_views_.begin()); 801 i != page_action_views_.end(); ++i) { 802 if ((*i)->visible()) { 803 trailing_decorations.AddDecoration( 804 vertical_edge_thickness(), location_height, (*i)); 805 } 806 } 807 if (zoom_view_->visible()) { 808 trailing_decorations.AddDecoration(vertical_edge_thickness(), 809 location_height, zoom_view_); 810 } 811 for (ContentSettingViews::const_reverse_iterator i( 812 content_setting_views_.rbegin()); i != content_setting_views_.rend(); 813 ++i) { 814 if ((*i)->visible()) { 815 trailing_decorations.AddDecoration( 816 bubble_location_y, bubble_height, false, 0, kItemPadding, 817 kItemPadding, (*i)); 818 } 819 } 820 if (generated_credit_card_view_->visible()) { 821 trailing_decorations.AddDecoration(vertical_edge_thickness(), 822 location_height, 823 generated_credit_card_view_); 824 } 825 if (mic_search_view_->visible()) { 826 trailing_decorations.AddDecoration(vertical_edge_thickness(), 827 location_height, mic_search_view_); 828 } 829 // Because IMEs may eat the tab key, we don't show "press tab to search" while 830 // IME composition is in progress. 831 if (!keyword.empty() && omnibox_view_->model()->is_keyword_hint() && 832 !omnibox_view_->IsImeComposing()) { 833 trailing_decorations.AddDecoration(vertical_edge_thickness(), 834 location_height, true, 0, kItemPadding, 835 kItemPadding, keyword_hint_view_); 836 if (keyword_hint_view_->keyword() != keyword) 837 keyword_hint_view_->SetKeyword(keyword); 838 } 839 840 // Perform layout. 841 const int horizontal_edge_thickness = GetHorizontalEdgeThickness(); 842 int full_width = width() - horizontal_edge_thickness - origin_chip_width; 843 844 const gfx::Size search_button_size(search_button_->GetPreferredSize()); 845 const int search_button_reserved_width = 846 search_button_size.width() + kSearchButtonInset; 847 full_width -= search_button_->visible() ? 848 search_button_reserved_width : horizontal_edge_thickness; 849 int entry_width = full_width; 850 leading_decorations.LayoutPass1(&entry_width); 851 trailing_decorations.LayoutPass1(&entry_width); 852 leading_decorations.LayoutPass2(&entry_width); 853 trailing_decorations.LayoutPass2(&entry_width); 854 855 int location_needed_width = omnibox_view_->GetTextWidth(); 856 int available_width = entry_width - location_needed_width; 857 // The bounds must be wide enough for all the decorations to fit. 858 gfx::Rect location_bounds( 859 origin_chip_width + horizontal_edge_thickness, vertical_edge_thickness(), 860 std::max(full_width, full_width - entry_width), location_height); 861 leading_decorations.LayoutPass3(&location_bounds, &available_width); 862 trailing_decorations.LayoutPass3(&location_bounds, &available_width); 863 864 // Calculate the animation parameters (see comments on these members in the 865 // header). We have to do this in Layout, after |origin_chip_view_| is laid 866 // out, because that may affect the host label offset in the origin chip. 867 const base::string16& chip_text(origin_chip_view_->host_label_text()); 868 // If the chip is clicked, the omnibox text will become the toolbar model's 869 // formatted URL. We can't ask the omnibox for its current text, because 870 // while the chip is visible the current text is empty. 871 size_t prefix_end = 0; 872 const base::string16& omnibox_text( 873 GetToolbarModel()->GetFormattedURL(&prefix_end)); 874 // Do a case-insensitive search to better match cases like 875 // "Settings" <-> "chrome://settings". Skip any pre-hostname text. 876 size_t chip_text_offset = std::search( 877 omnibox_text.begin() + prefix_end, omnibox_text.end(), 878 chip_text.begin(), chip_text.end(), 879 base::CaseInsensitiveCompare<base::char16>()) - omnibox_text.begin(); 880 // If we couldn't find the chip text, try checking whether the omnibox text 881 // starts with it, as is true for e.g. file: URLs. 882 if ((chip_text_offset >= omnibox_text.length()) && 883 StartsWith(omnibox_text, chip_text, true)) 884 chip_text_offset = 0; 885 const gfx::FontList& font_list = omnibox_view_->GetFontList(); 886 const int chip_text_width = gfx::GetStringWidth(chip_text, font_list); 887 const int old_starting_offset = starting_omnibox_offset_; 888 const int old_starting_leading_inset = starting_omnibox_leading_inset_; 889 const int old_ending_width = ending_omnibox_width_; 890 starting_omnibox_offset_ = current_omnibox_offset_ = 0; 891 starting_omnibox_leading_inset_ = current_omnibox_leading_inset_ = 0; 892 ending_omnibox_width_ = gfx::GetStringWidth(omnibox_text, font_list); 893 if (chip_text_offset < omnibox_text.length()) { 894 if (base::i18n::IsRTL()) 895 chip_text_offset += chip_text.length(); 896 base::string16 extra_omnibox_text(base::i18n::IsRTL() ? 897 omnibox_text.substr(chip_text_offset) : 898 omnibox_text.substr(0, chip_text_offset)); 899 starting_omnibox_leading_inset_ = 900 gfx::GetStringWidth(extra_omnibox_text, font_list); 901 starting_omnibox_offset_ = origin_chip_view_->HostLabelOffset() - 902 starting_omnibox_leading_inset_; 903 current_omnibox_width_ = chip_text_width; 904 } else { 905 // If the chip text wasn't found in the omnibox text, then instead of 906 // starting the show animation clipped to the "hostname", we'll start with 907 // the entire omnibox text visible, clipped to the remaining chip width, and 908 // only animate any necessary expansion of that width, without moving the 909 // omnibox bounds. 910 current_omnibox_width_ = origin_chip_view_->WidthFromStartOfLabels(); 911 } 912 913 // End the animations immediately if the parameters have changed. 914 if ((starting_omnibox_offset_ != old_starting_offset) || 915 (starting_omnibox_leading_inset_ != old_starting_leading_inset) || 916 (ending_omnibox_width_ != old_ending_width)) 917 EndOriginChipAnimations(true); 918 919 // Also end the animations immediately if there's nothing to animate (but do 920 // allow the chip to fade back in). 921 const ui::NativeTheme* native_theme = GetNativeTheme(); 922 const SkColor ending_selection_text_color = native_theme->GetSystemColor( 923 ui::NativeTheme::kColorId_TextfieldSelectionColor); 924 const SkColor ending_selection_background_color = 925 native_theme->GetSystemColor( 926 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused); 927 if ((starting_omnibox_offset_ == 0) && 928 (starting_omnibox_leading_inset_ == 0) && 929 (ending_omnibox_width_ == chip_text_width) && 930 (hide_url_animation_->is_animating() || 931 ((ending_selection_text_color == 932 origin_chip_view_->pressed_text_color()) && 933 (ending_selection_background_color == 934 origin_chip_view_->pressed_background_color())))) 935 EndOriginChipAnimations(false); 936 937 if (show_url_animation_->is_animating()) { 938 omnibox_view_->SetSelectionTextColor(gfx::Tween::ColorValueBetween( 939 show_url_animation_->GetCurrentValue(), 940 origin_chip_view_->pressed_text_color(), 941 ending_selection_text_color)); 942 omnibox_view_->SetSelectionBackgroundColor(gfx::Tween::ColorValueBetween( 943 show_url_animation_->GetCurrentValue(), 944 origin_chip_view_->pressed_background_color(), 945 ending_selection_background_color)); 946 current_omnibox_offset_ = 947 show_url_animation_->CurrentValueBetween(starting_omnibox_offset_, 0); 948 current_omnibox_leading_inset_ = show_url_animation_->CurrentValueBetween( 949 starting_omnibox_leading_inset_, 0); 950 current_omnibox_width_ = show_url_animation_->CurrentValueBetween( 951 chip_text_width, ending_omnibox_width_); 952 } else if (hide_url_animation_->is_animating()) { 953 current_omnibox_offset_ = 954 hide_url_animation_->CurrentValueBetween(0, starting_omnibox_offset_); 955 current_omnibox_leading_inset_ = hide_url_animation_->CurrentValueBetween( 956 0, starting_omnibox_leading_inset_); 957 current_omnibox_width_ = hide_url_animation_->CurrentValueBetween( 958 ending_omnibox_width_, chip_text_width); 959 } 960 // Contract |available_width| as necessary, but never expand it. This way, 961 // we'll never draw suggested text at first and then have it disappear 962 // midway through the animation. 963 if (current_omnibox_offset_ > 0) 964 available_width -= current_omnibox_offset_; 965 location_bounds.Inset(current_omnibox_offset_, 0, 0, 0); 966 967 // Layout out the suggested text view right aligned to the location 968 // entry. Only show the suggested text if we can fit the text from one 969 // character before the end of the selection to the end of the text and the 970 // suggested text. If we can't it means either the suggested text is too big, 971 // or the user has scrolled. 972 973 // TODO(sky): We could potentially adjust this to take into account suggested 974 // text to force using minimum size if necessary, but currently the chance of 975 // showing keyword hints and suggested text is minimal and we're not confident 976 // this is the right approach for suggested text. 977 978 int omnibox_view_margin = 0; 979 if (suggested_text_view_->visible()) { 980 // We do not display the suggested text when it contains a mix of RTL and 981 // LTR characters since this could mean the suggestion should be displayed 982 // in the middle of the string. 983 base::i18n::TextDirection text_direction = 984 base::i18n::GetStringDirection(omnibox_view_->GetText()); 985 if (text_direction != 986 base::i18n::GetStringDirection(suggested_text_view_->text())) 987 text_direction = base::i18n::UNKNOWN_DIRECTION; 988 989 // TODO(sky): need to layout when the user changes caret position. 990 gfx::Size suggested_text_size(suggested_text_view_->GetPreferredSize()); 991 if (suggested_text_size.width() > available_width || 992 text_direction == base::i18n::UNKNOWN_DIRECTION) { 993 // Hide the suggested text if the user has scrolled or we can't fit all 994 // the suggested text, or we have a mix of RTL and LTR characters. 995 suggested_text_view_->SetBounds(0, 0, 0, 0); 996 } else { 997 location_needed_width = 998 std::min(location_needed_width, 999 location_bounds.width() - suggested_text_size.width()); 1000 gfx::Rect suggested_text_bounds(location_bounds.x(), location_bounds.y(), 1001 suggested_text_size.width(), 1002 location_bounds.height()); 1003 // TODO(sky): figure out why this needs the -1. 1004 suggested_text_bounds.Offset(location_needed_width - 1, 0); 1005 1006 // We reverse the order of the location entry and suggested text if: 1007 // - Chrome is RTL but the text is fully LTR, or 1008 // - Chrome is LTR but the text is fully RTL. 1009 // This ensures the suggested text is correctly displayed to the right 1010 // (or left) of the user text. 1011 if (text_direction == (base::i18n::IsRTL() ? 1012 base::i18n::LEFT_TO_RIGHT : base::i18n::RIGHT_TO_LEFT)) { 1013 // TODO(sky): Figure out why we need the +1. 1014 suggested_text_bounds.set_x(location_bounds.x() + 1); 1015 // Use a margin to prevent omnibox text from overlapping suggest text. 1016 omnibox_view_margin = suggested_text_bounds.width(); 1017 } 1018 suggested_text_view_->SetBoundsRect(suggested_text_bounds); 1019 } 1020 } 1021 1022 const gfx::Insets insets = omnibox_view_->GetInsets(); 1023 omnibox_view_->SetBorder(views::Border::CreateEmptyBorder( 1024 insets.top(), insets.left(), insets.bottom(), omnibox_view_margin)); 1025 1026 // Layout |ime_inline_autocomplete_view_| next to the user input. 1027 if (ime_inline_autocomplete_view_->visible()) { 1028 int width = 1029 gfx::GetStringWidth(ime_inline_autocomplete_view_->text(), 1030 ime_inline_autocomplete_view_->font_list()) + 1031 ime_inline_autocomplete_view_->GetInsets().width(); 1032 // All the target languages (IMEs) are LTR, and we do not need to support 1033 // RTL so far. In other words, no testable RTL environment so far. 1034 int x = location_needed_width; 1035 if (width > entry_width) 1036 x = 0; 1037 else if (location_needed_width + width > entry_width) 1038 x = entry_width - width; 1039 location_bounds.set_width(x); 1040 ime_inline_autocomplete_view_->SetBounds( 1041 location_bounds.right(), location_bounds.y(), 1042 std::min(width, entry_width), location_bounds.height()); 1043 } 1044 1045 omnibox_view_->SetBoundsRect(location_bounds); 1046 1047 search_button_->SetBoundsRect(gfx::Rect( 1048 gfx::Point(width() - search_button_reserved_width, 0), 1049 search_button_size)); 1050} 1051 1052//////////////////////////////////////////////////////////////////////////////// 1053// LocationBarView, public OmniboxEditController implementation: 1054 1055void LocationBarView::Update(const WebContents* contents) { 1056 mic_search_view_->SetVisible( 1057 !GetToolbarModel()->input_in_progress() && browser_ && 1058 browser_->search_model()->voice_search_supported()); 1059 RefreshContentSettingViews(); 1060 generated_credit_card_view_->Update(); 1061 ZoomBubbleView::CloseBubble(); 1062 RefreshZoomView(); 1063 RefreshPageActionViews(); 1064 RefreshTranslateIcon(); 1065 RefreshManagePasswordsIconView(); 1066 content::WebContents* web_contents_for_sub_views = 1067 GetToolbarModel()->input_in_progress() ? NULL : GetWebContents(); 1068 open_pdf_in_reader_view_->Update(web_contents_for_sub_views); 1069 add_to_app_launcher_view_->Update(web_contents_for_sub_views); 1070 1071 if (star_view_) { 1072 star_view_->SetVisible( 1073 browser_defaults::bookmarks_enabled && !is_popup_mode_ && 1074 !GetToolbarModel()->input_in_progress() && 1075 edit_bookmarks_enabled_.GetValue() && 1076 !IsBookmarkStarHiddenByExtension()); 1077 } 1078 1079 if (contents) 1080 omnibox_view_->OnTabChanged(contents); 1081 else 1082 omnibox_view_->Update(); 1083 1084 OnChanged(); // NOTE: Calls Layout(). 1085} 1086 1087void LocationBarView::ShowURL() { 1088 // Start the animation before calling ShowURL(), since the latter eventually 1089 // calls back to Layout(), and if the animation is not marked as "running", 1090 // we'll draw the omnibox in its final position briefly until the first 1091 // animation callback reaches us. 1092 if (chrome::ShouldDisplayOriginChip()) { 1093 // If we're currently hiding, reverse the hide by swapping to the show 1094 // animation, offset so that the text is in the same position. 1095 if (hide_url_animation_->is_animating()) { 1096 const double show_value = GetValueForAnimation(false); 1097 hide_url_animation_->Reset(); 1098 show_url_animation_->Show(); 1099 // This must be done after calling Show() and is not equivalent to 1100 // calling Reset(n) before Show(); Reset() would have caused the entire 1101 // animation curve (and time) to run between this value and the final 1102 // value, whereas Show() + SetCurrentValue() skips the animation forward 1103 // to the supplied value. 1104 show_url_animation_->SetCurrentValue(show_value); 1105 } else { 1106 show_url_animation_->Show(); 1107 } 1108 } 1109 omnibox_view_->ShowURL(); 1110} 1111 1112void LocationBarView::EndOriginChipAnimations(bool cancel_fade) { 1113 show_url_animation_->End(); 1114 hide_url_animation_->End(); 1115 if (cancel_fade) 1116 origin_chip_view_->CancelFade(); 1117} 1118 1119ToolbarModel* LocationBarView::GetToolbarModel() { 1120 return delegate_->GetToolbarModel(); 1121} 1122 1123WebContents* LocationBarView::GetWebContents() { 1124 return delegate_->GetWebContents(); 1125} 1126 1127//////////////////////////////////////////////////////////////////////////////// 1128// LocationBarView, private: 1129 1130// static 1131int LocationBarView::IncrementalMinimumWidth(views::View* view) { 1132 return view->visible() ? (kItemPadding + view->GetMinimumSize().width()) : 0; 1133} 1134 1135int LocationBarView::GetHorizontalEdgeThickness() const { 1136 // In maximized popup mode, there isn't any edge. 1137 return (is_popup_mode_ && browser_ && browser_->window() && 1138 browser_->window()->IsMaximized()) ? 0 : vertical_edge_thickness(); 1139} 1140 1141bool LocationBarView::RefreshContentSettingViews() { 1142 bool visibility_changed = false; 1143 for (ContentSettingViews::const_iterator i(content_setting_views_.begin()); 1144 i != content_setting_views_.end(); ++i) { 1145 const bool was_visible = (*i)->visible(); 1146 (*i)->Update(GetToolbarModel()->input_in_progress() ? 1147 NULL : GetWebContents()); 1148 if (was_visible != (*i)->visible()) 1149 visibility_changed = true; 1150 } 1151 return visibility_changed; 1152} 1153 1154void LocationBarView::DeletePageActionViews() { 1155 for (PageActionViews::const_iterator i(page_action_views_.begin()); 1156 i != page_action_views_.end(); ++i) 1157 RemoveChildView(*i); 1158 STLDeleteElements(&page_action_views_); 1159} 1160 1161bool LocationBarView::RefreshPageActionViews() { 1162 if (is_popup_mode_) 1163 return false; 1164 1165 bool changed = false; 1166 1167 // Remember the previous visibility of the page actions so that we can 1168 // notify when this changes. 1169 std::map<ExtensionAction*, bool> old_visibility; 1170 for (PageActionViews::const_iterator i(page_action_views_.begin()); 1171 i != page_action_views_.end(); ++i) { 1172 old_visibility[(*i)->image_view()->page_action()] = (*i)->visible(); 1173 } 1174 1175 PageActions new_page_actions; 1176 1177 WebContents* web_contents = GetWebContents(); 1178 if (web_contents) { 1179 extensions::TabHelper* extensions_tab_helper = 1180 extensions::TabHelper::FromWebContents(web_contents); 1181 extensions::LocationBarController* controller = 1182 extensions_tab_helper->location_bar_controller(); 1183 new_page_actions = controller->GetCurrentActions(); 1184 } 1185 1186 // On startup we sometimes haven't loaded any extensions. This makes sure 1187 // we catch up when the extensions (and any page actions) load. 1188 if (page_actions_ != new_page_actions) { 1189 changed = true; 1190 1191 page_actions_.swap(new_page_actions); 1192 DeletePageActionViews(); // Delete the old views (if any). 1193 1194 // Create the page action views. 1195 for (PageActions::const_iterator i = page_actions_.begin(); 1196 i != page_actions_.end(); ++i) { 1197 PageActionWithBadgeView* page_action_view = new PageActionWithBadgeView( 1198 delegate_->CreatePageActionImageView(this, *i)); 1199 page_action_view->SetVisible(false); 1200 page_action_views_.push_back(page_action_view); 1201 } 1202 1203 // Move rightmost extensions to the start. 1204 std::stable_partition( 1205 page_action_views_.begin(), 1206 page_action_views_.end(), 1207 IsPageActionViewRightAligned( 1208 extensions::ExtensionSystem::Get(profile())->extension_service())); 1209 1210 View* right_anchor = open_pdf_in_reader_view_; 1211 if (!right_anchor) 1212 right_anchor = star_view_; 1213 DCHECK(right_anchor); 1214 1215 // |page_action_views_| are ordered right-to-left. Add them as children in 1216 // reverse order so the logical order and visual order match for 1217 // accessibility purposes. 1218 for (PageActionViews::reverse_iterator i = page_action_views_.rbegin(); 1219 i != page_action_views_.rend(); ++i) 1220 AddChildViewAt(*i, GetIndexOf(right_anchor)); 1221 } 1222 1223 if (!page_action_views_.empty() && web_contents) { 1224 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); 1225 GURL url = browser->tab_strip_model()->GetActiveWebContents()->GetURL(); 1226 1227 for (PageActionViews::const_iterator i(page_action_views_.begin()); 1228 i != page_action_views_.end(); ++i) { 1229 (*i)->UpdateVisibility( 1230 GetToolbarModel()->input_in_progress() ? NULL : web_contents, url); 1231 1232 // Check if the visibility of the action changed and notify if it did. 1233 ExtensionAction* action = (*i)->image_view()->page_action(); 1234 if (old_visibility.find(action) == old_visibility.end() || 1235 old_visibility[action] != (*i)->visible()) { 1236 changed = true; 1237 content::NotificationService::current()->Notify( 1238 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, 1239 content::Source<ExtensionAction>(action), 1240 content::Details<WebContents>(web_contents)); 1241 } 1242 } 1243 } 1244 return changed; 1245} 1246 1247bool LocationBarView::RefreshZoomView() { 1248 DCHECK(zoom_view_); 1249 WebContents* web_contents = GetWebContents(); 1250 if (!web_contents) 1251 return false; 1252 const bool was_visible = zoom_view_->visible(); 1253 zoom_view_->Update(ZoomController::FromWebContents(web_contents)); 1254 return was_visible != zoom_view_->visible(); 1255} 1256 1257void LocationBarView::RefreshTranslateIcon() { 1258 if (!TranslateService::IsTranslateBubbleEnabled()) 1259 return; 1260 1261 WebContents* web_contents = GetWebContents(); 1262 if (!web_contents) 1263 return; 1264 LanguageState& language_state = 1265 ChromeTranslateClient::FromWebContents(web_contents)->GetLanguageState(); 1266 bool enabled = language_state.translate_enabled(); 1267 command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE, enabled); 1268 translate_icon_view_->SetVisible(enabled); 1269 translate_icon_view_->SetToggled(language_state.IsPageTranslated()); 1270} 1271 1272bool LocationBarView::RefreshManagePasswordsIconView() { 1273 DCHECK(manage_passwords_icon_view_); 1274 WebContents* web_contents = GetWebContents(); 1275 if (!web_contents) 1276 return false; 1277 const bool was_visible = manage_passwords_icon_view_->visible(); 1278 ManagePasswordsUIController::FromWebContents( 1279 web_contents)->UpdateIconAndBubbleState(manage_passwords_icon_view_); 1280 return was_visible != manage_passwords_icon_view_->visible(); 1281} 1282 1283void LocationBarView::ShowFirstRunBubbleInternal() { 1284 // First run bubble doesn't make sense for Chrome OS. 1285#if !defined(OS_CHROMEOS) 1286 WebContents* web_contents = delegate_->GetWebContents(); 1287 if (!web_contents) 1288 return; 1289 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); 1290 if (browser) 1291 FirstRunBubble::ShowBubble(browser, location_icon_view_); 1292#endif 1293} 1294 1295void LocationBarView::AccessibilitySetValue(const base::string16& new_value) { 1296 omnibox_view_->SetUserText(new_value, new_value, true); 1297} 1298 1299bool LocationBarView::HasValidSuggestText() const { 1300 return suggested_text_view_->visible() && 1301 !suggested_text_view_->size().IsEmpty(); 1302} 1303 1304bool LocationBarView::ShouldShowKeywordBubble() const { 1305 return !omnibox_view_->model()->keyword().empty() && 1306 !omnibox_view_->model()->is_keyword_hint(); 1307} 1308 1309bool LocationBarView::ShouldShowEVBubble() const { 1310 return !chrome::ShouldDisplayOriginChip() && 1311 (GetToolbarModel()->GetSecurityLevel(false) == ToolbarModel::EV_SECURE); 1312} 1313 1314double LocationBarView::GetValueForAnimation(bool hide) const { 1315 int calculated_offset; 1316 const gfx::Tween::Type tween_type = hide ? kHideTweenType : kShowTweenType; 1317 int start_offset = starting_omnibox_offset_, end_offset = 0; 1318 if (hide) 1319 std::swap(start_offset, end_offset); 1320 const int desired_offset = abs(current_omnibox_offset_); 1321 // Binary-search the value space (0 <= value <= 1) to find the appropriate 1322 // position. We only bother to iterate to within 1/64 of the desired value, 1323 // because the longer of the two animations will only run for twelve frames 1324 // anyway (200 ms * 60 Hz), so at this point we'll have a maximum error of 1325 // less than a fifth of an animation frame, which the user isn't going to 1326 // notice. 1327 // 1328 // We have to use this method because Tween::CalculateValue() is not 1329 // necessarily easily invertible. Luckily, this only runs when the user 1330 // reverses the animation (rare), and the limit on how many iterations we'll 1331 // do ensures the cost is unnoticeable. 1332 double value = 0.5; 1333 double step = value / 2; 1334 do { 1335 calculated_offset = abs(gfx::Tween::IntValueBetween( 1336 gfx::Tween::CalculateValue(tween_type, value), start_offset, 1337 end_offset)); 1338 if (calculated_offset < desired_offset) 1339 value += step; 1340 else if (calculated_offset > desired_offset) 1341 value -= step; 1342 step /= 2; 1343 } while ((calculated_offset != desired_offset) && (step >= (1.0 / 64))); 1344 return value; 1345} 1346 1347void LocationBarView::ResetShowAnimationAndColors() { 1348 show_url_animation_->Reset(); 1349 omnibox_view_->UseDefaultSelectionTextColor(); 1350 omnibox_view_->UseDefaultSelectionBackgroundColor(); 1351} 1352 1353//////////////////////////////////////////////////////////////////////////////// 1354// LocationBarView, private LocationBar implementation: 1355 1356void LocationBarView::ShowFirstRunBubble() { 1357 // Wait until search engines have loaded to show the first run bubble. 1358 TemplateURLService* url_service = 1359 TemplateURLServiceFactory::GetForProfile(profile()); 1360 if (!url_service->loaded()) { 1361 template_url_service_ = url_service; 1362 template_url_service_->AddObserver(this); 1363 template_url_service_->Load(); 1364 return; 1365 } 1366 ShowFirstRunBubbleInternal(); 1367} 1368 1369GURL LocationBarView::GetDestinationURL() const { 1370 return destination_url(); 1371} 1372 1373WindowOpenDisposition LocationBarView::GetWindowOpenDisposition() const { 1374 return disposition(); 1375} 1376 1377content::PageTransition LocationBarView::GetPageTransition() const { 1378 return transition(); 1379} 1380 1381void LocationBarView::AcceptInput() { 1382 omnibox_view_->model()->AcceptInput(CURRENT_TAB, false); 1383} 1384 1385void LocationBarView::FocusSearch() { 1386 omnibox_view_->SetFocus(); 1387 omnibox_view_->SetForcedQuery(); 1388} 1389 1390void LocationBarView::UpdateContentSettingsIcons() { 1391 if (RefreshContentSettingViews()) { 1392 Layout(); 1393 SchedulePaint(); 1394 } 1395} 1396 1397void LocationBarView::UpdateManagePasswordsIconAndBubble() { 1398 if (RefreshManagePasswordsIconView()) { 1399 Layout(); 1400 SchedulePaint(); 1401 } 1402} 1403 1404void LocationBarView::UpdatePageActions() { 1405 size_t count_before = page_action_views_.size(); 1406 bool changed = RefreshPageActionViews(); 1407 if (page_action_views_.size() != count_before) { 1408 content::NotificationService::current()->Notify( 1409 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED, 1410 content::Source<LocationBar>(this), 1411 content::NotificationService::NoDetails()); 1412 } 1413 1414 if (changed) { 1415 Layout(); 1416 SchedulePaint(); 1417 } 1418} 1419 1420void LocationBarView::InvalidatePageActions() { 1421 size_t count_before = page_action_views_.size(); 1422 DeletePageActionViews(); 1423 if (page_action_views_.size() != count_before) { 1424 content::NotificationService::current()->Notify( 1425 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED, 1426 content::Source<LocationBar>(this), 1427 content::NotificationService::NoDetails()); 1428 } 1429} 1430 1431void LocationBarView::UpdateOpenPDFInReaderPrompt() { 1432 open_pdf_in_reader_view_->Update( 1433 GetToolbarModel()->input_in_progress() ? NULL : GetWebContents()); 1434 Layout(); 1435 SchedulePaint(); 1436} 1437 1438void LocationBarView::UpdateGeneratedCreditCardView() { 1439 generated_credit_card_view_->Update(); 1440 Layout(); 1441 SchedulePaint(); 1442} 1443 1444void LocationBarView::SaveStateToContents(WebContents* contents) { 1445 // If we're about to switch tabs, complete any current animations, so that if 1446 // the user is in the midst of hiding the URL, when he returns to this tab, 1447 // the URL will be hidden rather than shown. 1448 // NOTE: This must be called before SaveStateToTab(). 1449 EndOriginChipAnimations(true); 1450 omnibox_view_->SaveStateToTab(contents); 1451} 1452 1453const OmniboxView* LocationBarView::GetOmniboxView() const { 1454 return omnibox_view_; 1455} 1456 1457LocationBarTesting* LocationBarView::GetLocationBarForTesting() { 1458 return this; 1459} 1460 1461//////////////////////////////////////////////////////////////////////////////// 1462// LocationBarView, private LocationBarTesting implementation: 1463 1464int LocationBarView::PageActionCount() { 1465 return page_action_views_.size(); 1466} 1467 1468int LocationBarView::PageActionVisibleCount() { 1469 int result = 0; 1470 for (size_t i = 0; i < page_action_views_.size(); i++) { 1471 if (page_action_views_[i]->visible()) 1472 ++result; 1473 } 1474 return result; 1475} 1476 1477ExtensionAction* LocationBarView::GetPageAction(size_t index) { 1478 if (index < page_action_views_.size()) 1479 return page_action_views_[index]->image_view()->page_action(); 1480 1481 NOTREACHED(); 1482 return NULL; 1483} 1484 1485ExtensionAction* LocationBarView::GetVisiblePageAction(size_t index) { 1486 size_t current = 0; 1487 for (size_t i = 0; i < page_action_views_.size(); ++i) { 1488 if (page_action_views_[i]->visible()) { 1489 if (current == index) 1490 return page_action_views_[i]->image_view()->page_action(); 1491 1492 ++current; 1493 } 1494 } 1495 1496 NOTREACHED(); 1497 return NULL; 1498} 1499 1500void LocationBarView::TestPageActionPressed(size_t index) { 1501 size_t current = 0; 1502 for (size_t i = 0; i < page_action_views_.size(); ++i) { 1503 if (page_action_views_[i]->visible()) { 1504 if (current == index) { 1505 page_action_views_[i]->image_view()->ExecuteAction( 1506 ExtensionPopup::SHOW); 1507 return; 1508 } 1509 ++current; 1510 } 1511 } 1512 1513 NOTREACHED(); 1514} 1515 1516bool LocationBarView::GetBookmarkStarVisibility() { 1517 DCHECK(star_view_); 1518 return star_view_->visible(); 1519} 1520 1521//////////////////////////////////////////////////////////////////////////////// 1522// LocationBarView, private views::View implementation: 1523 1524const char* LocationBarView::GetClassName() const { 1525 return kViewClassName; 1526} 1527 1528void LocationBarView::OnBoundsChanged(const gfx::Rect& previous_bounds) { 1529 InstantServiceFactory::GetForProfile(profile())->OnOmniboxStartMarginChanged( 1530 bounds().x()); 1531 1532 OmniboxPopupView* popup = omnibox_view_->model()->popup_model()->view(); 1533 if (popup->IsOpen()) 1534 popup->UpdatePopupAppearance(); 1535} 1536 1537void LocationBarView::OnFocus() { 1538 // Explicitly focus the omnibox so a focus ring will be displayed around it on 1539 // Windows. 1540 omnibox_view_->SetFocus(); 1541} 1542 1543void LocationBarView::OnPaint(gfx::Canvas* canvas) { 1544 View::OnPaint(canvas); 1545 1546 // Fill the location bar background color behind the border. Parts of the 1547 // border images are meant to rest atop the toolbar background and parts atop 1548 // the omnibox background, so we can't just blindly fill our entire bounds. 1549 gfx::Rect bounds(GetContentsBounds()); 1550 bounds.Inset(GetHorizontalEdgeThickness(), vertical_edge_thickness()); 1551 SkColor color(GetColor(ToolbarModel::NONE, BACKGROUND)); 1552 if (is_popup_mode_) { 1553 canvas->FillRect(bounds, color); 1554 } else { 1555 SkPaint paint; 1556 paint.setStyle(SkPaint::kFill_Style); 1557 paint.setColor(color); 1558 const int kBorderCornerRadius = 2; 1559 canvas->DrawRoundRect(bounds, kBorderCornerRadius, paint); 1560 } 1561 1562 // The border itself will be drawn in PaintChildren() since it includes an 1563 // inner shadow which should be drawn over the contents. 1564} 1565 1566void LocationBarView::PaintChildren(gfx::Canvas* canvas, 1567 const views::CullSet& cull_set) { 1568 // Paint all the children except for the omnibox itself, which may need to be 1569 // clipped if it's animating in, and the origin chip and the search button, 1570 // which will be painted after the border. 1571 for (int i = 0, count = child_count(); i < count; ++i) { 1572 views::View* child = child_at(i); 1573 if (!child->layer() && (child != omnibox_view_) && 1574 (child != origin_chip_view_) && (child != search_button_)) 1575 child->Paint(canvas, cull_set); 1576 } 1577 1578 { 1579 gfx::ScopedCanvas scoped_canvas(canvas); 1580 if (show_url_animation_->is_animating() || 1581 hide_url_animation_->is_animating()) { 1582 gfx::Rect clip_rect(omnibox_view_->bounds()); 1583 clip_rect.Inset(current_omnibox_leading_inset_, 0, 0, 0); 1584 clip_rect.set_width(current_omnibox_width_); 1585 clip_rect.set_x(GetMirroredXForRect(clip_rect)); 1586 canvas->ClipRect(clip_rect); 1587 } 1588 omnibox_view_->Paint(canvas, cull_set); 1589 } 1590 1591 // For non-InstantExtendedAPI cases, if necessary, show focus rect. As we need 1592 // the focus rect to appear on top of children we paint here rather than 1593 // OnPaint(). 1594 // Note: |Canvas::DrawFocusRect| paints a dashed rect with gray color. 1595 if (show_focus_rect_ && HasFocus()) 1596 canvas->DrawFocusRect(omnibox_view_->bounds()); 1597 1598 // Maximized popup windows don't draw the horizontal edges. We implement this 1599 // by simply expanding the paint area outside the view by the edge thickness. 1600 gfx::Rect border_rect(GetContentsBounds()); 1601 if (is_popup_mode_ && (GetHorizontalEdgeThickness() == 0)) 1602 border_rect.Inset(-kPopupEdgeThickness, 0); 1603 views::Painter::PaintPainterAt(canvas, border_painter_.get(), border_rect); 1604 1605 // The origin chip and the search button must be painted after the border so 1606 // that the border shadow is not drawn over them. 1607 origin_chip_view_->Paint(canvas, cull_set); 1608 search_button_->Paint(canvas, cull_set); 1609} 1610 1611//////////////////////////////////////////////////////////////////////////////// 1612// LocationBarView, private views::ButtonListener implementation: 1613 1614void LocationBarView::ButtonPressed(views::Button* sender, 1615 const ui::Event& event) { 1616 if (sender == mic_search_view_) { 1617 command_updater()->ExecuteCommand(IDC_TOGGLE_SPEECH_INPUT); 1618 return; 1619 } 1620 1621 DCHECK_EQ(search_button_, sender); 1622 // TODO(pkasting): When macourteau adds UMA stats for this, wire them up here. 1623 omnibox_view_->model()->AcceptInput( 1624 ui::DispositionFromEventFlags(event.flags()), false); 1625} 1626 1627//////////////////////////////////////////////////////////////////////////////// 1628// LocationBarView, private views::DragController implementation: 1629 1630void LocationBarView::WriteDragDataForView(views::View* sender, 1631 const gfx::Point& press_pt, 1632 OSExchangeData* data) { 1633 DCHECK_NE(GetDragOperationsForView(sender, press_pt), 1634 ui::DragDropTypes::DRAG_NONE); 1635 1636 WebContents* web_contents = GetWebContents(); 1637 FaviconTabHelper* favicon_tab_helper = 1638 FaviconTabHelper::FromWebContents(web_contents); 1639 gfx::ImageSkia favicon = favicon_tab_helper->GetFavicon().AsImageSkia(); 1640 button_drag_utils::SetURLAndDragImage(web_contents->GetURL(), 1641 web_contents->GetTitle(), 1642 favicon, 1643 NULL, 1644 data, 1645 sender->GetWidget()); 1646} 1647 1648int LocationBarView::GetDragOperationsForView(views::View* sender, 1649 const gfx::Point& p) { 1650 DCHECK((sender == location_icon_view_) || (sender == ev_bubble_view_) || 1651 (sender == origin_chip_view_)); 1652 WebContents* web_contents = delegate_->GetWebContents(); 1653 return (web_contents && web_contents->GetURL().is_valid() && 1654 (!GetOmniboxView()->IsEditingOrEmpty() || 1655 sender == origin_chip_view_)) ? 1656 (ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK) : 1657 ui::DragDropTypes::DRAG_NONE; 1658} 1659 1660bool LocationBarView::CanStartDragForView(View* sender, 1661 const gfx::Point& press_pt, 1662 const gfx::Point& p) { 1663 return true; 1664} 1665 1666//////////////////////////////////////////////////////////////////////////////// 1667// LocationBarView, private OmniboxEditController implementation: 1668 1669void LocationBarView::OnChanged() { 1670 int icon_id = omnibox_view_->GetIcon(); 1671 location_icon_view_->SetImage(GetThemeProvider()->GetImageSkiaNamed(icon_id)); 1672 location_icon_view_->ShowTooltip(!GetOmniboxView()->IsEditingOrEmpty()); 1673 1674 ToolbarModel* toolbar_model = GetToolbarModel(); 1675 chrome::DisplaySearchButtonConditions conditions = 1676 chrome::GetDisplaySearchButtonConditions(); 1677 bool meets_conditions = 1678 (conditions == chrome::DISPLAY_SEARCH_BUTTON_ALWAYS) || 1679 ((conditions != chrome::DISPLAY_SEARCH_BUTTON_NEVER) && 1680 (toolbar_model->WouldPerformSearchTermReplacement(true) || 1681 ((conditions == chrome::DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP) && 1682 toolbar_model->input_in_progress()))); 1683 search_button_->SetVisible(!is_popup_mode_ && meets_conditions); 1684 search_button_->UpdateIcon(icon_id == IDR_OMNIBOX_SEARCH); 1685 1686 origin_chip_view_->OnChanged(); 1687 1688 Layout(); 1689 SchedulePaint(); 1690} 1691 1692void LocationBarView::OnSetFocus() { 1693 GetFocusManager()->SetFocusedView(this); 1694} 1695 1696InstantController* LocationBarView::GetInstant() { 1697 return delegate_->GetInstant(); 1698} 1699 1700const ToolbarModel* LocationBarView::GetToolbarModel() const { 1701 return delegate_->GetToolbarModel(); 1702} 1703 1704void LocationBarView::HideURL() { 1705 DCHECK(chrome::ShouldDisplayOriginChip()); 1706 1707 // If we're currently showing, reverse the hide by swapping to the hide 1708 // animation, offset so that the text is in the same position. 1709 if (show_url_animation_->is_animating()) { 1710 const double hide_value = GetValueForAnimation(true); 1711 ResetShowAnimationAndColors(); 1712 hide_url_animation_->Show(); 1713 // This must be done after calling Show() and is not equivalent to Reset(n); 1714 // see comments in ShowURL(). 1715 hide_url_animation_->SetCurrentValue(hide_value); 1716 } else { 1717 hide_url_animation_->Show(); 1718 } 1719} 1720 1721//////////////////////////////////////////////////////////////////////////////// 1722// LocationBarView, private DropdownBarHostDelegate implementation: 1723 1724void LocationBarView::SetFocusAndSelection(bool select_all) { 1725 FocusLocation(select_all); 1726} 1727 1728void LocationBarView::SetAnimationOffset(int offset) { 1729 dropdown_animation_offset_ = offset; 1730} 1731 1732//////////////////////////////////////////////////////////////////////////////// 1733// LocationBarView, private gfx::AnimationDelegate implementation: 1734 1735void LocationBarView::AnimationProgressed(const gfx::Animation* animation) { 1736 DCHECK((animation == show_url_animation_.get()) || 1737 (animation == hide_url_animation_.get())); 1738 Layout(); 1739 SchedulePaint(); 1740} 1741 1742void LocationBarView::AnimationEnded(const gfx::Animation* animation) { 1743 if (animation == show_url_animation_.get()) { 1744 ResetShowAnimationAndColors(); 1745 Layout(); 1746 SchedulePaint(); 1747 } else { 1748 DCHECK(animation == hide_url_animation_.get()); 1749 hide_url_animation_->Reset(); 1750 origin_chip_view_->FadeIn(); 1751 omnibox_view_->HideURL(); // Calls OnChanged(), triggering layout. 1752 } 1753} 1754 1755//////////////////////////////////////////////////////////////////////////////// 1756// LocationBarView, private TemplateURLServiceObserver implementation: 1757 1758void LocationBarView::OnTemplateURLServiceChanged() { 1759 template_url_service_->RemoveObserver(this); 1760 template_url_service_ = NULL; 1761 // If the browser is no longer active, let's not show the info bubble, as this 1762 // would make the browser the active window again. 1763 if (omnibox_view_ && omnibox_view_->GetWidget()->IsActive()) 1764 ShowFirstRunBubble(); 1765} 1766 1767//////////////////////////////////////////////////////////////////////////////// 1768// LocationBarView, private content::NotificationObserver implementation: 1769 1770void LocationBarView::Observe(int type, 1771 const content::NotificationSource& source, 1772 const content::NotificationDetails& details) { 1773 switch (type) { 1774 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: 1775 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: 1776 Update(NULL); 1777 break; 1778 1779 default: 1780 NOTREACHED() << "Unexpected notification."; 1781 } 1782} 1783 1784//////////////////////////////////////////////////////////////////////////////// 1785// LocationBarView, private SearchModelObserver implementation: 1786 1787void LocationBarView::ModelChanged(const SearchModel::State& old_state, 1788 const SearchModel::State& new_state) { 1789 const bool visible = !GetToolbarModel()->input_in_progress() && 1790 new_state.voice_search_supported; 1791 if (mic_search_view_->visible() != visible) { 1792 mic_search_view_->SetVisible(visible); 1793 Layout(); 1794 } 1795} 1796 1797