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/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/location_bar_controller.h"
21 #include "chrome/browser/extensions/script_bubble_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_engines/template_url.h"
26 #include "chrome/browser/search_engines/template_url_service.h"
27 #include "chrome/browser/search_engines/template_url_service_factory.h"
28 #include "chrome/browser/translate/translate_tab_helper.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/browser_finder.h"
31 #include "chrome/browser/ui/browser_instant_controller.h"
32 #include "chrome/browser/ui/browser_window.h"
33 #include "chrome/browser/ui/omnibox/location_bar_util.h"
34 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
35 #include "chrome/browser/ui/omnibox/omnibox_popup_view.h"
36 #include "chrome/browser/ui/tabs/tab_strip_model.h"
37 #include "chrome/browser/ui/view_ids.h"
38 #include "chrome/browser/ui/views/bookmarks/bookmark_prompt_view.h"
39 #include "chrome/browser/ui/views/browser_dialogs.h"
40 #include "chrome/browser/ui/views/extensions/extension_popup.h"
41 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
42 #include "chrome/browser/ui/views/location_bar/ev_bubble_view.h"
43 #include "chrome/browser/ui/views/location_bar/generated_credit_card_view.h"
44 #include "chrome/browser/ui/views/location_bar/keyword_hint_view.h"
45 #include "chrome/browser/ui/views/location_bar/location_bar_layout.h"
46 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
47 #include "chrome/browser/ui/views/location_bar/open_pdf_in_reader_view.h"
48 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
49 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
50 #include "chrome/browser/ui/views/location_bar/script_bubble_icon_view.h"
51 #include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
52 #include "chrome/browser/ui/views/location_bar/star_view.h"
53 #include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
54 #include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
55 #include "chrome/browser/ui/views/location_bar/zoom_view.h"
56 #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
57 #include "chrome/browser/ui/views/omnibox/omnibox_views.h"
58 #include "chrome/browser/ui/zoom/zoom_controller.h"
59 #include "chrome/common/chrome_switches.h"
60 #include "chrome/common/extensions/feature_switch.h"
61 #include "chrome/common/pref_names.h"
62 #include "content/public/browser/notification_service.h"
63 #include "content/public/browser/render_widget_host_view.h"
64 #include "content/public/browser/web_contents.h"
65 #include "grit/generated_resources.h"
66 #include "grit/theme_resources.h"
67 #include "ui/base/accessibility/accessible_view_state.h"
68 #include "ui/base/dragdrop/drag_drop_types.h"
69 #include "ui/base/l10n/l10n_util.h"
70 #include "ui/base/layout.h"
71 #include "ui/base/resource/resource_bundle.h"
72 #include "ui/base/theme_provider.h"
73 #include "ui/events/event.h"
74 #include "ui/gfx/canvas.h"
75 #include "ui/gfx/color_utils.h"
76 #include "ui/gfx/image/image.h"
77 #include "ui/gfx/image/image_skia_operations.h"
78 #include "ui/gfx/skia_util.h"
79 #include "ui/native_theme/native_theme.h"
80 #include "ui/views/background.h"
81 #include "ui/views/border.h"
82 #include "ui/views/button_drag_utils.h"
83 #include "ui/views/controls/button/image_button.h"
84 #include "ui/views/controls/label.h"
85 #include "ui/views/controls/textfield/textfield.h"
86 #include "ui/views/widget/widget.h"
87 #include "ui/views/window/non_client_view.h"
90 #include "base/win/scoped_hdc.h"
91 #include "base/win/scoped_select_object.h"
92 #include "ui/native_theme/native_theme_win.h"
95 #if defined(OS_WIN) && !defined(USE_AURA)
96 #include "chrome/browser/ui/views/omnibox/omnibox_view_win.h"
99 #if !defined(OS_CHROMEOS)
100 #include "chrome/browser/ui/views/first_run_bubble.h"
103 #if defined(USE_AURA)
104 #include "ui/compositor/layer.h"
105 #include "ui/compositor/scoped_layer_animation_settings.h"
108 using content::WebContents;
114 Browser* GetBrowserFromDelegate(LocationBarView::Delegate* delegate) {
115 WebContents* contents = delegate->GetWebContents();
116 return contents ? chrome::FindBrowserWithWebContents(contents) : NULL;
119 // Given a containing |height| and a |base_font_list|, shrinks the font size
120 // until the font list will fit within |height| while having its cap height
121 // vertically centered. Returns the correctly-sized font list.
123 // The expected layout:
124 // +--------+-----------------------------------------------+------------+
125 // | | y offset | space |
126 // | +--------+-------------------+------------------+ above |
127 // | | | | internal leading | cap height |
128 // | box | font | ascent (baseline) +------------------+------------+
129 // | height | height | | cap height |
130 // | | |-------------------+------------------+------------+
131 // | | | descent (height - baseline) | space |
132 // | +--------+--------------------------------------+ below |
133 // | | space at bottom | cap height |
134 // +--------+-----------------------------------------------+------------+
136 // center of box height == center of cap height
137 // (i.e. space above cap height == space below cap height)
140 // space at bottom >= 0
141 // (i.e. Entire font must be visible inside the box.)
142 gfx::FontList GetLargestFontListWithHeightBound(
143 const gfx::FontList& base_font_list,
145 gfx::FontList font_list = base_font_list;
146 for (int font_size = font_list.GetFontSize(); font_size > 1; --font_size) {
147 const int internal_leading =
148 font_list.GetBaseline() - font_list.GetCapHeight();
149 // Some platforms don't support getting the cap height, and simply return
150 // the entire font ascent from GetCapHeight(). Centering the ascent makes
151 // the font look too low, so if GetCapHeight() returns the ascent, center
152 // the entire font height instead.
154 height - ((internal_leading != 0) ?
155 font_list.GetCapHeight() : font_list.GetHeight());
156 const int y_offset = space / 2 - internal_leading;
157 const int space_at_bottom = height - (y_offset + font_list.GetHeight());
158 if ((y_offset >= 0) && (space_at_bottom >= 0))
160 font_list = font_list.DeriveFontListWithSizeDelta(-1);
168 // LocationBarView -----------------------------------------------------------
171 const int LocationBarView::kNormalEdgeThickness = 2;
172 const int LocationBarView::kPopupEdgeThickness = 1;
173 const int LocationBarView::kIconInternalPadding = 2;
174 const int LocationBarView::kBubblePadding = 1;
175 const char LocationBarView::kViewClassName[] = "LocationBarView";
177 LocationBarView::LocationBarView(Browser* browser,
179 CommandUpdater* command_updater,
182 : OmniboxEditController(command_updater),
186 location_icon_view_(NULL),
187 ev_bubble_view_(NULL),
188 location_entry_view_(NULL),
189 ime_inline_autocomplete_view_(NULL),
190 selected_keyword_view_(NULL),
191 suggested_text_view_(NULL),
192 keyword_hint_view_(NULL),
193 mic_search_view_(NULL),
195 generated_credit_card_view_(NULL),
196 open_pdf_in_reader_view_(NULL),
197 script_bubble_icon_view_(NULL),
199 translate_icon_view_(NULL),
200 is_popup_mode_(is_popup_mode),
201 show_focus_rect_(false),
202 template_url_service_(NULL),
203 animation_offset_(0),
204 weak_ptr_factory_(this) {
205 if (!views::Textfield::IsViewsTextfieldEnabled())
206 set_id(VIEW_ID_OMNIBOX);
208 const int kOmniboxBorderImages[] = IMAGE_GRID(IDR_OMNIBOX_BORDER);
209 const int kOmniboxPopupImages[] = IMAGE_GRID(IDR_OMNIBOX_POPUP_BORDER);
210 background_border_painter_.reset(
211 views::Painter::CreateImageGridPainter(
212 is_popup_mode_ ? kOmniboxPopupImages : kOmniboxBorderImages));
213 #if defined(OS_CHROMEOS)
214 if (!is_popup_mode_) {
215 const int kOmniboxFillingImages[] = IMAGE_GRID(IDR_OMNIBOX_FILLING);
216 background_filling_painter_.reset(
217 views::Painter::CreateImageGridPainter(kOmniboxFillingImages));
221 edit_bookmarks_enabled_.Init(
222 prefs::kEditBookmarksEnabled,
223 profile_->GetPrefs(),
224 base::Bind(&LocationBarView::Update,
225 base::Unretained(this),
226 static_cast<content::WebContents*>(NULL)));
229 browser_->search_model()->AddObserver(this);
232 LocationBarView::~LocationBarView() {
233 if (template_url_service_)
234 template_url_service_->RemoveObserver(this);
236 browser_->search_model()->RemoveObserver(this);
240 void LocationBarView::InitTouchableLocationBarChildView(views::View* view) {
241 int horizontal_padding = GetBuiltInHorizontalPaddingForChildViews();
242 if (horizontal_padding != 0) {
243 view->set_border(views::Border::CreateEmptyBorder(
244 3, horizontal_padding, 3, horizontal_padding));
248 void LocationBarView::Init() {
249 // We need to be in a Widget, otherwise GetNativeTheme() may change and we're
250 // not prepared for that.
253 location_icon_view_ = new LocationIconView(this);
254 location_icon_view_->set_drag_controller(this);
255 AddChildView(location_icon_view_);
257 // Determine the main font.
258 gfx::FontList font_list = ResourceBundle::GetSharedInstance().GetFontList(
259 ResourceBundle::BaseFont);
260 const int current_font_size = font_list.GetFontSize();
261 const int desired_font_size = browser_defaults::kOmniboxFontPixelSize;
262 if (current_font_size < desired_font_size)
263 font_list = font_list.DeriveFontListWithSize(desired_font_size);
264 // Shrink large fonts to make them fit.
265 // TODO(pkasting): Stretch the location bar instead in this case.
266 const int location_height = GetInternalHeight(true);
267 font_list = GetLargestFontListWithHeightBound(font_list, location_height);
269 // Determine the font for use inside the bubbles. The bubble background
270 // images have 1 px thick edges, which we don't want to overlap.
271 const int kBubbleInteriorVerticalPadding = 1;
272 const int bubble_vertical_padding =
273 (kBubblePadding + kBubbleInteriorVerticalPadding) * 2;
274 const gfx::FontList bubble_font_list(
275 GetLargestFontListWithHeightBound(
276 font_list, location_height - bubble_vertical_padding));
278 const SkColor background_color =
279 GetColor(ToolbarModel::NONE, LocationBarView::BACKGROUND);
280 ev_bubble_view_ = new EVBubbleView(
281 bubble_font_list, GetColor(ToolbarModel::EV_SECURE, SECURITY_TEXT),
282 background_color, this);
283 ev_bubble_view_->set_drag_controller(this);
284 AddChildView(ev_bubble_view_);
286 // Initialize the Omnibox view.
287 location_entry_.reset(CreateOmniboxView(this, profile_, command_updater(),
288 is_popup_mode_, this, font_list));
289 SetLocationEntryFocusable(true);
290 location_entry_view_ = location_entry_->AddToView(this);
292 // Initialize the inline autocomplete view which is visible only when IME is
293 // turned on. Use the same font with the omnibox and highlighted background.
294 ime_inline_autocomplete_view_ = new views::Label(string16(), font_list);
295 ime_inline_autocomplete_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
296 ime_inline_autocomplete_view_->SetAutoColorReadabilityEnabled(false);
297 ime_inline_autocomplete_view_->set_background(
298 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
299 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused)));
300 ime_inline_autocomplete_view_->SetEnabledColor(
301 GetNativeTheme()->GetSystemColor(
302 ui::NativeTheme::kColorId_TextfieldSelectionColor));
303 ime_inline_autocomplete_view_->SetVisible(false);
304 AddChildView(ime_inline_autocomplete_view_);
306 const SkColor text_color = GetColor(ToolbarModel::NONE, TEXT);
307 selected_keyword_view_ = new SelectedKeywordView(
308 bubble_font_list, text_color, background_color, profile_);
309 AddChildView(selected_keyword_view_);
311 suggested_text_view_ = new views::Label(string16(), font_list);
312 suggested_text_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
313 suggested_text_view_->SetAutoColorReadabilityEnabled(false);
314 suggested_text_view_->SetEnabledColor(GetColor(
315 ToolbarModel::NONE, LocationBarView::DEEMPHASIZED_TEXT));
316 suggested_text_view_->SetVisible(false);
317 AddChildView(suggested_text_view_);
319 keyword_hint_view_ = new KeywordHintView(
321 GetColor(ToolbarModel::NONE, LocationBarView::DEEMPHASIZED_TEXT),
323 AddChildView(keyword_hint_view_);
325 mic_search_view_ = new views::ImageButton(this);
326 mic_search_view_->set_id(VIEW_ID_MIC_SEARCH_BUTTON);
327 mic_search_view_->set_accessibility_focusable(true);
328 mic_search_view_->SetTooltipText(
329 l10n_util::GetStringUTF16(IDS_TOOLTIP_MIC_SEARCH));
330 mic_search_view_->SetImage(
331 views::Button::STATE_NORMAL,
332 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
333 IDR_OMNIBOX_MIC_SEARCH));
334 mic_search_view_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
335 views::ImageButton::ALIGN_MIDDLE);
336 mic_search_view_->SetVisible(false);
337 InitTouchableLocationBarChildView(mic_search_view_);
338 AddChildView(mic_search_view_);
340 for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
341 ContentSettingImageView* content_blocked_view =
342 new ContentSettingImageView(static_cast<ContentSettingsType>(i), this,
343 bubble_font_list, text_color,
345 content_setting_views_.push_back(content_blocked_view);
346 content_blocked_view->SetVisible(false);
347 AddChildView(content_blocked_view);
350 generated_credit_card_view_ = new GeneratedCreditCardView(delegate_);
351 AddChildView(generated_credit_card_view_);
353 zoom_view_ = new ZoomView(delegate_);
354 zoom_view_->set_id(VIEW_ID_ZOOM_BUTTON);
355 AddChildView(zoom_view_);
357 open_pdf_in_reader_view_ = new OpenPDFInReaderView(this);
358 AddChildView(open_pdf_in_reader_view_);
360 script_bubble_icon_view_ = new ScriptBubbleIconView(delegate());
361 script_bubble_icon_view_->SetVisible(false);
362 AddChildView(script_bubble_icon_view_);
364 star_view_ = new StarView(command_updater());
365 star_view_->SetVisible(false);
366 AddChildView(star_view_);
368 if (CommandLine::ForCurrentProcess()->HasSwitch(
369 switches::kEnableTranslateNewUX)) {
370 translate_icon_view_ = new TranslateIconView(command_updater());
371 translate_icon_view_->SetVisible(false);
372 AddChildView(translate_icon_view_);
376 chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
377 content::Source<Profile>(profile_));
379 // Initialize the location entry. We do this to avoid a black flash which is
380 // visible when the location entry has just been initialized.
384 bool LocationBarView::IsInitialized() const {
385 return location_entry_view_ != NULL;
388 SkColor LocationBarView::GetColor(ToolbarModel::SecurityLevel security_level,
389 ColorKind kind) const {
390 const ui::NativeTheme* native_theme = GetNativeTheme();
393 #if defined(OS_CHROMEOS)
394 // Chrome OS requires a transparent omnibox background color.
395 return SkColorSetARGB(0, 255, 255, 255);
397 return native_theme->GetSystemColor(
398 ui::NativeTheme::kColorId_TextfieldDefaultBackground);
402 return native_theme->GetSystemColor(
403 ui::NativeTheme::kColorId_TextfieldDefaultColor);
406 return native_theme->GetSystemColor(
407 ui::NativeTheme::kColorId_TextfieldSelectionColor);
409 case DEEMPHASIZED_TEXT:
410 return color_utils::AlphaBlend(
411 GetColor(security_level, TEXT),
412 GetColor(security_level, BACKGROUND),
415 case SECURITY_TEXT: {
417 switch (security_level) {
418 case ToolbarModel::EV_SECURE:
419 case ToolbarModel::SECURE:
420 color = SkColorSetRGB(7, 149, 0);
423 case ToolbarModel::SECURITY_WARNING:
424 case ToolbarModel::SECURITY_POLICY_WARNING:
425 return GetColor(security_level, DEEMPHASIZED_TEXT);
428 case ToolbarModel::SECURITY_ERROR:
429 color = SkColorSetRGB(162, 0, 0);
434 return GetColor(security_level, TEXT);
436 return color_utils::GetReadableColor(
437 color, GetColor(security_level, BACKGROUND));
442 return GetColor(security_level, TEXT);
446 void LocationBarView::GetOmniboxPopupPositioningInfo(
447 gfx::Point* top_left_screen_coord,
451 // Because the popup might appear atop the attached bookmark bar, there won't
452 // necessarily be a client edge separating it from the rest of the toolbar.
453 // Therefore we position the popup high enough so it can draw its own client
454 // edge at the top, in the same place the toolbar would normally draw the
456 *top_left_screen_coord = gfx::Point(
458 parent()->height() - views::NonClientFrameView::kClientEdgeThickness);
459 views::View::ConvertPointToScreen(parent(), top_left_screen_coord);
460 *popup_width = parent()->width();
462 gfx::Rect location_bar_bounds(bounds());
463 location_bar_bounds.Inset(kNormalEdgeThickness, 0);
464 *left_margin = location_bar_bounds.x();
465 *right_margin = *popup_width - location_bar_bounds.right();
469 int LocationBarView::GetItemPadding() {
470 const int kTouchItemPadding = 8;
471 if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH)
472 return kTouchItemPadding;
474 const int kDesktopScriptBadgeItemPadding = 9;
475 const int kDesktopItemPadding = 3;
476 return extensions::FeatureSwitch::script_badges()->IsEnabled() ?
477 kDesktopScriptBadgeItemPadding : kDesktopItemPadding;
480 // DropdownBarHostDelegate
481 void LocationBarView::SetFocusAndSelection(bool select_all) {
482 FocusLocation(select_all);
485 void LocationBarView::SetAnimationOffset(int offset) {
486 animation_offset_ = offset;
489 void LocationBarView::UpdateContentSettingsIcons() {
490 UpdateContentSettingViewsPreLayout();
492 UpdateContentSettingViewsPostLayout();
496 void LocationBarView::UpdatePageActions() {
497 size_t count_before = page_action_views_.size();
498 RefreshPageActionViews();
499 RefreshScriptBubble();
500 if (page_action_views_.size() != count_before) {
501 content::NotificationService::current()->Notify(
502 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
503 content::Source<LocationBar>(this),
504 content::NotificationService::NoDetails());
511 void LocationBarView::InvalidatePageActions() {
512 size_t count_before = page_action_views_.size();
513 DeletePageActionViews();
514 if (page_action_views_.size() != count_before) {
515 content::NotificationService::current()->Notify(
516 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
517 content::Source<LocationBar>(this),
518 content::NotificationService::NoDetails());
522 void LocationBarView::UpdateOpenPDFInReaderPrompt() {
523 open_pdf_in_reader_view_->Update(
524 GetToolbarModel()->input_in_progress() ? NULL : GetWebContents());
529 void LocationBarView::UpdateGeneratedCreditCardView() {
530 generated_credit_card_view_->Update();
535 void LocationBarView::OnFocus() {
536 // Focus the view widget first which implements accessibility for
537 // Chrome OS. It is noop on Win. This should be removed once
538 // Chrome OS migrates to aura, which uses Views' textfield that receives
539 // focus. See crbug.com/106428.
540 NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, false);
542 // Then focus the native location view which implements accessibility for
544 location_entry_->SetFocus();
547 void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction* page_action,
548 bool preview_enabled) {
553 WebContents* contents = delegate_->GetWebContents();
555 RefreshPageActionViews();
556 PageActionWithBadgeView* page_action_view =
557 static_cast<PageActionWithBadgeView*>(GetPageActionView(page_action));
558 DCHECK(page_action_view);
559 if (!page_action_view)
562 page_action_view->image_view()->set_preview_enabled(preview_enabled);
563 page_action_view->UpdateVisibility(contents, GetToolbarModel()->GetURL());
568 views::View* LocationBarView::GetPageActionView(ExtensionAction *page_action) {
570 for (PageActionViews::const_iterator i(page_action_views_.begin());
571 i != page_action_views_.end(); ++i) {
572 if ((*i)->image_view()->page_action() == page_action)
578 void LocationBarView::SetStarToggled(bool on) {
580 star_view_->SetToggled(on);
583 void LocationBarView::ShowBookmarkPrompt() {
584 if (star_view_ && star_view_->visible())
585 BookmarkPromptView::ShowPrompt(star_view_, profile_->GetPrefs());
588 void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble) {
595 if (can_show_bubble && zoom_view_->visible() && delegate_->GetWebContents())
596 ZoomBubbleView::ShowBubble(delegate_->GetWebContents(), true);
599 gfx::Point LocationBarView::GetLocationEntryOrigin() const {
600 gfx::Point origin(location_entry_view_->bounds().origin());
601 // If the UI layout is RTL, the coordinate system is not transformed and
602 // therefore we need to adjust the X coordinate so that bubble appears on the
603 // right hand side of the location bar.
604 if (base::i18n::IsRTL())
605 origin.set_x(width() - origin.x());
606 views::View::ConvertPointToScreen(this, &origin);
610 void LocationBarView::SetImeInlineAutocompletion(const string16& text) {
611 ime_inline_autocomplete_view_->SetText(text);
612 ime_inline_autocomplete_view_->SetVisible(!text.empty());
615 void LocationBarView::SetGrayTextAutocompletion(const string16& text) {
616 if (suggested_text_view_->text() != text) {
617 suggested_text_view_->SetText(text);
618 suggested_text_view_->SetVisible(!text.empty());
624 string16 LocationBarView::GetGrayTextAutocompletion() const {
625 return HasValidSuggestText() ? suggested_text_view_->text() : string16();
628 void LocationBarView::SetLocationEntryFocusable(bool focusable) {
629 OmniboxViewViews* omnibox_views = GetOmniboxViewViews(location_entry_.get());
631 omnibox_views->set_focusable(focusable);
633 set_focusable(focusable);
636 bool LocationBarView::IsLocationEntryFocusableInRootView() const {
637 OmniboxViewViews* omnibox_views = GetOmniboxViewViews(location_entry_.get());
638 return omnibox_views ? omnibox_views->IsFocusable() : View::IsFocusable();
641 gfx::Size LocationBarView::GetPreferredSize() {
642 return background_border_painter_->GetMinimumSize();
645 void LocationBarView::Layout() {
646 if (!location_entry_.get())
649 selected_keyword_view_->SetVisible(false);
650 location_icon_view_->SetVisible(false);
651 ev_bubble_view_->SetVisible(false);
652 keyword_hint_view_->SetVisible(false);
654 const int item_padding = GetItemPadding();
655 // The native edit has 1 px of whitespace inside it before the text when the
656 // text is not scrolled off the leading edge. The views textfield has 1 px of
657 // whitespace before the text in the RTL case only.
658 const int kEditLeadingInternalSpace =
659 (base::i18n::IsRTL() || GetOmniboxViewWin(location_entry_.get())) ? 1 : 0;
660 LocationBarLayout leading_decorations(
661 LocationBarLayout::LEFT_EDGE, item_padding - kEditLeadingInternalSpace);
662 LocationBarLayout trailing_decorations(LocationBarLayout::RIGHT_EDGE,
665 const string16 keyword(location_entry_->model()->keyword());
666 const bool is_keyword_hint(location_entry_->model()->is_keyword_hint());
667 const int bubble_location_y = vertical_edge_thickness() + kBubblePadding;
668 // In some cases (e.g. fullscreen mode) we may have 0 height. We still want
669 // to position our child views in this case, because other things may be
670 // positioned relative to them (e.g. the "bookmark added" bubble if the user
672 const int location_height = GetInternalHeight(false);
673 const int bubble_height = std::max(location_height - (kBubblePadding * 2), 0);
674 if (!keyword.empty() && !is_keyword_hint) {
675 leading_decorations.AddDecoration(bubble_location_y, bubble_height, true, 0,
676 kBubblePadding, item_padding, 0,
677 selected_keyword_view_);
678 if (selected_keyword_view_->keyword() != keyword) {
679 selected_keyword_view_->SetKeyword(keyword);
680 const TemplateURL* template_url =
681 TemplateURLServiceFactory::GetForProfile(profile_)->
682 GetTemplateURLForKeyword(keyword);
684 (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) {
685 gfx::Image image = extensions::OmniboxAPI::Get(profile_)->
686 GetOmniboxIcon(template_url->GetExtensionId());
687 selected_keyword_view_->SetImage(image.AsImageSkia());
688 selected_keyword_view_->set_is_extension_icon(true);
690 selected_keyword_view_->SetImage(
691 *(GetThemeProvider()->GetImageSkiaNamed(IDR_OMNIBOX_SEARCH)));
692 selected_keyword_view_->set_is_extension_icon(false);
695 } else if (GetToolbarModel()->GetSecurityLevel(false) ==
696 ToolbarModel::EV_SECURE) {
697 ev_bubble_view_->SetLabel(GetToolbarModel()->GetEVCertName());
698 // The largest fraction of the omnibox that can be taken by the EV bubble.
699 const double kMaxBubbleFraction = 0.5;
700 leading_decorations.AddDecoration(bubble_location_y, bubble_height, false,
701 kMaxBubbleFraction, kBubblePadding,
702 item_padding, 0, ev_bubble_view_);
704 leading_decorations.AddDecoration(
705 vertical_edge_thickness(), location_height,
706 GetBuiltInHorizontalPaddingForChildViews(),
707 location_icon_view_);
710 if (star_view_ && star_view_->visible()) {
711 trailing_decorations.AddDecoration(
712 vertical_edge_thickness(), location_height,
713 GetBuiltInHorizontalPaddingForChildViews(), star_view_);
715 if (translate_icon_view_ && translate_icon_view_->visible()) {
716 trailing_decorations.AddDecoration(
717 vertical_edge_thickness(), location_height,
718 GetBuiltInHorizontalPaddingForChildViews(),
719 translate_icon_view_);
721 if (script_bubble_icon_view_ && script_bubble_icon_view_->visible()) {
722 trailing_decorations.AddDecoration(
723 vertical_edge_thickness(), location_height,
724 GetBuiltInHorizontalPaddingForChildViews(),
725 script_bubble_icon_view_);
727 if (open_pdf_in_reader_view_ && open_pdf_in_reader_view_->visible()) {
728 trailing_decorations.AddDecoration(
729 vertical_edge_thickness(), location_height,
730 GetBuiltInHorizontalPaddingForChildViews(),
731 open_pdf_in_reader_view_);
733 for (PageActionViews::const_iterator i(page_action_views_.begin());
734 i != page_action_views_.end(); ++i) {
735 if ((*i)->visible()) {
736 trailing_decorations.AddDecoration(
737 vertical_edge_thickness(), location_height,
738 GetBuiltInHorizontalPaddingForChildViews(), (*i));
741 if (zoom_view_->visible()) {
742 trailing_decorations.AddDecoration(vertical_edge_thickness(),
743 location_height, 0, zoom_view_);
745 for (ContentSettingViews::const_reverse_iterator i(
746 content_setting_views_.rbegin()); i != content_setting_views_.rend();
748 if ((*i)->visible()) {
749 trailing_decorations.AddDecoration(
750 bubble_location_y, bubble_height, false, 0, item_padding,
751 item_padding, GetBuiltInHorizontalPaddingForChildViews(), (*i));
754 if (generated_credit_card_view_->visible()) {
755 trailing_decorations.AddDecoration(vertical_edge_thickness(),
757 generated_credit_card_view_);
759 if (mic_search_view_->visible()) {
760 trailing_decorations.AddDecoration(vertical_edge_thickness(),
761 location_height, 0, mic_search_view_);
763 // Because IMEs may eat the tab key, we don't show "press tab to search" while
764 // IME composition is in progress.
765 if (!keyword.empty() && is_keyword_hint &&
766 !location_entry_->IsImeComposing()) {
767 trailing_decorations.AddDecoration(vertical_edge_thickness(),
768 location_height, true, 0, item_padding,
769 item_padding, 0, keyword_hint_view_);
770 if (keyword_hint_view_->keyword() != keyword)
771 keyword_hint_view_->SetKeyword(keyword);
775 const int horizontal_edge_thickness = GetHorizontalEdgeThickness();
776 int full_width = width() - 2 * horizontal_edge_thickness;
777 int entry_width = full_width;
778 leading_decorations.LayoutPass1(&entry_width);
779 trailing_decorations.LayoutPass1(&entry_width);
780 leading_decorations.LayoutPass2(&entry_width);
781 trailing_decorations.LayoutPass2(&entry_width);
783 int location_needed_width = location_entry_->TextWidth();
784 int available_width = entry_width - location_needed_width;
785 // The bounds must be wide enough for all the decorations to fit.
786 gfx::Rect location_bounds(
787 horizontal_edge_thickness, vertical_edge_thickness(),
788 std::max(full_width, full_width - entry_width), location_height);
789 leading_decorations.LayoutPass3(&location_bounds, &available_width);
790 trailing_decorations.LayoutPass3(&location_bounds, &available_width);
792 // Layout out the suggested text view right aligned to the location
793 // entry. Only show the suggested text if we can fit the text from one
794 // character before the end of the selection to the end of the text and the
795 // suggested text. If we can't it means either the suggested text is too big,
796 // or the user has scrolled.
798 // TODO(sky): We could potentially adjust this to take into account suggested
799 // text to force using minimum size if necessary, but currently the chance of
800 // showing keyword hints and suggested text is minimal and we're not confident
801 // this is the right approach for suggested text.
803 OmniboxViewViews* omnibox_views =
804 GetOmniboxViewViews(location_entry_.get());
805 int omnibox_views_margin = 0;
806 if (suggested_text_view_->visible()) {
807 // We do not display the suggested text when it contains a mix of RTL and
808 // LTR characters since this could mean the suggestion should be displayed
809 // in the middle of the string.
810 base::i18n::TextDirection text_direction =
811 base::i18n::GetStringDirection(location_entry_->GetText());
812 if (text_direction !=
813 base::i18n::GetStringDirection(suggested_text_view_->text()))
814 text_direction = base::i18n::UNKNOWN_DIRECTION;
816 // TODO(sky): need to layout when the user changes caret position.
817 gfx::Size suggested_text_size(suggested_text_view_->GetPreferredSize());
818 if (suggested_text_size.width() > available_width ||
819 text_direction == base::i18n::UNKNOWN_DIRECTION) {
820 // Hide the suggested text if the user has scrolled or we can't fit all
821 // the suggested text, or we have a mix of RTL and LTR characters.
822 suggested_text_view_->SetBounds(0, 0, 0, 0);
824 location_needed_width =
825 std::min(location_needed_width,
826 location_bounds.width() - suggested_text_size.width());
827 gfx::Rect suggested_text_bounds(location_bounds.x(), location_bounds.y(),
828 suggested_text_size.width(),
829 location_bounds.height());
830 // TODO(sky): figure out why this needs the -1.
831 suggested_text_bounds.Offset(location_needed_width - 1, 0);
832 // For non-views the omnibox needs to be shrunk so that the suggest text
835 location_bounds.set_width(location_needed_width);
837 // We reverse the order of the location entry and suggested text if:
838 // - Chrome is RTL but the text is fully LTR, or
839 // - Chrome is LTR but the text is fully RTL.
840 // This ensures the suggested text is correctly displayed to the right
841 // (or left) of the user text.
842 if (text_direction == (base::i18n::IsRTL() ?
843 base::i18n::LEFT_TO_RIGHT : base::i18n::RIGHT_TO_LEFT)) {
844 // TODO(sky): Figure out why we need the +1.
845 suggested_text_bounds.set_x(location_bounds.x() + 1);
847 // Use a margin to prevent the omnibox text from overlapping the
849 omnibox_views_margin = suggested_text_bounds.width();
851 // Non-views doesn't support margins so move the omnibox over.
852 location_bounds.set_x(
853 location_bounds.x() + suggested_text_bounds.width());
856 suggested_text_view_->SetBoundsRect(suggested_text_bounds);
861 omnibox_views->SetHorizontalMargins(0, omnibox_views_margin);
863 // Layout |ime_inline_autocomplete_view_| next to the user input.
864 if (ime_inline_autocomplete_view_->visible()) {
866 ime_inline_autocomplete_view_->font().GetStringWidth(
867 ime_inline_autocomplete_view_->text()) +
868 ime_inline_autocomplete_view_->GetInsets().width();
869 // All the target languages (IMEs) are LTR, and we do not need to support
870 // RTL so far. In other words, no testable RTL environment so far.
871 int x = location_needed_width;
872 if (width > entry_width)
874 else if (location_needed_width + width > entry_width)
875 x = entry_width - width;
876 location_bounds.set_width(x);
877 ime_inline_autocomplete_view_->SetBounds(
878 location_bounds.right(), location_bounds.y(),
879 std::min(width, entry_width), location_bounds.height());
882 location_entry_view_->SetBoundsRect(location_bounds);
885 void LocationBarView::OnPaint(gfx::Canvas* canvas) {
886 View::OnPaint(canvas);
888 // Fill the location bar background color behind the border. Parts of the
889 // border images are meant to rest atop the toolbar background and parts atop
890 // the omnibox background, so we can't just blindly fill our entire bounds.
891 const int horizontal_edge_thickness = GetHorizontalEdgeThickness();
892 if (!background_filling_painter_) {
893 gfx::Rect bounds(GetContentsBounds());
894 bounds.Inset(horizontal_edge_thickness, vertical_edge_thickness());
895 SkColor color(GetColor(ToolbarModel::NONE, BACKGROUND));
896 if (is_popup_mode_) {
897 canvas->FillRect(bounds, color);
900 paint.setStyle(SkPaint::kFill_Style);
901 paint.setColor(color);
902 const int kBorderCornerRadius = 2;
903 canvas->DrawRoundRect(bounds, kBorderCornerRadius, paint);
907 // Maximized popup windows don't draw the horizontal edges. We implement this
908 // by simply expanding the paint area outside the view by the edge thickness.
909 gfx::Rect background_rect(GetContentsBounds());
910 if (is_popup_mode_ && (horizontal_edge_thickness == 0))
911 background_rect.Inset(-kPopupEdgeThickness, 0);
912 views::Painter::PaintPainterAt(canvas, background_border_painter_.get(),
914 if (background_filling_painter_)
915 background_filling_painter_->Paint(canvas, size());
918 PaintPageActionBackgrounds(canvas);
920 // For non-InstantExtendedAPI cases, if necessary, show focus rect.
921 // Note: |Canvas::DrawFocusRect| paints a dashed rect with gray color.
922 if (show_focus_rect_ && HasFocus()) {
923 gfx::Rect r = location_entry_view_->bounds();
924 // TODO(jamescook): Is this still needed?
929 canvas->DrawFocusRect(r);
933 void LocationBarView::SetShowFocusRect(bool show) {
934 show_focus_rect_ = show;
938 void LocationBarView::SelectAll() {
939 location_entry_->SelectAll(true);
942 #if defined(OS_WIN) && !defined(USE_AURA)
943 bool LocationBarView::OnMousePressed(const ui::MouseEvent& event) {
945 if (event.IsLeftMouseButton()) {
946 msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
947 WM_LBUTTONDBLCLK : WM_LBUTTONDOWN;
948 } else if (event.IsMiddleMouseButton()) {
949 msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
950 WM_MBUTTONDBLCLK : WM_MBUTTONDOWN;
951 } else if (event.IsRightMouseButton()) {
952 msg = (event.flags() & ui::EF_IS_DOUBLE_CLICK) ?
953 WM_RBUTTONDBLCLK : WM_RBUTTONDOWN;
958 OnMouseEvent(event, msg);
962 bool LocationBarView::OnMouseDragged(const ui::MouseEvent& event) {
963 OnMouseEvent(event, WM_MOUSEMOVE);
967 void LocationBarView::OnMouseReleased(const ui::MouseEvent& event) {
969 if (event.IsLeftMouseButton()) {
971 } else if (event.IsMiddleMouseButton()) {
973 } else if (event.IsRightMouseButton()) {
979 OnMouseEvent(event, msg);
982 void LocationBarView::OnMouseCaptureLost() {
983 OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
985 omnibox_win->HandleExternalMsg(WM_CAPTURECHANGED, 0, CPoint());
989 views::View* LocationBarView::generated_credit_card_view() {
990 return generated_credit_card_view_;
993 void LocationBarView::Update(const WebContents* contents) {
994 mic_search_view_->SetVisible(
995 !GetToolbarModel()->input_in_progress() && browser_ &&
996 browser_->search_model()->voice_search_supported());
997 UpdateContentSettingViewsPreLayout();
998 generated_credit_card_view_->Update();
999 ZoomBubbleView::CloseBubble();
1001 RefreshPageActionViews();
1002 RefreshScriptBubble();
1003 RefreshTranslateIcon();
1004 open_pdf_in_reader_view_->Update(
1005 GetToolbarModel()->input_in_progress() ? NULL : GetWebContents());
1007 bool star_enabled = browser_defaults::bookmarks_enabled && !is_popup_mode_ &&
1008 star_view_ && !GetToolbarModel()->input_in_progress() &&
1009 edit_bookmarks_enabled_.GetValue();
1011 command_updater()->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
1012 command_updater()->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
1015 star_view_->SetVisible(star_enabled);
1018 location_entry_->OnTabChanged(contents);
1020 location_entry_->Update();
1022 OnChanged(); // NOTE: Calls Layout().
1023 UpdateContentSettingViewsPostLayout();
1026 void LocationBarView::OnChanged() {
1027 location_icon_view_->SetImage(
1028 GetThemeProvider()->GetImageSkiaNamed(location_entry_->GetIcon()));
1029 location_icon_view_->ShowTooltip(!GetLocationEntry()->IsEditingOrEmpty());
1035 void LocationBarView::OnSetFocus() {
1036 GetFocusManager()->SetFocusedView(this);
1039 InstantController* LocationBarView::GetInstant() {
1040 return delegate_->GetInstant();
1043 WebContents* LocationBarView::GetWebContents() {
1044 return delegate_->GetWebContents();
1047 ToolbarModel* LocationBarView::GetToolbarModel() {
1048 return delegate_->GetToolbarModel();
1051 const ToolbarModel* LocationBarView::GetToolbarModel() const {
1052 return delegate_->GetToolbarModel();
1055 const char* LocationBarView::GetClassName() const {
1056 return kViewClassName;
1059 bool LocationBarView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
1061 if (views::FocusManager::IsTabTraversalKeyEvent(event)) {
1062 if (location_entry_->model()->popup_model()->IsOpen()) {
1063 // Return true so that the edit sees the tab and moves the selection.
1066 if (keyword_hint_view_->visible() && !event.IsShiftDown()) {
1067 // Return true so the edit gets the tab event and enters keyword mode.
1072 #if defined(USE_AURA)
1075 OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
1077 return omnibox_win->SkipDefaultKeyEventProcessing(event);
1081 // This method is not used for Linux ports. See FocusManager::OnKeyEvent() in
1082 // src/ui/views/focus/focus_manager.cc for details.
1086 void LocationBarView::GetAccessibleState(ui::AccessibleViewState* state) {
1087 if (!location_entry_)
1090 state->role = ui::AccessibilityTypes::ROLE_LOCATION_BAR;
1091 state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_LOCATION);
1092 state->value = location_entry_->GetText();
1094 string16::size_type entry_start;
1095 string16::size_type entry_end;
1096 location_entry_->GetSelectionBounds(&entry_start, &entry_end);
1097 state->selection_start = entry_start;
1098 state->selection_end = entry_end;
1100 if (is_popup_mode_) {
1101 state->state |= ui::AccessibilityTypes::STATE_READONLY;
1103 state->set_value_callback =
1104 base::Bind(&LocationBarView::AccessibilitySetValue,
1105 weak_ptr_factory_.GetWeakPtr());
1109 bool LocationBarView::HasFocus() const {
1110 return location_entry_->model()->has_focus();
1113 void LocationBarView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
1114 if (browser_ && browser_->instant_controller() && parent())
1115 browser_->instant_controller()->SetOmniboxBounds(bounds());
1116 OmniboxPopupView* popup = location_entry_->model()->popup_model()->view();
1117 if (popup->IsOpen())
1118 popup->UpdatePopupAppearance();
1121 void LocationBarView::ButtonPressed(views::Button* sender,
1122 const ui::Event& event) {
1123 DCHECK_EQ(mic_search_view_, sender);
1124 command_updater()->ExecuteCommand(IDC_TOGGLE_SPEECH_INPUT);
1127 void LocationBarView::WriteDragDataForView(views::View* sender,
1128 const gfx::Point& press_pt,
1129 OSExchangeData* data) {
1130 DCHECK_NE(GetDragOperationsForView(sender, press_pt),
1131 ui::DragDropTypes::DRAG_NONE);
1133 WebContents* web_contents = GetWebContents();
1134 FaviconTabHelper* favicon_tab_helper =
1135 FaviconTabHelper::FromWebContents(web_contents);
1136 gfx::ImageSkia favicon = favicon_tab_helper->GetFavicon().AsImageSkia();
1137 button_drag_utils::SetURLAndDragImage(web_contents->GetURL(),
1138 web_contents->GetTitle(),
1141 sender->GetWidget());
1144 int LocationBarView::GetDragOperationsForView(views::View* sender,
1145 const gfx::Point& p) {
1146 DCHECK((sender == location_icon_view_) || (sender == ev_bubble_view_));
1147 WebContents* web_contents = delegate_->GetWebContents();
1148 return (web_contents && web_contents->GetURL().is_valid() &&
1149 !GetLocationEntry()->IsEditingOrEmpty()) ?
1150 (ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK) :
1151 ui::DragDropTypes::DRAG_NONE;
1154 bool LocationBarView::CanStartDragForView(View* sender,
1155 const gfx::Point& press_pt,
1156 const gfx::Point& p) {
1160 ////////////////////////////////////////////////////////////////////////////////
1161 // LocationBarView, LocationBar implementation:
1163 void LocationBarView::ShowFirstRunBubble() {
1164 // Wait until search engines have loaded to show the first run bubble.
1165 TemplateURLService* url_service =
1166 TemplateURLServiceFactory::GetForProfile(profile_);
1167 if (!url_service->loaded()) {
1168 template_url_service_ = url_service;
1169 template_url_service_->AddObserver(this);
1170 template_url_service_->Load();
1173 ShowFirstRunBubbleInternal();
1176 GURL LocationBarView::GetDestinationURL() const {
1177 return destination_url();
1180 WindowOpenDisposition LocationBarView::GetWindowOpenDisposition() const {
1181 return disposition();
1184 content::PageTransition LocationBarView::GetPageTransition() const {
1185 return transition();
1188 void LocationBarView::AcceptInput() {
1189 location_entry_->model()->AcceptInput(CURRENT_TAB, false);
1192 void LocationBarView::FocusLocation(bool select_all) {
1193 location_entry_->SetFocus();
1195 location_entry_->SelectAll(true);
1198 void LocationBarView::FocusSearch() {
1199 location_entry_->SetFocus();
1200 location_entry_->SetForcedQuery();
1203 void LocationBarView::SaveStateToContents(WebContents* contents) {
1204 location_entry_->SaveStateToTab(contents);
1207 void LocationBarView::Revert() {
1208 location_entry_->RevertAll();
1211 const OmniboxView* LocationBarView::GetLocationEntry() const {
1212 return location_entry_.get();
1215 OmniboxView* LocationBarView::GetLocationEntry() {
1216 return location_entry_.get();
1219 LocationBarTesting* LocationBarView::GetLocationBarForTesting() {
1223 int LocationBarView::PageActionCount() {
1224 return page_action_views_.size();
1227 int LocationBarView::PageActionVisibleCount() {
1229 for (size_t i = 0; i < page_action_views_.size(); i++) {
1230 if (page_action_views_[i]->visible())
1236 ExtensionAction* LocationBarView::GetPageAction(size_t index) {
1237 if (index < page_action_views_.size())
1238 return page_action_views_[index]->image_view()->page_action();
1244 ExtensionAction* LocationBarView::GetVisiblePageAction(size_t index) {
1246 for (size_t i = 0; i < page_action_views_.size(); ++i) {
1247 if (page_action_views_[i]->visible()) {
1248 if (current == index)
1249 return page_action_views_[i]->image_view()->page_action();
1259 void LocationBarView::TestPageActionPressed(size_t index) {
1261 for (size_t i = 0; i < page_action_views_.size(); ++i) {
1262 if (page_action_views_[i]->visible()) {
1263 if (current == index) {
1264 page_action_views_[i]->image_view()->ExecuteAction(
1265 ExtensionPopup::SHOW);
1275 bool LocationBarView::GetBookmarkStarVisibility() {
1277 return star_view_->visible();
1280 void LocationBarView::OnTemplateURLServiceChanged() {
1281 template_url_service_->RemoveObserver(this);
1282 template_url_service_ = NULL;
1283 // If the browser is no longer active, let's not show the info bubble, as this
1284 // would make the browser the active window again.
1285 if (location_entry_view_ && location_entry_view_->GetWidget()->IsActive())
1286 ShowFirstRunBubble();
1289 void LocationBarView::Observe(int type,
1290 const content::NotificationSource& source,
1291 const content::NotificationDetails& details) {
1293 case chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED: {
1294 // Only update if the updated action box was for the active tab contents.
1295 WebContents* target_tab = content::Details<WebContents>(details).ptr();
1296 if (target_tab == GetWebContents())
1297 UpdatePageActions();
1302 NOTREACHED() << "Unexpected notification.";
1306 void LocationBarView::ModelChanged(const SearchModel::State& old_state,
1307 const SearchModel::State& new_state) {
1308 const bool visible = !GetToolbarModel()->input_in_progress() &&
1309 new_state.voice_search_supported;
1310 if (mic_search_view_->visible() != visible) {
1311 mic_search_view_->SetVisible(visible);
1316 int LocationBarView::GetInternalHeight(bool use_preferred_size) {
1318 use_preferred_size ? GetPreferredSize().height() : height();
1319 return std::max(total_height - (vertical_edge_thickness() * 2), 0);
1322 ////////////////////////////////////////////////////////////////////////////////
1323 // LocationBarView, private:
1326 int LocationBarView::GetBuiltInHorizontalPaddingForChildViews() {
1327 return (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) ?
1328 GetItemPadding() / 2 : 0;
1331 int LocationBarView::GetHorizontalEdgeThickness() const {
1332 // In maximized popup mode, there isn't any edge.
1333 return (is_popup_mode_ && browser_ && browser_->window() &&
1334 browser_->window()->IsMaximized()) ? 0 : vertical_edge_thickness();
1337 void LocationBarView::UpdateContentSettingViewsPreLayout() {
1338 for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
1339 i != content_setting_views_.end(); ++i) {
1340 (*i)->UpdatePreLayout(GetToolbarModel()->input_in_progress() ?
1341 NULL : GetWebContents());
1345 void LocationBarView::UpdateContentSettingViewsPostLayout() {
1346 for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
1347 i != content_setting_views_.end(); ++i) {
1348 (*i)->UpdatePostLayout(GetToolbarModel()->input_in_progress() ?
1349 NULL : GetWebContents());
1353 void LocationBarView::DeletePageActionViews() {
1354 for (PageActionViews::const_iterator i(page_action_views_.begin());
1355 i != page_action_views_.end(); ++i)
1356 RemoveChildView(*i);
1357 STLDeleteElements(&page_action_views_);
1360 void LocationBarView::RefreshPageActionViews() {
1364 // Remember the previous visibility of the page actions so that we can
1365 // notify when this changes.
1366 std::map<ExtensionAction*, bool> old_visibility;
1367 for (PageActionViews::const_iterator i(page_action_views_.begin());
1368 i != page_action_views_.end(); ++i) {
1369 old_visibility[(*i)->image_view()->page_action()] = (*i)->visible();
1372 std::vector<ExtensionAction*> new_page_actions;
1374 WebContents* contents = delegate_->GetWebContents();
1376 extensions::TabHelper* extensions_tab_helper =
1377 extensions::TabHelper::FromWebContents(contents);
1378 extensions::LocationBarController* controller =
1379 extensions_tab_helper->location_bar_controller();
1380 new_page_actions = controller->GetCurrentActions();
1383 // On startup we sometimes haven't loaded any extensions. This makes sure
1384 // we catch up when the extensions (and any page actions) load.
1385 if (page_actions_ != new_page_actions) {
1386 page_actions_.swap(new_page_actions);
1387 DeletePageActionViews(); // Delete the old views (if any).
1389 page_action_views_.resize(page_actions_.size());
1390 View* right_anchor = open_pdf_in_reader_view_;
1392 right_anchor = star_view_;
1394 right_anchor = script_bubble_icon_view_;
1395 DCHECK(right_anchor);
1397 // Add the page actions in reverse order, so that the child views are
1398 // inserted in left-to-right order for accessibility.
1399 for (int i = page_actions_.size() - 1; i >= 0; --i) {
1400 page_action_views_[i] = new PageActionWithBadgeView(
1401 delegate_->CreatePageActionImageView(this, page_actions_[i]));
1402 page_action_views_[i]->SetVisible(false);
1403 AddChildViewAt(page_action_views_[i], GetIndexOf(right_anchor));
1407 if (!page_action_views_.empty() && contents) {
1408 Browser* browser = chrome::FindBrowserWithWebContents(contents);
1409 GURL url = browser->tab_strip_model()->GetActiveWebContents()->GetURL();
1411 for (PageActionViews::const_iterator i(page_action_views_.begin());
1412 i != page_action_views_.end(); ++i) {
1413 (*i)->UpdateVisibility(
1414 GetToolbarModel()->input_in_progress() ? NULL : contents, url);
1416 // Check if the visibility of the action changed and notify if it did.
1417 ExtensionAction* action = (*i)->image_view()->page_action();
1418 if (old_visibility.find(action) == old_visibility.end() ||
1419 old_visibility[action] != (*i)->visible()) {
1420 content::NotificationService::current()->Notify(
1421 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
1422 content::Source<ExtensionAction>(action),
1423 content::Details<WebContents>(contents));
1429 size_t LocationBarView::ScriptBubbleScriptsRunning() {
1430 WebContents* contents = delegate_->GetWebContents();
1433 extensions::TabHelper* extensions_tab_helper =
1434 extensions::TabHelper::FromWebContents(contents);
1435 if (!extensions_tab_helper)
1437 extensions::ScriptBubbleController* script_bubble_controller =
1438 extensions_tab_helper->script_bubble_controller();
1439 if (!script_bubble_controller)
1441 size_t script_count =
1442 script_bubble_controller->extensions_running_scripts().size();
1443 return script_count;
1446 void LocationBarView::RefreshScriptBubble() {
1447 if (!script_bubble_icon_view_)
1449 size_t script_count = ScriptBubbleScriptsRunning();
1450 script_bubble_icon_view_->SetVisible(script_count > 0);
1451 if (script_count > 0)
1452 script_bubble_icon_view_->SetScriptCount(script_count);
1455 void LocationBarView::RefreshZoomView() {
1457 WebContents* web_contents = GetWebContents();
1461 ZoomController* zoom_controller =
1462 ZoomController::FromWebContents(web_contents);
1463 zoom_view_->Update(zoom_controller);
1466 void LocationBarView::RefreshTranslateIcon() {
1467 if (!translate_icon_view_)
1470 WebContents* web_contents = GetWebContents();
1474 TranslateTabHelper* translate_tab_helper =
1475 TranslateTabHelper::FromWebContents(web_contents);
1477 translate_tab_helper->language_state().translate_enabled();
1479 command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE, enabled);
1480 translate_icon_view_->SetVisible(enabled);
1483 #if defined(OS_WIN) && !defined(USE_AURA)
1484 void LocationBarView::OnMouseEvent(const ui::MouseEvent& event, UINT msg) {
1485 OmniboxViewWin* omnibox_win = GetOmniboxViewWin(location_entry_.get());
1487 UINT flags = event.native_event().wParam;
1488 gfx::Point screen_point(event.location());
1489 ConvertPointToScreen(this, &screen_point);
1490 omnibox_win->HandleExternalMsg(msg, flags, screen_point.ToPOINT());
1495 bool LocationBarView::HasValidSuggestText() const {
1496 return suggested_text_view_->visible() &&
1497 !suggested_text_view_->size().IsEmpty();
1500 void LocationBarView::ShowFirstRunBubbleInternal() {
1501 #if !defined(OS_CHROMEOS)
1502 // First run bubble doesn't make sense for Chrome OS.
1503 Browser* browser = GetBrowserFromDelegate(delegate_);
1505 return; // Possible when browser is shutting down.
1507 FirstRunBubble::ShowBubble(browser, location_icon_view_);
1511 void LocationBarView::PaintPageActionBackgrounds(gfx::Canvas* canvas) {
1512 WebContents* web_contents = GetWebContents();
1513 // web_contents may be NULL while the browser is shutting down.
1517 const int32 tab_id = SessionID::IdForTab(web_contents);
1518 const ToolbarModel::SecurityLevel security_level =
1519 GetToolbarModel()->GetSecurityLevel(false);
1520 const SkColor text_color = GetColor(security_level, TEXT);
1521 const SkColor background_color = GetColor(security_level, BACKGROUND);
1523 for (PageActionViews::const_iterator
1524 page_action_view = page_action_views_.begin();
1525 page_action_view != page_action_views_.end();
1526 ++page_action_view) {
1527 gfx::Rect bounds = (*page_action_view)->bounds();
1528 int horizontal_padding =
1529 GetItemPadding() - GetBuiltInHorizontalPaddingForChildViews();
1530 // Make the bounding rectangle include the whole vertical range of the
1531 // location bar, and the mid-point pixels between adjacent page actions.
1533 // For odd horizontal_paddings, "horizontal_padding + 1" includes the
1534 // mid-point between two page actions in the bounding rectangle. For even
1535 // paddings, the +1 is dropped, which is right since there is no pixel at
1537 bounds.Inset(-(horizontal_padding + 1) / 2, 0);
1538 location_bar_util::PaintExtensionActionBackground(
1539 *(*page_action_view)->image_view()->page_action(),
1540 tab_id, canvas, bounds, text_color, background_color);
1544 void LocationBarView::AccessibilitySetValue(const string16& new_value) {
1545 location_entry_->SetUserText(new_value);