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.
5 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
10 #include "base/i18n/rtl.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/stl_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/app/chrome_command_ids.h"
15 #include "chrome/browser/command_updater.h"
16 #include "chrome/browser/defaults.h"
17 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
18 #include "chrome/browser/extensions/extension_action.h"
19 #include "chrome/browser/extensions/extension_action_manager.h"
20 #include "chrome/browser/extensions/extension_util.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/content_setting_image_view.h"
43 #include "chrome/browser/ui/views/location_bar/ev_bubble_view.h"
44 #include "chrome/browser/ui/views/location_bar/generated_credit_card_view.h"
45 #include "chrome/browser/ui/views/location_bar/keyword_hint_view.h"
46 #include "chrome/browser/ui/views/location_bar/location_bar_layout.h"
47 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
48 #include "chrome/browser/ui/views/location_bar/open_pdf_in_reader_view.h"
49 #include "chrome/browser/ui/views/location_bar/origin_chip_view.h"
50 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
51 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
52 #include "chrome/browser/ui/views/location_bar/search_button.h"
53 #include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
54 #include "chrome/browser/ui/views/location_bar/star_view.h"
55 #include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
56 #include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
57 #include "chrome/browser/ui/views/location_bar/zoom_view.h"
58 #include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h"
59 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_view.h"
60 #include "chrome/browser/ui/views/translate/translate_bubble_view.h"
61 #include "chrome/common/pref_names.h"
62 #include "chrome/grit/generated_resources.h"
63 #include "components/search_engines/template_url.h"
64 #include "components/search_engines/template_url_service.h"
65 #include "components/translate/core/browser/language_state.h"
66 #include "components/ui/zoom/zoom_controller.h"
67 #include "content/public/browser/render_widget_host_view.h"
68 #include "content/public/browser/web_contents.h"
69 #include "extensions/browser/extension_registry.h"
70 #include "extensions/common/feature_switch.h"
71 #include "extensions/common/permissions/permissions_data.h"
72 #include "grit/components_scaled_resources.h"
73 #include "grit/theme_resources.h"
74 #include "ui/accessibility/ax_view_state.h"
75 #include "ui/base/dragdrop/drag_drop_types.h"
76 #include "ui/base/l10n/l10n_util.h"
77 #include "ui/base/resource/resource_bundle.h"
78 #include "ui/base/theme_provider.h"
79 #include "ui/events/event.h"
80 #include "ui/gfx/animation/slide_animation.h"
81 #include "ui/gfx/canvas.h"
82 #include "ui/gfx/color_utils.h"
83 #include "ui/gfx/image/image.h"
84 #include "ui/gfx/image/image_skia_operations.h"
85 #include "ui/gfx/scoped_canvas.h"
86 #include "ui/gfx/skia_util.h"
87 #include "ui/gfx/text_utils.h"
88 #include "ui/native_theme/native_theme.h"
89 #include "ui/views/background.h"
90 #include "ui/views/border.h"
91 #include "ui/views/button_drag_utils.h"
92 #include "ui/views/controls/button/image_button.h"
93 #include "ui/views/controls/label.h"
94 #include "ui/views/widget/widget.h"
96 #if !defined(OS_CHROMEOS)
97 #include "chrome/browser/ui/views/first_run_bubble.h"
100 using content::WebContents
;
105 const gfx::Tween::Type kShowTweenType
= gfx::Tween::LINEAR_OUT_SLOW_IN
;
106 const gfx::Tween::Type kHideTweenType
= gfx::Tween::FAST_OUT_LINEAR_IN
;
108 // The search button images are made to look as if they overlay the normal edge
109 // images, but to align things, the search button needs to be inset horizontally
111 const int kSearchButtonInset
= 1;
113 int GetEditLeadingInternalSpace() {
114 // The textfield has 1 px of whitespace before the text in the RTL case only.
115 return base::i18n::IsRTL() ? 1 : 0;
118 // Functor for moving BookmarkManagerPrivate page actions to the right via
120 class IsPageActionViewRightAligned
{
122 explicit IsPageActionViewRightAligned(
123 extensions::ExtensionRegistry
* extension_registry
)
124 : extension_registry_(extension_registry
) {}
126 bool operator()(PageActionWithBadgeView
* page_action_view
) {
127 return extension_registry_
->enabled_extensions().GetByID(
128 page_action_view
->image_view()->extension_action()->extension_id())->
130 HasAPIPermission(extensions::APIPermission::kBookmarkManagerPrivate
);
134 extensions::ExtensionRegistry
* extension_registry_
;
136 // NOTE: Can't DISALLOW_COPY_AND_ASSIGN as we pass this object by value to
137 // std::stable_partition().
143 // LocationBarView -----------------------------------------------------------
146 const int LocationBarView::kNormalEdgeThickness
= 2;
147 const int LocationBarView::kPopupEdgeThickness
= 1;
148 const int LocationBarView::kItemPadding
= 3;
149 const int LocationBarView::kIconInternalPadding
= 2;
150 const int LocationBarView::kBubblePadding
= 1;
151 const char LocationBarView::kViewClassName
[] = "LocationBarView";
153 LocationBarView::LocationBarView(Browser
* browser
,
155 CommandUpdater
* command_updater
,
158 : LocationBar(profile
),
159 OmniboxEditController(command_updater
),
163 origin_chip_view_(NULL
),
164 location_icon_view_(NULL
),
165 ev_bubble_view_(NULL
),
166 ime_inline_autocomplete_view_(NULL
),
167 selected_keyword_view_(NULL
),
168 suggested_text_view_(NULL
),
169 keyword_hint_view_(NULL
),
170 mic_search_view_(NULL
),
172 generated_credit_card_view_(NULL
),
173 open_pdf_in_reader_view_(NULL
),
174 manage_passwords_icon_view_(NULL
),
175 translate_icon_view_(NULL
),
177 search_button_(NULL
),
178 is_popup_mode_(is_popup_mode
),
179 show_focus_rect_(false),
180 template_url_service_(NULL
),
181 dropdown_animation_offset_(0),
182 starting_omnibox_offset_(0),
183 current_omnibox_offset_(0),
184 starting_omnibox_leading_inset_(0),
185 current_omnibox_leading_inset_(0),
186 current_omnibox_width_(0),
187 ending_omnibox_width_(0),
188 web_contents_null_at_last_refresh_(true) {
189 edit_bookmarks_enabled_
.Init(
190 bookmarks::prefs::kEditBookmarksEnabled
, profile
->GetPrefs(),
191 base::Bind(&LocationBarView::Update
, base::Unretained(this),
192 static_cast<content::WebContents
*>(NULL
)));
195 browser_
->search_model()->AddObserver(this);
198 LocationBarView::~LocationBarView() {
199 if (template_url_service_
)
200 template_url_service_
->RemoveObserver(this);
202 browser_
->search_model()->RemoveObserver(this);
205 ////////////////////////////////////////////////////////////////////////////////
206 // LocationBarView, public:
208 void LocationBarView::Init() {
209 // We need to be in a Widget, otherwise GetNativeTheme() may change and we're
210 // not prepared for that.
213 const int kOmniboxPopupBorderImages
[] =
214 IMAGE_GRID(IDR_OMNIBOX_POPUP_BORDER_AND_SHADOW
);
215 const int kOmniboxBorderImages
[] = IMAGE_GRID(IDR_TEXTFIELD
);
216 border_painter_
.reset(views::Painter::CreateImageGridPainter(
217 is_popup_mode_
? kOmniboxPopupBorderImages
: kOmniboxBorderImages
));
219 location_icon_view_
= new LocationIconView(this);
220 location_icon_view_
->set_drag_controller(this);
221 AddChildView(location_icon_view_
);
223 // Determine the main font.
224 gfx::FontList font_list
= ResourceBundle::GetSharedInstance().GetFontList(
225 ResourceBundle::BaseFont
);
226 const int current_font_size
= font_list
.GetFontSize();
227 const int desired_font_size
= browser_defaults::kOmniboxFontPixelSize
;
228 if (current_font_size
!= desired_font_size
) {
230 font_list
.DeriveWithSizeDelta(desired_font_size
- current_font_size
);
232 // Shrink large fonts to make them fit.
233 // TODO(pkasting): Stretch the location bar instead in this case.
234 const int location_height
= GetInternalHeight(true);
235 font_list
= font_list
.DeriveWithHeightUpperBound(location_height
);
237 // Determine the font for use inside the bubbles. The bubble background
238 // images have 1 px thick edges, which we don't want to overlap.
239 const int kBubbleInteriorVerticalPadding
= 1;
240 const int bubble_vertical_padding
=
241 (kBubblePadding
+ kBubbleInteriorVerticalPadding
) * 2;
242 const gfx::FontList
bubble_font_list(font_list
.DeriveWithHeightUpperBound(
243 location_height
- bubble_vertical_padding
));
245 const SkColor background_color
=
246 GetColor(ToolbarModel::NONE
, LocationBarView::BACKGROUND
);
247 ev_bubble_view_
= new EVBubbleView(
248 bubble_font_list
, GetColor(ToolbarModel::EV_SECURE
, SECURITY_TEXT
),
249 background_color
, this);
250 ev_bubble_view_
->set_drag_controller(this);
251 AddChildView(ev_bubble_view_
);
253 // Initialize the Omnibox view.
254 omnibox_view_
= new OmniboxViewViews(
255 this, profile(), command_updater(), is_popup_mode_
, this, font_list
);
256 omnibox_view_
->Init();
257 omnibox_view_
->SetFocusable(true);
258 AddChildView(omnibox_view_
);
260 // Initialize the inline autocomplete view which is visible only when IME is
261 // turned on. Use the same font with the omnibox and highlighted background.
262 ime_inline_autocomplete_view_
= new views::Label(base::string16(), font_list
);
263 ime_inline_autocomplete_view_
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
264 ime_inline_autocomplete_view_
->SetAutoColorReadabilityEnabled(false);
265 ime_inline_autocomplete_view_
->set_background(
266 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
267 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused
)));
268 ime_inline_autocomplete_view_
->SetEnabledColor(
269 GetNativeTheme()->GetSystemColor(
270 ui::NativeTheme::kColorId_TextfieldSelectionColor
));
271 ime_inline_autocomplete_view_
->SetVisible(false);
272 AddChildView(ime_inline_autocomplete_view_
);
274 origin_chip_view_
= new OriginChipView(this, profile(), font_list
);
275 origin_chip_view_
->SetFocusable(false);
276 origin_chip_view_
->set_drag_controller(this);
277 AddChildView(origin_chip_view_
);
279 const SkColor text_color
= GetColor(ToolbarModel::NONE
, TEXT
);
280 selected_keyword_view_
= new SelectedKeywordView(
281 bubble_font_list
, text_color
, background_color
, profile());
282 AddChildView(selected_keyword_view_
);
284 suggested_text_view_
= new views::Label(base::string16(), font_list
);
285 suggested_text_view_
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
286 suggested_text_view_
->SetAutoColorReadabilityEnabled(false);
287 suggested_text_view_
->SetEnabledColor(GetColor(
288 ToolbarModel::NONE
, LocationBarView::DEEMPHASIZED_TEXT
));
289 suggested_text_view_
->SetVisible(false);
290 AddChildView(suggested_text_view_
);
292 keyword_hint_view_
= new KeywordHintView(
293 profile(), font_list
,
294 GetColor(ToolbarModel::NONE
, LocationBarView::DEEMPHASIZED_TEXT
),
296 AddChildView(keyword_hint_view_
);
298 mic_search_view_
= new views::ImageButton(this);
299 mic_search_view_
->set_id(VIEW_ID_MIC_SEARCH_BUTTON
);
300 mic_search_view_
->SetAccessibilityFocusable(true);
301 mic_search_view_
->SetTooltipText(
302 l10n_util::GetStringUTF16(IDS_TOOLTIP_MIC_SEARCH
));
303 mic_search_view_
->SetImage(
304 views::Button::STATE_NORMAL
,
305 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
306 IDR_OMNIBOX_MIC_SEARCH
));
307 mic_search_view_
->SetImageAlignment(views::ImageButton::ALIGN_CENTER
,
308 views::ImageButton::ALIGN_MIDDLE
);
309 mic_search_view_
->SetVisible(false);
310 AddChildView(mic_search_view_
);
312 for (int i
= 0; i
< CONTENT_SETTINGS_NUM_TYPES
; ++i
) {
313 ContentSettingImageView
* content_blocked_view
=
314 new ContentSettingImageView(static_cast<ContentSettingsType
>(i
), this,
315 bubble_font_list
, text_color
,
317 content_setting_views_
.push_back(content_blocked_view
);
318 content_blocked_view
->SetVisible(false);
319 AddChildView(content_blocked_view
);
322 generated_credit_card_view_
= new GeneratedCreditCardView(delegate_
);
323 AddChildView(generated_credit_card_view_
);
325 zoom_view_
= new ZoomView(delegate_
);
326 AddChildView(zoom_view_
);
328 open_pdf_in_reader_view_
= new OpenPDFInReaderView();
329 AddChildView(open_pdf_in_reader_view_
);
331 manage_passwords_icon_view_
= new ManagePasswordsIconView(command_updater());
332 AddChildView(manage_passwords_icon_view_
);
334 translate_icon_view_
= new TranslateIconView(command_updater());
335 translate_icon_view_
->SetVisible(false);
336 AddChildView(translate_icon_view_
);
338 star_view_
= new StarView(command_updater(), browser_
);
339 star_view_
->SetVisible(false);
340 AddChildView(star_view_
);
342 search_button_
= new SearchButton(this);
343 search_button_
->SetVisible(false);
344 AddChildView(search_button_
);
346 show_url_animation_
.reset(new gfx::SlideAnimation(this));
347 show_url_animation_
->SetTweenType(kShowTweenType
);
348 show_url_animation_
->SetSlideDuration(200);
350 hide_url_animation_
.reset(new gfx::SlideAnimation(this));
351 hide_url_animation_
->SetTweenType(kHideTweenType
);
352 hide_url_animation_
->SetSlideDuration(175);
354 // Initialize the location entry. We do this to avoid a black flash which is
355 // visible when the location entry has just been initialized.
359 bool LocationBarView::IsInitialized() const {
360 return omnibox_view_
!= NULL
;
363 SkColor
LocationBarView::GetColor(ToolbarModel::SecurityLevel security_level
,
364 ColorKind kind
) const {
365 const ui::NativeTheme
* native_theme
= GetNativeTheme();
368 return native_theme
->GetSystemColor(
369 ui::NativeTheme::kColorId_TextfieldDefaultBackground
);
372 return native_theme
->GetSystemColor(
373 ui::NativeTheme::kColorId_TextfieldDefaultColor
);
376 return native_theme
->GetSystemColor(
377 ui::NativeTheme::kColorId_TextfieldSelectionColor
);
379 case DEEMPHASIZED_TEXT
:
380 return color_utils::AlphaBlend(
381 GetColor(security_level
, TEXT
),
382 GetColor(security_level
, BACKGROUND
),
385 case SECURITY_TEXT
: {
387 switch (security_level
) {
388 case ToolbarModel::EV_SECURE
:
389 case ToolbarModel::SECURE
:
390 color
= SkColorSetRGB(7, 149, 0);
393 case ToolbarModel::SECURITY_WARNING
:
394 case ToolbarModel::SECURITY_POLICY_WARNING
:
395 return GetColor(security_level
, DEEMPHASIZED_TEXT
);
398 case ToolbarModel::SECURITY_ERROR
:
399 color
= SkColorSetRGB(162, 0, 0);
404 return GetColor(security_level
, TEXT
);
406 return color_utils::GetReadableColor(
407 color
, GetColor(security_level
, BACKGROUND
));
412 return GetColor(security_level
, TEXT
);
416 void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble
) {
418 if (RefreshZoomView()) {
423 WebContents
* web_contents
= GetWebContents();
424 if (can_show_bubble
&& zoom_view_
->visible() && web_contents
)
425 ZoomBubbleView::ShowBubble(web_contents
, true);
428 void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction
* page_action
,
429 bool preview_enabled
) {
434 WebContents
* web_contents
= GetWebContents();
436 RefreshPageActionViews();
437 PageActionWithBadgeView
* page_action_view
=
438 static_cast<PageActionWithBadgeView
*>(GetPageActionView(page_action
));
439 DCHECK(page_action_view
);
440 if (!page_action_view
)
443 page_action_view
->image_view()->set_preview_enabled(preview_enabled
);
444 page_action_view
->UpdateVisibility(web_contents
);
449 PageActionWithBadgeView
* LocationBarView::GetPageActionView(
450 ExtensionAction
* page_action
) {
452 for (PageActionViews::const_iterator
i(page_action_views_
.begin());
453 i
!= page_action_views_
.end(); ++i
) {
454 if ((*i
)->image_view()->extension_action() == page_action
)
460 void LocationBarView::SetStarToggled(bool on
) {
462 star_view_
->SetToggled(on
);
465 void LocationBarView::SetTranslateIconToggled(bool on
) {
466 translate_icon_view_
->SetToggled(on
);
469 gfx::Point
LocationBarView::GetOmniboxViewOrigin() const {
470 gfx::Point
origin(omnibox_view_
->bounds().origin());
471 origin
.set_x(GetMirroredXInView(origin
.x() - current_omnibox_offset_
));
472 views::View::ConvertPointToScreen(this, &origin
);
476 void LocationBarView::SetImeInlineAutocompletion(const base::string16
& text
) {
477 ime_inline_autocomplete_view_
->SetText(text
);
478 ime_inline_autocomplete_view_
->SetVisible(!text
.empty());
481 void LocationBarView::SetGrayTextAutocompletion(const base::string16
& text
) {
482 if (suggested_text_view_
->text() != text
) {
483 suggested_text_view_
->SetText(text
);
484 suggested_text_view_
->SetVisible(!text
.empty());
490 base::string16
LocationBarView::GetGrayTextAutocompletion() const {
491 return HasValidSuggestText() ?
492 suggested_text_view_
->text() : base::string16();
495 void LocationBarView::SetShowFocusRect(bool show
) {
496 show_focus_rect_
= show
;
500 void LocationBarView::SelectAll() {
501 omnibox_view_
->SelectAll(true);
504 gfx::Point
LocationBarView::GetLocationBarAnchorPoint() const {
505 // The +1 in the next line creates a 1-px gap between icon and arrow tip.
506 gfx::Point
icon_bottom(0, location_icon_view_
->GetImageBounds().bottom() -
507 LocationBarView::kIconInternalPadding
+ 1);
508 gfx::Point
icon_center(location_icon_view_
->GetImageBounds().CenterPoint());
509 gfx::Point
point(icon_center
.x(), icon_bottom
.y());
510 ConvertPointToTarget(location_icon_view_
, this, &point
);
514 views::View
* LocationBarView::generated_credit_card_view() {
515 return generated_credit_card_view_
;
518 int LocationBarView::GetInternalHeight(bool use_preferred_size
) {
520 use_preferred_size
? GetPreferredSize().height() : height();
521 return std::max(total_height
- (vertical_edge_thickness() * 2), 0);
524 void LocationBarView::GetOmniboxPopupPositioningInfo(
525 gfx::Point
* top_left_screen_coord
,
529 // Because the popup might appear atop the attached bookmark bar, there won't
530 // necessarily be a client edge separating it from the rest of the toolbar.
531 // Therefore we position the popup high enough so it can draw its own client
532 // edge at the top, in the same place the toolbar would normally draw the
534 *top_left_screen_coord
= gfx::Point(
536 parent()->height() - views::NonClientFrameView::kClientEdgeThickness
);
537 views::View::ConvertPointToScreen(parent(), top_left_screen_coord
);
538 *popup_width
= parent()->width();
540 gfx::Rect
location_bar_bounds(bounds());
541 location_bar_bounds
.Inset(kNormalEdgeThickness
, 0);
542 *left_margin
= location_bar_bounds
.x();
543 *right_margin
= *popup_width
- location_bar_bounds
.right();
546 ////////////////////////////////////////////////////////////////////////////////
547 // LocationBarView, public LocationBar implementation:
549 void LocationBarView::FocusLocation(bool select_all
) {
550 omnibox_view_
->SetFocus();
552 omnibox_view_
->SelectAll(true);
555 void LocationBarView::Revert() {
556 omnibox_view_
->RevertAll();
559 OmniboxView
* LocationBarView::GetOmniboxView() {
560 return omnibox_view_
;
563 ////////////////////////////////////////////////////////////////////////////////
564 // LocationBarView, public views::View implementation:
566 bool LocationBarView::HasFocus() const {
567 return omnibox_view_
->model()->has_focus();
570 void LocationBarView::GetAccessibleState(ui::AXViewState
* state
) {
571 state
->role
= ui::AX_ROLE_GROUP
;
574 gfx::Size
LocationBarView::GetPreferredSize() const {
575 // Compute minimum height.
576 gfx::Size
min_size(border_painter_
->GetMinimumSize());
577 if (!IsInitialized())
579 gfx::Size
search_button_min_size(search_button_
->GetMinimumSize());
580 min_size
.SetToMax(search_button_min_size
);
582 // Compute width of omnibox-leading content.
583 const int horizontal_edge_thickness
= GetHorizontalEdgeThickness();
584 int leading_width
= horizontal_edge_thickness
;
585 // TODO(pkasting): Make the origin chip min width sane, and make the chip
586 // handle being shrunken down more gracefully; then uncomment this.
587 /*if (GetToolbarModel()->ShouldShowOriginChip())
588 leading_width += origin_chip_view_->GetMinimumSize().width();*/
589 if (ShouldShowKeywordBubble()) {
590 // The selected keyword view can collapse completely.
591 } else if (ShouldShowEVBubble()) {
592 leading_width
+= kBubblePadding
+
593 ev_bubble_view_
->GetMinimumSizeForLabelText(
594 GetToolbarModel()->GetEVCertName()).width();
595 } else if (!origin_chip_view_
->visible()) {
597 kItemPadding
+ location_icon_view_
->GetMinimumSize().width();
600 // Compute width of omnibox-trailing content.
601 int trailing_width
= search_button_
->visible() ?
602 (search_button_
->GetMinimumSize().width() + kSearchButtonInset
) :
603 horizontal_edge_thickness
;
604 trailing_width
+= IncrementalMinimumWidth(star_view_
) +
605 IncrementalMinimumWidth(translate_icon_view_
) +
606 IncrementalMinimumWidth(open_pdf_in_reader_view_
) +
607 IncrementalMinimumWidth(manage_passwords_icon_view_
) +
608 IncrementalMinimumWidth(zoom_view_
) +
609 IncrementalMinimumWidth(generated_credit_card_view_
) +
610 IncrementalMinimumWidth(mic_search_view_
);
611 for (PageActionViews::const_iterator
i(page_action_views_
.begin());
612 i
!= page_action_views_
.end(); ++i
)
613 trailing_width
+= IncrementalMinimumWidth((*i
));
614 for (ContentSettingViews::const_iterator
i(content_setting_views_
.begin());
615 i
!= content_setting_views_
.end(); ++i
)
616 trailing_width
+= IncrementalMinimumWidth((*i
));
618 min_size
.set_width(leading_width
+ omnibox_view_
->GetMinimumSize().width() +
619 2 * kItemPadding
- omnibox_view_
->GetInsets().width() + trailing_width
);
623 void LocationBarView::Layout() {
624 if (!IsInitialized())
627 origin_chip_view_
->SetVisible(GetToolbarModel()->ShouldShowOriginChip());
628 selected_keyword_view_
->SetVisible(false);
629 location_icon_view_
->SetVisible(false);
630 ev_bubble_view_
->SetVisible(false);
631 keyword_hint_view_
->SetVisible(false);
633 LocationBarLayout
leading_decorations(
634 LocationBarLayout::LEFT_EDGE
,
635 kItemPadding
- omnibox_view_
->GetInsets().left() -
636 GetEditLeadingInternalSpace());
637 LocationBarLayout
trailing_decorations(
638 LocationBarLayout::RIGHT_EDGE
,
639 kItemPadding
- omnibox_view_
->GetInsets().right());
641 const int origin_chip_preferred_width
=
642 origin_chip_view_
->GetPreferredSize().width();
643 const int origin_chip_width
=
644 origin_chip_view_
->visible() ? origin_chip_preferred_width
: 0;
645 // Always give the origin chip view its desired size and lay it out, even when
646 // it's not visible, so we can calculate the correct animation values below
647 // when switching to tabs that have the origin chip hidden.
648 origin_chip_view_
->SetBounds(0, 0, origin_chip_preferred_width
, height());
649 origin_chip_view_
->Layout();
651 const int bubble_location_y
= vertical_edge_thickness() + kBubblePadding
;
652 const base::string16
keyword(omnibox_view_
->model()->keyword());
653 // In some cases (e.g. fullscreen mode) we may have 0 height. We still want
654 // to position our child views in this case, because other things may be
655 // positioned relative to them (e.g. the "bookmark added" bubble if the user
657 const int location_height
= GetInternalHeight(false);
658 const int bubble_height
= std::max(location_height
- (kBubblePadding
* 2), 0);
659 if (ShouldShowKeywordBubble()) {
660 leading_decorations
.AddDecoration(bubble_location_y
, bubble_height
, true, 0,
661 kBubblePadding
, kItemPadding
,
662 selected_keyword_view_
);
663 if (selected_keyword_view_
->keyword() != keyword
) {
664 selected_keyword_view_
->SetKeyword(keyword
);
665 const TemplateURL
* template_url
=
666 TemplateURLServiceFactory::GetForProfile(profile())->
667 GetTemplateURLForKeyword(keyword
);
669 (template_url
->GetType() == TemplateURL::OMNIBOX_API_EXTENSION
)) {
670 gfx::Image image
= extensions::OmniboxAPI::Get(profile())->
671 GetOmniboxIcon(template_url
->GetExtensionId());
672 selected_keyword_view_
->SetImage(image
.AsImageSkia());
673 selected_keyword_view_
->set_is_extension_icon(true);
675 selected_keyword_view_
->SetImage(
676 *(GetThemeProvider()->GetImageSkiaNamed(IDR_OMNIBOX_SEARCH
)));
677 selected_keyword_view_
->set_is_extension_icon(false);
680 } else if (ShouldShowEVBubble()) {
681 ev_bubble_view_
->SetLabel(GetToolbarModel()->GetEVCertName());
682 // The largest fraction of the omnibox that can be taken by the EV bubble.
683 const double kMaxBubbleFraction
= 0.5;
684 leading_decorations
.AddDecoration(bubble_location_y
, bubble_height
, false,
685 kMaxBubbleFraction
, kBubblePadding
,
686 kItemPadding
, ev_bubble_view_
);
687 } else if (!origin_chip_view_
->visible()) {
688 leading_decorations
.AddDecoration(
689 vertical_edge_thickness(), location_height
,
690 location_icon_view_
);
693 if (star_view_
->visible()) {
694 trailing_decorations
.AddDecoration(
695 vertical_edge_thickness(), location_height
, star_view_
);
697 if (translate_icon_view_
->visible()) {
698 trailing_decorations
.AddDecoration(
699 vertical_edge_thickness(), location_height
, translate_icon_view_
);
701 if (open_pdf_in_reader_view_
->visible()) {
702 trailing_decorations
.AddDecoration(
703 vertical_edge_thickness(), location_height
, open_pdf_in_reader_view_
);
705 if (manage_passwords_icon_view_
->visible()) {
706 trailing_decorations
.AddDecoration(vertical_edge_thickness(),
708 manage_passwords_icon_view_
);
710 for (PageActionViews::const_iterator
i(page_action_views_
.begin());
711 i
!= page_action_views_
.end(); ++i
) {
712 if ((*i
)->visible()) {
713 trailing_decorations
.AddDecoration(
714 vertical_edge_thickness(), location_height
, (*i
));
717 if (zoom_view_
->visible()) {
718 trailing_decorations
.AddDecoration(vertical_edge_thickness(),
719 location_height
, zoom_view_
);
721 for (ContentSettingViews::const_reverse_iterator
i(
722 content_setting_views_
.rbegin()); i
!= content_setting_views_
.rend();
724 if ((*i
)->visible()) {
725 trailing_decorations
.AddDecoration(
726 bubble_location_y
, bubble_height
, false, 0, kItemPadding
,
730 if (generated_credit_card_view_
->visible()) {
731 trailing_decorations
.AddDecoration(vertical_edge_thickness(),
733 generated_credit_card_view_
);
735 if (mic_search_view_
->visible()) {
736 trailing_decorations
.AddDecoration(vertical_edge_thickness(),
737 location_height
, mic_search_view_
);
739 // Because IMEs may eat the tab key, we don't show "press tab to search" while
740 // IME composition is in progress.
741 if (!keyword
.empty() && omnibox_view_
->model()->is_keyword_hint() &&
742 !omnibox_view_
->IsImeComposing()) {
743 trailing_decorations
.AddDecoration(vertical_edge_thickness(),
744 location_height
, true, 0, kItemPadding
,
745 kItemPadding
, keyword_hint_view_
);
746 if (keyword_hint_view_
->keyword() != keyword
)
747 keyword_hint_view_
->SetKeyword(keyword
);
751 const int horizontal_edge_thickness
= GetHorizontalEdgeThickness();
752 int full_width
= width() - horizontal_edge_thickness
- origin_chip_width
;
754 const gfx::Size
search_button_size(search_button_
->GetPreferredSize());
755 const int search_button_reserved_width
=
756 search_button_size
.width() + kSearchButtonInset
;
757 full_width
-= search_button_
->visible() ?
758 search_button_reserved_width
: horizontal_edge_thickness
;
759 int entry_width
= full_width
;
760 leading_decorations
.LayoutPass1(&entry_width
);
761 trailing_decorations
.LayoutPass1(&entry_width
);
762 leading_decorations
.LayoutPass2(&entry_width
);
763 trailing_decorations
.LayoutPass2(&entry_width
);
765 int location_needed_width
= omnibox_view_
->GetTextWidth();
766 int available_width
= entry_width
- location_needed_width
;
767 // The bounds must be wide enough for all the decorations to fit.
768 gfx::Rect
location_bounds(
769 origin_chip_width
+ horizontal_edge_thickness
, vertical_edge_thickness(),
770 std::max(full_width
, full_width
- entry_width
), location_height
);
771 leading_decorations
.LayoutPass3(&location_bounds
, &available_width
);
772 trailing_decorations
.LayoutPass3(&location_bounds
, &available_width
);
774 // Calculate the animation parameters (see comments on these members in the
775 // header). We have to do this in Layout, after |origin_chip_view_| is laid
776 // out, because that may affect the host label offset in the origin chip.
777 const base::string16
& chip_text(origin_chip_view_
->host_label_text());
778 // If the chip is clicked, the omnibox text will become the toolbar model's
779 // formatted URL. We can't ask the omnibox for its current text, because
780 // while the chip is visible the current text is empty.
781 size_t prefix_end
= 0;
782 const base::string16
& omnibox_text(
783 GetToolbarModel()->GetFormattedURL(&prefix_end
));
784 // Do a case-insensitive search to better match cases like
785 // "Settings" <-> "chrome://settings". Skip any pre-hostname text.
786 size_t chip_text_offset
= std::search(
787 omnibox_text
.begin() + prefix_end
, omnibox_text
.end(),
788 chip_text
.begin(), chip_text
.end(),
789 base::CaseInsensitiveCompare
<base::char16
>()) - omnibox_text
.begin();
790 // If we couldn't find the chip text, try checking whether the omnibox text
791 // starts with it, as is true for e.g. file: URLs.
792 if ((chip_text_offset
>= omnibox_text
.length()) &&
793 StartsWith(omnibox_text
, chip_text
, true))
794 chip_text_offset
= 0;
795 const gfx::FontList
& font_list
= omnibox_view_
->GetFontList();
796 const int chip_text_width
= gfx::GetStringWidth(chip_text
, font_list
);
797 const int old_starting_offset
= starting_omnibox_offset_
;
798 const int old_starting_leading_inset
= starting_omnibox_leading_inset_
;
799 const int old_ending_width
= ending_omnibox_width_
;
800 starting_omnibox_offset_
= current_omnibox_offset_
= 0;
801 starting_omnibox_leading_inset_
= current_omnibox_leading_inset_
= 0;
802 ending_omnibox_width_
= gfx::GetStringWidth(omnibox_text
, font_list
);
803 if (chip_text_offset
< omnibox_text
.length()) {
804 if (base::i18n::IsRTL())
805 chip_text_offset
+= chip_text
.length();
806 base::string16
extra_omnibox_text(base::i18n::IsRTL() ?
807 omnibox_text
.substr(chip_text_offset
) :
808 omnibox_text
.substr(0, chip_text_offset
));
809 starting_omnibox_leading_inset_
=
810 gfx::GetStringWidth(extra_omnibox_text
, font_list
);
811 starting_omnibox_offset_
= origin_chip_view_
->HostLabelOffset() -
812 starting_omnibox_leading_inset_
;
813 current_omnibox_width_
= chip_text_width
;
815 // If the chip text wasn't found in the omnibox text, then instead of
816 // starting the show animation clipped to the "hostname", we'll start with
817 // the entire omnibox text visible, clipped to the remaining chip width, and
818 // only animate any necessary expansion of that width, without moving the
820 current_omnibox_width_
= origin_chip_view_
->WidthFromStartOfLabels();
823 // End the animations immediately if the parameters have changed.
824 if ((starting_omnibox_offset_
!= old_starting_offset
) ||
825 (starting_omnibox_leading_inset_
!= old_starting_leading_inset
) ||
826 (ending_omnibox_width_
!= old_ending_width
))
827 EndOriginChipAnimations(true);
829 // Also end the animations immediately if there's nothing to animate (but do
830 // allow the chip to fade back in).
831 const ui::NativeTheme
* native_theme
= GetNativeTheme();
832 const SkColor ending_selection_text_color
= native_theme
->GetSystemColor(
833 ui::NativeTheme::kColorId_TextfieldSelectionColor
);
834 const SkColor ending_selection_background_color
=
835 native_theme
->GetSystemColor(
836 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused
);
837 if ((starting_omnibox_offset_
== 0) &&
838 (starting_omnibox_leading_inset_
== 0) &&
839 (ending_omnibox_width_
== chip_text_width
) &&
840 (hide_url_animation_
->is_animating() ||
841 ((ending_selection_text_color
==
842 origin_chip_view_
->pressed_text_color()) &&
843 (ending_selection_background_color
==
844 origin_chip_view_
->pressed_background_color()))))
845 EndOriginChipAnimations(false);
847 if (show_url_animation_
->is_animating()) {
848 omnibox_view_
->SetSelectionTextColor(gfx::Tween::ColorValueBetween(
849 show_url_animation_
->GetCurrentValue(),
850 origin_chip_view_
->pressed_text_color(),
851 ending_selection_text_color
));
852 omnibox_view_
->SetSelectionBackgroundColor(gfx::Tween::ColorValueBetween(
853 show_url_animation_
->GetCurrentValue(),
854 origin_chip_view_
->pressed_background_color(),
855 ending_selection_background_color
));
856 current_omnibox_offset_
=
857 show_url_animation_
->CurrentValueBetween(starting_omnibox_offset_
, 0);
858 current_omnibox_leading_inset_
= show_url_animation_
->CurrentValueBetween(
859 starting_omnibox_leading_inset_
, 0);
860 current_omnibox_width_
= show_url_animation_
->CurrentValueBetween(
861 chip_text_width
, ending_omnibox_width_
);
862 } else if (hide_url_animation_
->is_animating()) {
863 current_omnibox_offset_
=
864 hide_url_animation_
->CurrentValueBetween(0, starting_omnibox_offset_
);
865 current_omnibox_leading_inset_
= hide_url_animation_
->CurrentValueBetween(
866 0, starting_omnibox_leading_inset_
);
867 current_omnibox_width_
= hide_url_animation_
->CurrentValueBetween(
868 ending_omnibox_width_
, chip_text_width
);
870 // Contract |available_width| as necessary, but never expand it. This way,
871 // we'll never draw suggested text at first and then have it disappear
872 // midway through the animation.
873 if (current_omnibox_offset_
> 0)
874 available_width
-= current_omnibox_offset_
;
875 location_bounds
.Inset(current_omnibox_offset_
, 0, 0, 0);
877 // Layout out the suggested text view right aligned to the location
878 // entry. Only show the suggested text if we can fit the text from one
879 // character before the end of the selection to the end of the text and the
880 // suggested text. If we can't it means either the suggested text is too big,
881 // or the user has scrolled.
883 // TODO(sky): We could potentially adjust this to take into account suggested
884 // text to force using minimum size if necessary, but currently the chance of
885 // showing keyword hints and suggested text is minimal and we're not confident
886 // this is the right approach for suggested text.
888 int omnibox_view_margin
= 0;
889 if (suggested_text_view_
->visible()) {
890 // We do not display the suggested text when it contains a mix of RTL and
891 // LTR characters since this could mean the suggestion should be displayed
892 // in the middle of the string.
893 base::i18n::TextDirection text_direction
=
894 base::i18n::GetStringDirection(omnibox_view_
->GetText());
895 if (text_direction
!=
896 base::i18n::GetStringDirection(suggested_text_view_
->text()))
897 text_direction
= base::i18n::UNKNOWN_DIRECTION
;
899 // TODO(sky): need to layout when the user changes caret position.
900 gfx::Size
suggested_text_size(suggested_text_view_
->GetPreferredSize());
901 if (suggested_text_size
.width() > available_width
||
902 text_direction
== base::i18n::UNKNOWN_DIRECTION
) {
903 // Hide the suggested text if the user has scrolled or we can't fit all
904 // the suggested text, or we have a mix of RTL and LTR characters.
905 suggested_text_view_
->SetBounds(0, 0, 0, 0);
907 location_needed_width
=
908 std::min(location_needed_width
,
909 location_bounds
.width() - suggested_text_size
.width());
910 gfx::Rect
suggested_text_bounds(location_bounds
.x(), location_bounds
.y(),
911 suggested_text_size
.width(),
912 location_bounds
.height());
913 // TODO(sky): figure out why this needs the -1.
914 suggested_text_bounds
.Offset(location_needed_width
- 1, 0);
916 // We reverse the order of the location entry and suggested text if:
917 // - Chrome is RTL but the text is fully LTR, or
918 // - Chrome is LTR but the text is fully RTL.
919 // This ensures the suggested text is correctly displayed to the right
920 // (or left) of the user text.
921 if (text_direction
== (base::i18n::IsRTL() ?
922 base::i18n::LEFT_TO_RIGHT
: base::i18n::RIGHT_TO_LEFT
)) {
923 // TODO(sky): Figure out why we need the +1.
924 suggested_text_bounds
.set_x(location_bounds
.x() + 1);
925 // Use a margin to prevent omnibox text from overlapping suggest text.
926 omnibox_view_margin
= suggested_text_bounds
.width();
928 suggested_text_view_
->SetBoundsRect(suggested_text_bounds
);
932 omnibox_view_
->SetBorder(
933 views::Border::CreateEmptyBorder(0, 0, 0, omnibox_view_margin
));
935 // Layout |ime_inline_autocomplete_view_| next to the user input.
936 if (ime_inline_autocomplete_view_
->visible()) {
938 gfx::GetStringWidth(ime_inline_autocomplete_view_
->text(),
939 ime_inline_autocomplete_view_
->font_list()) +
940 ime_inline_autocomplete_view_
->GetInsets().width();
941 // All the target languages (IMEs) are LTR, and we do not need to support
942 // RTL so far. In other words, no testable RTL environment so far.
943 int x
= location_needed_width
;
944 if (width
> entry_width
)
946 else if (location_needed_width
+ width
> entry_width
)
947 x
= entry_width
- width
;
948 location_bounds
.set_width(x
);
949 ime_inline_autocomplete_view_
->SetBounds(
950 location_bounds
.right(), location_bounds
.y(),
951 std::min(width
, entry_width
), location_bounds
.height());
954 omnibox_view_
->SetBoundsRect(location_bounds
);
956 search_button_
->SetBoundsRect(gfx::Rect(
957 gfx::Point(width() - search_button_reserved_width
, 0),
958 search_button_size
));
961 ////////////////////////////////////////////////////////////////////////////////
962 // LocationBarView, public OmniboxEditController implementation:
964 void LocationBarView::Update(const WebContents
* contents
) {
965 mic_search_view_
->SetVisible(
966 !GetToolbarModel()->input_in_progress() && browser_
&&
967 browser_
->search_model()->voice_search_supported());
968 RefreshContentSettingViews();
969 generated_credit_card_view_
->Update();
971 RefreshPageActionViews();
972 RefreshTranslateIcon();
973 RefreshManagePasswordsIconView();
974 content::WebContents
* web_contents_for_sub_views
=
975 GetToolbarModel()->input_in_progress() ? NULL
: GetWebContents();
976 open_pdf_in_reader_view_
->Update(web_contents_for_sub_views
);
979 UpdateBookmarkStarVisibility();
982 omnibox_view_
->OnTabChanged(contents
);
984 omnibox_view_
->Update();
986 OnChanged(); // NOTE: Calls Layout().
989 void LocationBarView::ResetTabState(WebContents
* contents
) {
990 omnibox_view_
->ResetTabState(contents
);
993 void LocationBarView::ShowURL() {
994 // Start the animation before calling ShowURL(), since the latter eventually
995 // calls back to Layout(), and if the animation is not marked as "running",
996 // we'll draw the omnibox in its final position briefly until the first
997 // animation callback reaches us.
998 if (chrome::ShouldDisplayOriginChip()) {
999 // If we're currently hiding, reverse the hide by swapping to the show
1000 // animation, offset so that the text is in the same position.
1001 if (hide_url_animation_
->is_animating()) {
1002 const double show_value
= GetValueForAnimation(false);
1003 hide_url_animation_
->Reset();
1004 show_url_animation_
->Show();
1005 // This must be done after calling Show() and is not equivalent to
1006 // calling Reset(n) before Show(); Reset() would have caused the entire
1007 // animation curve (and time) to run between this value and the final
1008 // value, whereas Show() + SetCurrentValue() skips the animation forward
1009 // to the supplied value.
1010 show_url_animation_
->SetCurrentValue(show_value
);
1012 show_url_animation_
->Show();
1015 omnibox_view_
->ShowURL();
1018 void LocationBarView::EndOriginChipAnimations(bool cancel_fade
) {
1019 show_url_animation_
->End();
1020 hide_url_animation_
->End();
1022 origin_chip_view_
->CancelFade();
1025 ToolbarModel
* LocationBarView::GetToolbarModel() {
1026 return delegate_
->GetToolbarModel();
1029 WebContents
* LocationBarView::GetWebContents() {
1030 return delegate_
->GetWebContents();
1033 ////////////////////////////////////////////////////////////////////////////////
1034 // LocationBarView, private:
1037 int LocationBarView::IncrementalMinimumWidth(views::View
* view
) {
1038 return view
->visible() ? (kItemPadding
+ view
->GetMinimumSize().width()) : 0;
1041 int LocationBarView::GetHorizontalEdgeThickness() const {
1042 // In maximized popup mode, there isn't any edge.
1043 return (is_popup_mode_
&& browser_
&& browser_
->window() &&
1044 browser_
->window()->IsMaximized()) ? 0 : vertical_edge_thickness();
1047 bool LocationBarView::RefreshContentSettingViews() {
1048 bool visibility_changed
= false;
1049 for (ContentSettingViews::const_iterator
i(content_setting_views_
.begin());
1050 i
!= content_setting_views_
.end(); ++i
) {
1051 const bool was_visible
= (*i
)->visible();
1052 (*i
)->Update(GetToolbarModel()->input_in_progress() ?
1053 NULL
: GetWebContents());
1054 if (was_visible
!= (*i
)->visible())
1055 visibility_changed
= true;
1057 return visibility_changed
;
1060 void LocationBarView::DeletePageActionViews() {
1061 for (PageActionViews::const_iterator
i(page_action_views_
.begin());
1062 i
!= page_action_views_
.end(); ++i
)
1063 RemoveChildView(*i
);
1064 STLDeleteElements(&page_action_views_
);
1067 bool LocationBarView::RefreshPageActionViews() {
1071 bool changed
= false;
1072 PageActions new_page_actions
;
1074 WebContents
* web_contents
= GetWebContents();
1076 extensions::TabHelper
* extensions_tab_helper
=
1077 extensions::TabHelper::FromWebContents(web_contents
);
1078 extensions::LocationBarController
* controller
=
1079 extensions_tab_helper
->location_bar_controller();
1080 new_page_actions
= controller
->GetCurrentActions();
1082 web_contents_null_at_last_refresh_
= web_contents
== NULL
;
1084 // On startup we sometimes haven't loaded any extensions. This makes sure
1085 // we catch up when the extensions (and any page actions) load.
1086 if (PageActionsDiffer(new_page_actions
)) {
1089 DeletePageActionViews();
1091 // Create the page action views.
1092 for (PageActions::const_iterator i
= new_page_actions
.begin();
1093 i
!= new_page_actions
.end(); ++i
) {
1094 PageActionWithBadgeView
* page_action_view
= new PageActionWithBadgeView(
1095 delegate_
->CreatePageActionImageView(this, *i
));
1096 page_action_view
->SetVisible(false);
1097 page_action_views_
.push_back(page_action_view
);
1100 // Move rightmost extensions to the start.
1101 std::stable_partition(
1102 page_action_views_
.begin(),
1103 page_action_views_
.end(),
1104 IsPageActionViewRightAligned(
1105 extensions::ExtensionRegistry::Get(profile())));
1107 View
* right_anchor
= open_pdf_in_reader_view_
;
1109 right_anchor
= star_view_
;
1110 DCHECK(right_anchor
);
1112 // |page_action_views_| are ordered right-to-left. Add them as children in
1113 // reverse order so the logical order and visual order match for
1114 // accessibility purposes.
1115 for (PageActionViews::reverse_iterator i
= page_action_views_
.rbegin();
1116 i
!= page_action_views_
.rend(); ++i
)
1117 AddChildViewAt(*i
, GetIndexOf(right_anchor
));
1120 for (PageActionViews::const_iterator
i(page_action_views_
.begin());
1121 i
!= page_action_views_
.end(); ++i
) {
1122 bool old_visibility
= (*i
)->visible();
1123 (*i
)->UpdateVisibility(
1124 GetToolbarModel()->input_in_progress() ? NULL
: web_contents
);
1125 changed
|= old_visibility
!= (*i
)->visible();
1130 bool LocationBarView::PageActionsDiffer(
1131 const PageActions
& page_actions
) const {
1132 if (page_action_views_
.size() != page_actions
.size())
1135 for (size_t index
= 0; index
< page_actions
.size(); ++index
) {
1136 PageActionWithBadgeView
* view
= page_action_views_
[index
];
1137 if (view
->image_view()->extension_action() != page_actions
[index
])
1144 bool LocationBarView::RefreshZoomView() {
1146 WebContents
* web_contents
= GetWebContents();
1149 const bool was_visible
= zoom_view_
->visible();
1150 zoom_view_
->Update(ui_zoom::ZoomController::FromWebContents(web_contents
));
1151 if (!zoom_view_
->visible())
1152 ZoomBubbleView::CloseBubble();
1153 return was_visible
!= zoom_view_
->visible();
1156 void LocationBarView::RefreshTranslateIcon() {
1157 if (!TranslateService::IsTranslateBubbleEnabled())
1160 WebContents
* web_contents
= GetWebContents();
1163 translate::LanguageState
& language_state
=
1164 ChromeTranslateClient::FromWebContents(web_contents
)->GetLanguageState();
1165 bool enabled
= language_state
.translate_enabled();
1166 command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE
, enabled
);
1167 translate_icon_view_
->SetVisible(enabled
);
1168 translate_icon_view_
->SetToggled(language_state
.IsPageTranslated());
1170 TranslateBubbleView::CloseBubble();
1173 bool LocationBarView::RefreshManagePasswordsIconView() {
1174 DCHECK(manage_passwords_icon_view_
);
1175 WebContents
* web_contents
= GetWebContents();
1178 const bool was_visible
= manage_passwords_icon_view_
->visible();
1179 ManagePasswordsUIController::FromWebContents(
1180 web_contents
)->UpdateIconAndBubbleState(manage_passwords_icon_view_
);
1181 return was_visible
!= manage_passwords_icon_view_
->visible();
1184 void LocationBarView::ShowFirstRunBubbleInternal() {
1185 // First run bubble doesn't make sense for Chrome OS.
1186 #if !defined(OS_CHROMEOS)
1187 WebContents
* web_contents
= delegate_
->GetWebContents();
1190 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents
);
1192 FirstRunBubble::ShowBubble(browser
, location_icon_view_
);
1196 bool LocationBarView::HasValidSuggestText() const {
1197 return suggested_text_view_
->visible() &&
1198 !suggested_text_view_
->size().IsEmpty();
1201 bool LocationBarView::ShouldShowKeywordBubble() const {
1202 return !omnibox_view_
->model()->keyword().empty() &&
1203 !omnibox_view_
->model()->is_keyword_hint();
1206 bool LocationBarView::ShouldShowEVBubble() const {
1207 return !chrome::ShouldDisplayOriginChip() &&
1208 (GetToolbarModel()->GetSecurityLevel(false) == ToolbarModel::EV_SECURE
);
1211 double LocationBarView::GetValueForAnimation(bool hide
) const {
1212 int calculated_offset
;
1213 const gfx::Tween::Type tween_type
= hide
? kHideTweenType
: kShowTweenType
;
1214 int start_offset
= starting_omnibox_offset_
, end_offset
= 0;
1216 std::swap(start_offset
, end_offset
);
1217 const int desired_offset
= abs(current_omnibox_offset_
);
1218 // Binary-search the value space (0 <= value <= 1) to find the appropriate
1219 // position. We only bother to iterate to within 1/64 of the desired value,
1220 // because the longer of the two animations will only run for twelve frames
1221 // anyway (200 ms * 60 Hz), so at this point we'll have a maximum error of
1222 // less than a fifth of an animation frame, which the user isn't going to
1225 // We have to use this method because Tween::CalculateValue() is not
1226 // necessarily easily invertible. Luckily, this only runs when the user
1227 // reverses the animation (rare), and the limit on how many iterations we'll
1228 // do ensures the cost is unnoticeable.
1230 double step
= value
/ 2;
1232 calculated_offset
= abs(gfx::Tween::IntValueBetween(
1233 gfx::Tween::CalculateValue(tween_type
, value
), start_offset
,
1235 if (calculated_offset
< desired_offset
)
1237 else if (calculated_offset
> desired_offset
)
1240 } while ((calculated_offset
!= desired_offset
) && (step
>= (1.0 / 64)));
1244 void LocationBarView::ResetShowAnimationAndColors() {
1245 show_url_animation_
->Reset();
1246 omnibox_view_
->UseDefaultSelectionTextColor();
1247 omnibox_view_
->UseDefaultSelectionBackgroundColor();
1250 ////////////////////////////////////////////////////////////////////////////////
1251 // LocationBarView, private LocationBar implementation:
1253 void LocationBarView::ShowFirstRunBubble() {
1254 // Wait until search engines have loaded to show the first run bubble.
1255 TemplateURLService
* url_service
=
1256 TemplateURLServiceFactory::GetForProfile(profile());
1257 if (!url_service
->loaded()) {
1258 template_url_service_
= url_service
;
1259 template_url_service_
->AddObserver(this);
1260 template_url_service_
->Load();
1263 ShowFirstRunBubbleInternal();
1266 GURL
LocationBarView::GetDestinationURL() const {
1267 return destination_url();
1270 WindowOpenDisposition
LocationBarView::GetWindowOpenDisposition() const {
1271 return disposition();
1274 ui::PageTransition
LocationBarView::GetPageTransition() const {
1275 return transition();
1278 void LocationBarView::AcceptInput() {
1279 omnibox_view_
->model()->AcceptInput(CURRENT_TAB
, false);
1282 void LocationBarView::FocusSearch() {
1283 omnibox_view_
->SetFocus();
1284 omnibox_view_
->SetForcedQuery();
1287 void LocationBarView::UpdateContentSettingsIcons() {
1288 if (RefreshContentSettingViews()) {
1294 void LocationBarView::UpdateManagePasswordsIconAndBubble() {
1295 if (RefreshManagePasswordsIconView()) {
1301 void LocationBarView::UpdatePageActions() {
1302 if (RefreshPageActionViews()) { // Changed.
1308 void LocationBarView::UpdateBookmarkStarVisibility() {
1310 star_view_
->SetVisible(
1311 browser_defaults::bookmarks_enabled
&& !is_popup_mode_
&&
1312 !GetToolbarModel()->input_in_progress() &&
1313 edit_bookmarks_enabled_
.GetValue() &&
1314 !IsBookmarkStarHiddenByExtension());
1318 bool LocationBarView::ShowPageActionPopup(
1319 const extensions::Extension
* extension
,
1320 bool grant_tab_permissions
) {
1321 ExtensionAction
* extension_action
=
1322 extensions::ExtensionActionManager::Get(profile())->GetPageAction(
1324 CHECK(extension_action
);
1325 PageActionWithBadgeView
* page_action_view
=
1326 GetPageActionView(extension_action
);
1327 if (!page_action_view
) {
1328 CHECK(!web_contents_null_at_last_refresh_
);
1329 CHECK(!is_popup_mode_
);
1330 CHECK(!extensions::FeatureSwitch::extension_action_redesign()->IsEnabled());
1333 PageActionImageView
* page_action_image_view
= page_action_view
->image_view();
1334 CHECK(page_action_image_view
);
1335 ExtensionActionViewController
* extension_action_view_controller
=
1336 page_action_image_view
->view_controller();
1337 CHECK(extension_action_view_controller
);
1338 return extension_action_view_controller
->ExecuteAction(grant_tab_permissions
);
1341 void LocationBarView::UpdateOpenPDFInReaderPrompt() {
1342 open_pdf_in_reader_view_
->Update(
1343 GetToolbarModel()->input_in_progress() ? NULL
: GetWebContents());
1348 void LocationBarView::UpdateGeneratedCreditCardView() {
1349 generated_credit_card_view_
->Update();
1354 void LocationBarView::SaveStateToContents(WebContents
* contents
) {
1355 // If we're about to switch tabs, complete any current animations, so that if
1356 // the user is in the midst of hiding the URL, when he returns to this tab,
1357 // the URL will be hidden rather than shown.
1358 // NOTE: This must be called before SaveStateToTab().
1359 EndOriginChipAnimations(true);
1360 omnibox_view_
->SaveStateToTab(contents
);
1363 const OmniboxView
* LocationBarView::GetOmniboxView() const {
1364 return omnibox_view_
;
1367 LocationBarTesting
* LocationBarView::GetLocationBarForTesting() {
1371 ////////////////////////////////////////////////////////////////////////////////
1372 // LocationBarView, private LocationBarTesting implementation:
1374 int LocationBarView::PageActionCount() {
1375 return page_action_views_
.size();
1378 int LocationBarView::PageActionVisibleCount() {
1380 for (size_t i
= 0; i
< page_action_views_
.size(); i
++) {
1381 if (page_action_views_
[i
]->visible())
1387 ExtensionAction
* LocationBarView::GetPageAction(size_t index
) {
1388 if (index
< page_action_views_
.size())
1389 return page_action_views_
[index
]->image_view()->extension_action();
1395 ExtensionAction
* LocationBarView::GetVisiblePageAction(size_t index
) {
1397 for (size_t i
= 0; i
< page_action_views_
.size(); ++i
) {
1398 if (page_action_views_
[i
]->visible()) {
1399 if (current
== index
)
1400 return page_action_views_
[i
]->image_view()->extension_action();
1410 void LocationBarView::TestPageActionPressed(size_t index
) {
1412 for (size_t i
= 0; i
< page_action_views_
.size(); ++i
) {
1413 if (page_action_views_
[i
]->visible()) {
1414 if (current
== index
) {
1415 page_action_views_
[i
]->image_view()->view_controller()->
1416 ExecuteAction(true);
1426 bool LocationBarView::GetBookmarkStarVisibility() {
1428 return star_view_
->visible();
1431 ////////////////////////////////////////////////////////////////////////////////
1432 // LocationBarView, private views::View implementation:
1434 const char* LocationBarView::GetClassName() const {
1435 return kViewClassName
;
1438 void LocationBarView::OnBoundsChanged(const gfx::Rect
& previous_bounds
) {
1439 InstantServiceFactory::GetForProfile(profile())->OnOmniboxStartMarginChanged(
1442 OmniboxPopupView
* popup
= omnibox_view_
->model()->popup_model()->view();
1443 if (popup
->IsOpen())
1444 popup
->UpdatePopupAppearance();
1447 void LocationBarView::OnFocus() {
1448 // Explicitly focus the omnibox so a focus ring will be displayed around it on
1450 omnibox_view_
->SetFocus();
1453 void LocationBarView::OnPaint(gfx::Canvas
* canvas
) {
1454 View::OnPaint(canvas
);
1456 // Fill the location bar background color behind the border. Parts of the
1457 // border images are meant to rest atop the toolbar background and parts atop
1458 // the omnibox background, so we can't just blindly fill our entire bounds.
1459 gfx::Rect
bounds(GetContentsBounds());
1460 bounds
.Inset(GetHorizontalEdgeThickness(), vertical_edge_thickness());
1461 SkColor
color(GetColor(ToolbarModel::NONE
, BACKGROUND
));
1462 if (is_popup_mode_
) {
1463 canvas
->FillRect(bounds
, color
);
1466 paint
.setStyle(SkPaint::kFill_Style
);
1467 paint
.setColor(color
);
1468 const int kBorderCornerRadius
= 2;
1469 canvas
->DrawRoundRect(bounds
, kBorderCornerRadius
, paint
);
1472 // The border itself will be drawn in PaintChildren() since it includes an
1473 // inner shadow which should be drawn over the contents.
1476 void LocationBarView::PaintChildren(gfx::Canvas
* canvas
,
1477 const views::CullSet
& cull_set
) {
1478 // Paint all the children except for the omnibox itself, which may need to be
1479 // clipped if it's animating in, and the origin chip and the search button,
1480 // which will be painted after the border.
1481 for (int i
= 0, count
= child_count(); i
< count
; ++i
) {
1482 views::View
* child
= child_at(i
);
1483 if (!child
->layer() && (child
!= omnibox_view_
) &&
1484 (child
!= origin_chip_view_
) && (child
!= search_button_
))
1485 child
->Paint(canvas
, cull_set
);
1489 gfx::ScopedCanvas
scoped_canvas(canvas
);
1490 if (show_url_animation_
->is_animating() ||
1491 hide_url_animation_
->is_animating()) {
1492 gfx::Rect
clip_rect(omnibox_view_
->bounds());
1493 clip_rect
.Inset(current_omnibox_leading_inset_
, 0, 0, 0);
1494 clip_rect
.set_width(current_omnibox_width_
);
1495 clip_rect
.set_x(GetMirroredXForRect(clip_rect
));
1496 canvas
->ClipRect(clip_rect
);
1498 omnibox_view_
->Paint(canvas
, cull_set
);
1501 // For non-InstantExtendedAPI cases, if necessary, show focus rect. As we need
1502 // the focus rect to appear on top of children we paint here rather than
1504 // Note: |Canvas::DrawFocusRect| paints a dashed rect with gray color.
1505 if (show_focus_rect_
&& HasFocus())
1506 canvas
->DrawFocusRect(omnibox_view_
->bounds());
1508 // Maximized popup windows don't draw the horizontal edges. We implement this
1509 // by simply expanding the paint area outside the view by the edge thickness.
1510 gfx::Rect
border_rect(GetContentsBounds());
1511 if (is_popup_mode_
&& (GetHorizontalEdgeThickness() == 0))
1512 border_rect
.Inset(-kPopupEdgeThickness
, 0);
1513 views::Painter::PaintPainterAt(canvas
, border_painter_
.get(), border_rect
);
1515 // The origin chip and the search button must be painted after the border so
1516 // that the border shadow is not drawn over them.
1517 origin_chip_view_
->Paint(canvas
, cull_set
);
1518 search_button_
->Paint(canvas
, cull_set
);
1521 ////////////////////////////////////////////////////////////////////////////////
1522 // LocationBarView, private views::ButtonListener implementation:
1524 void LocationBarView::ButtonPressed(views::Button
* sender
,
1525 const ui::Event
& event
) {
1526 if (sender
== mic_search_view_
) {
1527 command_updater()->ExecuteCommand(IDC_TOGGLE_SPEECH_INPUT
);
1531 DCHECK_EQ(search_button_
, sender
);
1532 // TODO(pkasting): When macourteau adds UMA stats for this, wire them up here.
1533 omnibox_view_
->model()->AcceptInput(
1534 ui::DispositionFromEventFlags(event
.flags()), false);
1537 ////////////////////////////////////////////////////////////////////////////////
1538 // LocationBarView, private views::DragController implementation:
1540 void LocationBarView::WriteDragDataForView(views::View
* sender
,
1541 const gfx::Point
& press_pt
,
1542 OSExchangeData
* data
) {
1543 DCHECK_NE(GetDragOperationsForView(sender
, press_pt
),
1544 ui::DragDropTypes::DRAG_NONE
);
1546 WebContents
* web_contents
= GetWebContents();
1547 FaviconTabHelper
* favicon_tab_helper
=
1548 FaviconTabHelper::FromWebContents(web_contents
);
1549 gfx::ImageSkia favicon
= favicon_tab_helper
->GetFavicon().AsImageSkia();
1550 button_drag_utils::SetURLAndDragImage(web_contents
->GetURL(),
1551 web_contents
->GetTitle(),
1555 sender
->GetWidget());
1558 int LocationBarView::GetDragOperationsForView(views::View
* sender
,
1559 const gfx::Point
& p
) {
1560 DCHECK((sender
== location_icon_view_
) || (sender
== ev_bubble_view_
) ||
1561 (sender
== origin_chip_view_
));
1562 WebContents
* web_contents
= delegate_
->GetWebContents();
1563 return (web_contents
&& web_contents
->GetURL().is_valid() &&
1564 (!GetOmniboxView()->IsEditingOrEmpty() ||
1565 sender
== origin_chip_view_
)) ?
1566 (ui::DragDropTypes::DRAG_COPY
| ui::DragDropTypes::DRAG_LINK
) :
1567 ui::DragDropTypes::DRAG_NONE
;
1570 bool LocationBarView::CanStartDragForView(View
* sender
,
1571 const gfx::Point
& press_pt
,
1572 const gfx::Point
& p
) {
1576 ////////////////////////////////////////////////////////////////////////////////
1577 // LocationBarView, private OmniboxEditController implementation:
1579 void LocationBarView::OnChanged() {
1580 int icon_id
= omnibox_view_
->GetIcon();
1581 location_icon_view_
->SetImage(GetThemeProvider()->GetImageSkiaNamed(icon_id
));
1582 location_icon_view_
->ShowTooltip(!GetOmniboxView()->IsEditingOrEmpty());
1584 ToolbarModel
* toolbar_model
= GetToolbarModel();
1585 chrome::DisplaySearchButtonConditions conditions
=
1586 chrome::GetDisplaySearchButtonConditions();
1587 bool meets_conditions
=
1588 (conditions
== chrome::DISPLAY_SEARCH_BUTTON_ALWAYS
) ||
1589 ((conditions
!= chrome::DISPLAY_SEARCH_BUTTON_NEVER
) &&
1590 (toolbar_model
->WouldPerformSearchTermReplacement(true) ||
1591 ((conditions
== chrome::DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP
) &&
1592 toolbar_model
->input_in_progress())));
1593 search_button_
->SetVisible(!is_popup_mode_
&& meets_conditions
);
1594 search_button_
->UpdateIcon(icon_id
== IDR_OMNIBOX_SEARCH
);
1596 origin_chip_view_
->OnChanged();
1602 void LocationBarView::OnSetFocus() {
1603 GetFocusManager()->SetFocusedView(this);
1606 InstantController
* LocationBarView::GetInstant() {
1607 return delegate_
->GetInstant();
1610 const ToolbarModel
* LocationBarView::GetToolbarModel() const {
1611 return delegate_
->GetToolbarModel();
1614 void LocationBarView::HideURL() {
1615 DCHECK(chrome::ShouldDisplayOriginChip());
1617 // If we're currently showing, reverse the hide by swapping to the hide
1618 // animation, offset so that the text is in the same position.
1619 if (show_url_animation_
->is_animating()) {
1620 const double hide_value
= GetValueForAnimation(true);
1621 ResetShowAnimationAndColors();
1622 hide_url_animation_
->Show();
1623 // This must be done after calling Show() and is not equivalent to Reset(n);
1624 // see comments in ShowURL().
1625 hide_url_animation_
->SetCurrentValue(hide_value
);
1627 hide_url_animation_
->Show();
1631 ////////////////////////////////////////////////////////////////////////////////
1632 // LocationBarView, private DropdownBarHostDelegate implementation:
1634 void LocationBarView::SetFocusAndSelection(bool select_all
) {
1635 FocusLocation(select_all
);
1638 void LocationBarView::SetAnimationOffset(int offset
) {
1639 dropdown_animation_offset_
= offset
;
1642 ////////////////////////////////////////////////////////////////////////////////
1643 // LocationBarView, private gfx::AnimationDelegate implementation:
1645 void LocationBarView::AnimationProgressed(const gfx::Animation
* animation
) {
1646 DCHECK((animation
== show_url_animation_
.get()) ||
1647 (animation
== hide_url_animation_
.get()));
1652 void LocationBarView::AnimationEnded(const gfx::Animation
* animation
) {
1653 if (animation
== show_url_animation_
.get()) {
1654 ResetShowAnimationAndColors();
1658 DCHECK(animation
== hide_url_animation_
.get());
1659 hide_url_animation_
->Reset();
1660 origin_chip_view_
->FadeIn();
1661 omnibox_view_
->HideURL(); // Calls OnChanged(), triggering layout.
1665 ////////////////////////////////////////////////////////////////////////////////
1666 // LocationBarView, private TemplateURLServiceObserver implementation:
1668 void LocationBarView::OnTemplateURLServiceChanged() {
1669 template_url_service_
->RemoveObserver(this);
1670 template_url_service_
= NULL
;
1671 // If the browser is no longer active, let's not show the info bubble, as this
1672 // would make the browser the active window again.
1673 if (omnibox_view_
&& omnibox_view_
->GetWidget()->IsActive())
1674 ShowFirstRunBubble();
1677 ////////////////////////////////////////////////////////////////////////////////
1678 // LocationBarView, private SearchModelObserver implementation:
1680 void LocationBarView::ModelChanged(const SearchModel::State
& old_state
,
1681 const SearchModel::State
& new_state
) {
1682 const bool visible
= !GetToolbarModel()->input_in_progress() &&
1683 new_state
.voice_search_supported
;
1684 if (mic_search_view_
->visible() != visible
) {
1685 mic_search_view_
->SetVisible(visible
);