blob: d6f1959503feab764e5ae60c3a48fa839e729a90 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include <algorithm>
#include <map>
#include <memory>
#include "base/i18n/rtl.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
#include "chrome/browser/extensions/extension_ui_util.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ssl/security_state_tab_helper.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/browser/translate/translate_service.h"
#include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
#include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
#include "chrome/browser/ui/find_bar/find_bar.h"
#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
#include "chrome/browser/ui/omnibox/omnibox_theme.h"
#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
#include "chrome/browser/ui/views/chrome_platform_style.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
#include "chrome/browser/ui/views/harmony/chrome_typography.h"
#include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
#include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
#include "chrome/browser/ui/views/location_bar/find_bar_icon.h"
#include "chrome/browser/ui/views/location_bar/keyword_hint_view.h"
#include "chrome/browser/ui/views/location_bar/location_bar_layout.h"
#include "chrome/browser/ui/views/location_bar/location_icon_view.h"
#include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
#include "chrome/browser/ui/views/location_bar/star_view.h"
#include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
#include "chrome/browser/ui/views/location_bar/zoom_view.h"
#include "chrome/browser/ui/views/page_action/page_action_icon_container_view.h"
#include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
#include "chrome/browser/ui/views/page_info/page_info_bubble_view.h"
#include "chrome/browser/ui/views/passwords/manage_passwords_icon_views.h"
#include "chrome/browser/ui/views/translate/translate_bubble_view.h"
#include "chrome/browser/ui/views/translate/translate_icon_view.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/bookmarks/common/bookmark_pref_names.h"
#include "components/favicon/content/content_favicon_driver.h"
#include "components/omnibox/browser/omnibox_popup_model.h"
#include "components/omnibox/browser/omnibox_popup_view.h"
#include "components/omnibox/browser/vector_icons.h"
#include "components/prefs/pref_service.h"
#include "components/search_engines/template_url.h"
#include "components/search_engines/template_url_service.h"
#include "components/security_state/core/security_state.h"
#include "components/toolbar/toolbar_model.h"
#include "components/toolbar/vector_icons.h"
#include "components/translate/core/browser/language_state.h"
#include "components/variations/variations_associated_data.h"
#include "components/zoom/zoom_controller.h"
#include "components/zoom/zoom_event_manager.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/feature_switch.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_keyboard_controller.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/events/event.h"
#include "ui/gfx/animation/slide_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/text_utils.h"
#include "ui/gfx/vector_icon_types.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/button_drag_utils.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/label.h"
#include "ui/views/widget/widget.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/ui/views/location_bar/intent_picker_view.h"
#endif
using content::WebContents;
using views::View;
namespace {
bool InTouchableMode() {
return ui::MaterialDesignController::IsTouchOptimizedUiEnabled();
}
// Returns true when a views::FocusRing should be used.
bool ShouldUseFocusRingView(bool show_focus_ring) {
return (show_focus_ring && LocationBarView::IsRounded()) ||
ChromePlatformStyle::ShouldOmniboxUseFocusRing();
}
// Installs a focus ring on the LocationBarView if it's focused and returns it.
views::View* InstallFocusRing(LocationBarView* view) {
if (!view->HasFocus())
return nullptr;
return views::FocusRing::Install(
view, view->GetColor(OmniboxPart::LOCATION_BAR_FOCUS_RING),
view->GetBorderRadius());
}
views::View* UninstallFocusRing(LocationBarView* view) {
// This should be a no-op if the focus ring doesn't exist.
views::FocusRing::Uninstall(view);
return nullptr;
}
// Helper function to create a rounded rect background (no stroke).
std::unique_ptr<views::Background> CreateRoundRectBackground(SkColor bg_color,
float radius) {
std::unique_ptr<views::Background> background = CreateBackgroundFromPainter(
views::Painter::CreateSolidRoundRectPainter(bg_color, radius));
background->SetNativeControlColor(bg_color);
return background;
}
} // namespace
// LocationBarView -----------------------------------------------------------
// static
const char LocationBarView::kViewClassName[] = "LocationBarView";
LocationBarView::LocationBarView(Browser* browser,
Profile* profile,
CommandUpdater* command_updater,
Delegate* delegate,
bool is_popup_mode)
: LocationBar(profile),
ChromeOmniboxEditController(command_updater),
browser_(browser),
delegate_(delegate),
is_popup_mode_(is_popup_mode),
tint_(GetTint()) {
edit_bookmarks_enabled_.Init(
bookmarks::prefs::kEditBookmarksEnabled, profile->GetPrefs(),
base::Bind(&LocationBarView::UpdateWithoutTabRestore,
base::Unretained(this)));
zoom::ZoomEventManager::GetForBrowserContext(profile)
->AddZoomEventManagerObserver(this);
}
LocationBarView::~LocationBarView() {
zoom::ZoomEventManager::GetForBrowserContext(profile())
->RemoveZoomEventManagerObserver(this);
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, public:
void LocationBarView::Init() {
// We need to be in a Widget, otherwise GetNativeTheme() may change and we're
// not prepared for that.
DCHECK(GetWidget());
// Note that children with layers are *not* clipped, because focus rings have
// to draw outside the parent's bounds.
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
const gfx::FontList& font_list = views::style::GetFont(
CONTEXT_OMNIBOX_PRIMARY, views::style::STYLE_PRIMARY);
location_icon_view_ = new LocationIconView(font_list, this);
location_icon_view_->set_drag_controller(this);
AddChildView(location_icon_view_);
// Initialize the Omnibox view.
omnibox_view_ = new OmniboxViewViews(
this, std::make_unique<ChromeOmniboxClient>(this, profile()),
is_popup_mode_, this, font_list);
omnibox_view_->Init();
AddChildView(omnibox_view_);
RefreshBackground();
// Initialize the inline autocomplete view which is visible only when IME is
// turned on. Use the same font with the omnibox and highlighted background.
ime_inline_autocomplete_view_ =
new views::Label(base::string16(), {font_list});
ime_inline_autocomplete_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
ime_inline_autocomplete_view_->SetAutoColorReadabilityEnabled(false);
ime_inline_autocomplete_view_->SetBackground(views::CreateSolidBackground(
GetColor(OmniboxPart::LOCATION_BAR_IME_AUTOCOMPLETE_BACKGROUND)));
ime_inline_autocomplete_view_->SetEnabledColor(
GetColor(OmniboxPart::LOCATION_BAR_IME_AUTOCOMPLETE_TEXT));
ime_inline_autocomplete_view_->SetVisible(false);
AddChildView(ime_inline_autocomplete_view_);
selected_keyword_view_ = new SelectedKeywordView(this, font_list, profile());
AddChildView(selected_keyword_view_);
keyword_hint_view_ = new KeywordHintView(this, profile(), tint());
AddChildView(keyword_hint_view_);
std::vector<std::unique_ptr<ContentSettingImageModel>> models =
ContentSettingImageModel::GenerateContentSettingImageModels();
for (auto& model : models) {
ContentSettingImageView* image_view =
new ContentSettingImageView(std::move(model), this, font_list);
content_setting_views_.push_back(image_view);
image_view->SetVisible(false);
AddChildView(image_view);
}
zoom_view_ = new ZoomView(delegate_, this);
page_action_icons_.push_back(zoom_view_);
manage_passwords_icon_view_ =
new ManagePasswordsIconViews(command_updater(), this);
page_action_icons_.push_back(manage_passwords_icon_view_);
if (browser_) {
save_credit_card_icon_view_ =
new autofill::SaveCardIconView(command_updater(), browser_, this);
page_action_icons_.push_back(save_credit_card_icon_view_);
}
translate_icon_view_ = new TranslateIconView(command_updater(), this);
page_action_icons_.push_back(translate_icon_view_);
#if defined(OS_CHROMEOS)
if (browser_)
page_action_icons_.push_back(intent_picker_view_ =
new IntentPickerView(browser_, this));
#endif
page_action_icons_.push_back(find_bar_icon_ = new FindBarIcon(this));
if (browser_) {
page_action_icons_.push_back(
star_view_ = new StarView(command_updater(), browser_, this));
}
std::for_each(page_action_icons_.begin(), page_action_icons_.end(),
[this](PageActionIconView* icon_view) -> void {
icon_view->Init();
icon_view->SetVisible(false);
AddChildView(icon_view);
});
page_action_icon_container_view_ = new PageActionIconContainerView();
AddChildView(page_action_icon_container_view_);
clear_all_button_ = views::CreateVectorImageButton(this);
clear_all_button_->SetTooltipText(
l10n_util::GetStringUTF16(IDS_OMNIBOX_CLEAR_ALL));
RefreshClearAllButtonIcon();
AddChildView(clear_all_button_);
// Initialize the location entry. We do this to avoid a black flash which is
// visible when the location entry has just been initialized.
Update(nullptr);
size_animation_.Reset(1);
}
bool LocationBarView::IsInitialized() const {
return omnibox_view_ != nullptr;
}
SkColor LocationBarView::GetColor(OmniboxPart part) const {
return GetOmniboxColor(part, tint());
}
SkColor LocationBarView::GetOpaqueBorderColor(bool incognito) const {
return color_utils::GetResultingPaintColor(
GetBorderColor(), ThemeProperties::GetDefaultColor(
ThemeProperties::COLOR_TOOLBAR, incognito));
}
// static
int LocationBarView::GetBorderThicknessDip() {
return IsRounded() ? 0 : BackgroundWith1PxBorder::kBorderThicknessDip;
}
// static
bool LocationBarView::IsRounded() {
return ui::MaterialDesignController::IsNewerMaterialUi();
}
float LocationBarView::GetBorderRadius() {
return IsRounded() ? ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
views::EMPHASIS_HIGH, size())
: GetLayoutConstant(LOCATION_BAR_BUBBLE_CORNER_RADIUS);
}
SkColor LocationBarView::GetSecurityChipColor(
security_state::SecurityLevel security_level) const {
// Only used in ChromeOS.
if (security_level == security_state::SECURE_WITH_POLICY_INSTALLED_CERT)
return GetColor(OmniboxPart::LOCATION_BAR_TEXT_DIMMED);
OmniboxPartState state = OmniboxPartState::CHIP_DEFAULT;
if (security_level == security_state::EV_SECURE ||
security_level == security_state::SECURE) {
state = OmniboxPartState::CHIP_SECURE;
} else if (security_level == security_state::DANGEROUS) {
state = OmniboxPartState::CHIP_DANGEROUS;
}
return GetOmniboxColor(OmniboxPart::LOCATION_BAR_SECURITY_CHIP, tint(),
state);
}
void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble) {
DCHECK(zoom_view_);
if (RefreshZoomView()) {
Layout();
SchedulePaint();
}
WebContents* web_contents = GetWebContents();
if (can_show_bubble && web_contents) {
ZoomBubbleView::ShowBubble(web_contents, gfx::Point(),
ZoomBubbleView::AUTOMATIC);
}
}
void LocationBarView::SetStarToggled(bool on) {
if (star_view_)
star_view_->SetToggled(on);
}
gfx::Point LocationBarView::GetOmniboxViewOrigin() const {
gfx::Point origin(omnibox_view_->origin());
origin.set_x(GetMirroredXInView(origin.x()));
views::View::ConvertPointToScreen(this, &origin);
return origin;
}
void LocationBarView::SetImeInlineAutocompletion(const base::string16& text) {
ime_inline_autocomplete_view_->SetText(text);
ime_inline_autocomplete_view_->SetVisible(!text.empty());
}
void LocationBarView::SetShowFocusRect(bool show) {
show_focus_rect_ = show;
focus_ring_ = ShouldUseFocusRingView(show) ? InstallFocusRing(this)
: UninstallFocusRing(this);
SchedulePaint();
}
void LocationBarView::SelectAll() {
omnibox_view_->SelectAll(true);
}
views::View* LocationBarView::GetSecurityBubbleAnchorView() {
if (ui::MaterialDesignController::IsSecondaryUiMaterial())
return this;
return location_icon_view()->GetImageView();
}
bool LocationBarView::ShowPageInfoDialog(WebContents* contents) {
DCHECK(contents);
content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
if (!entry)
return false;
SecurityStateTabHelper* helper =
SecurityStateTabHelper::FromWebContents(contents);
DCHECK(helper);
security_state::SecurityInfo security_info;
helper->GetSecurityInfo(&security_info);
DCHECK(GetWidget());
views::BubbleDialogDelegateView* bubble =
PageInfoBubbleView::CreatePageInfoBubble(
GetSecurityBubbleAnchorView(), gfx::Rect(),
GetWidget()->GetNativeWindow(), profile(), contents,
entry->GetVirtualURL(), security_info);
location_icon_view()->OnBubbleCreated(bubble->GetWidget());
bubble->GetWidget()->Show();
return true;
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, public LocationBar implementation:
void LocationBarView::FocusLocation(bool select_all) {
omnibox_view_->SetFocus();
if (select_all)
omnibox_view_->SelectAll(true);
}
void LocationBarView::Revert() {
omnibox_view_->RevertAll();
}
OmniboxView* LocationBarView::GetOmniboxView() {
return omnibox_view_;
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, public views::View implementation:
bool LocationBarView::HasFocus() const {
return omnibox_view_->model()->has_focus();
}
void LocationBarView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kGroup;
}
gfx::Size LocationBarView::CalculatePreferredSize() const {
// Compute minimum height.
gfx::Size min_size(0, GetLayoutConstant(LOCATION_BAR_HEIGHT));
if (!IsInitialized())
return min_size;
min_size.set_height(min_size.height() * size_animation_.GetCurrentValue());
// Compute width of omnibox-leading content.
const int edge_thickness = GetHorizontalEdgeThickness();
int leading_width = edge_thickness;
if (ShouldShowKeywordBubble()) {
// The selected keyword view can collapse completely.
} else if (ShouldShowLocationIconText()) {
leading_width +=
location_icon_view_->GetMinimumSizeForLabelText(GetLocationIconText())
.width();
} else {
leading_width += GetLayoutConstant(LOCATION_BAR_ELEMENT_PADDING) +
location_icon_view_->GetMinimumSize().width();
}
// Compute width of omnibox-trailing content.
int trailing_width = edge_thickness;
if (star_view_)
trailing_width += IncrementalMinimumWidth(star_view_);
trailing_width += IncrementalMinimumWidth(translate_icon_view_);
if (save_credit_card_icon_view_)
trailing_width += IncrementalMinimumWidth(save_credit_card_icon_view_);
trailing_width += IncrementalMinimumWidth(manage_passwords_icon_view_) +
IncrementalMinimumWidth(zoom_view_);
#if defined(OS_CHROMEOS)
if (intent_picker_view_)
trailing_width += IncrementalMinimumWidth(intent_picker_view_);
#endif // defined(OS_CHROMEOS)
for (auto i = content_setting_views_.begin();
i != content_setting_views_.end(); ++i) {
trailing_width += IncrementalMinimumWidth((*i));
}
min_size.set_width(leading_width + omnibox_view_->GetMinimumSize().width() +
2 * GetLayoutConstant(LOCATION_BAR_ELEMENT_PADDING) -
omnibox_view_->GetInsets().width() + trailing_width);
return min_size;
}
void LocationBarView::Layout() {
if (!IsInitialized())
return;
View::Layout();
selected_keyword_view_->SetVisible(false);
location_icon_view_->SetVisible(false);
keyword_hint_view_->SetVisible(false);
const int item_padding = GetLayoutConstant(LOCATION_BAR_ELEMENT_PADDING);
LocationBarLayout leading_decorations(
LocationBarLayout::LEFT_EDGE, item_padding,
item_padding - omnibox_view_->GetInsets().left());
LocationBarLayout trailing_decorations(LocationBarLayout::RIGHT_EDGE,
item_padding, item_padding);
const base::string16 keyword(omnibox_view_->model()->keyword());
// In some cases (e.g. fullscreen mode) we may have 0 height. We still want
// to position our child views in this case, because other things may be
// positioned relative to them (e.g. the "bookmark added" bubble if the user
// hits ctrl-d).
const int vertical_padding = GetTotalVerticalPadding();
const int location_height = std::max(height() - (vertical_padding * 2), 0);
// The largest fraction of the omnibox that can be taken by the EV or search
// label/chip.
const double kLeadingDecorationMaxFraction = 0.5;
location_icon_view_->SetLabel(base::string16());
if (ShouldShowKeywordBubble()) {
leading_decorations.AddDecoration(
vertical_padding, location_height, false, kLeadingDecorationMaxFraction,
item_padding, item_padding, selected_keyword_view_);
if (selected_keyword_view_->keyword() != keyword) {
selected_keyword_view_->SetKeyword(keyword);
const TemplateURL* template_url =
TemplateURLServiceFactory::GetForProfile(profile())->
GetTemplateURLForKeyword(keyword);
if (template_url &&
(template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)) {
gfx::Image image = extensions::OmniboxAPI::Get(profile())->
GetOmniboxIcon(template_url->GetExtensionId());
selected_keyword_view_->SetImage(image.AsImageSkia());
} else {
selected_keyword_view_->ResetImage();
}
}
} else if (ShouldShowLocationIconText()) {
location_icon_view_->SetLabel(GetLocationIconText());
leading_decorations.AddDecoration(
vertical_padding, location_height, false, kLeadingDecorationMaxFraction,
item_padding, item_padding, location_icon_view_);
} else {
leading_decorations.AddDecoration(vertical_padding, location_height,
location_icon_view_);
}
auto add_trailing_decoration = [&trailing_decorations, vertical_padding,
location_height, item_padding](View* view) {
if (view->visible()) {
trailing_decorations.AddDecoration(vertical_padding, location_height,
false, 0, item_padding, item_padding,
view);
}
};
if (star_view_)
add_trailing_decoration(star_view_);
add_trailing_decoration(zoom_view_);
add_trailing_decoration(find_bar_icon_);
#if defined(OS_CHROMEOS)
if (intent_picker_view_)
add_trailing_decoration(intent_picker_view_);
#endif
add_trailing_decoration(translate_icon_view_);
if (save_credit_card_icon_view_)
add_trailing_decoration(save_credit_card_icon_view_);
add_trailing_decoration(manage_passwords_icon_view_);
for (ContentSettingViews::const_reverse_iterator i(
content_setting_views_.rbegin());
i != content_setting_views_.rend(); ++i) {
add_trailing_decoration(*i);
}
// Because IMEs may eat the tab key, we don't show "press tab to search" while
// IME composition is in progress.
if (HasFocus() && !keyword.empty() &&
omnibox_view_->model()->is_keyword_hint() &&
!omnibox_view_->IsImeComposing()) {
trailing_decorations.AddDecoration(vertical_padding, location_height, true,
0, item_padding, item_padding,
keyword_hint_view_);
keyword_hint_view_->SetKeyword(keyword, GetOmniboxPopupView()->IsOpen(),
tint());
}
add_trailing_decoration(clear_all_button_);
const int edge_thickness = GetHorizontalEdgeThickness();
// Perform layout.
int full_width = width() - (2 * edge_thickness);
int entry_width = full_width;
leading_decorations.LayoutPass1(&entry_width);
trailing_decorations.LayoutPass1(&entry_width);
leading_decorations.LayoutPass2(&entry_width);
trailing_decorations.LayoutPass2(&entry_width);
int location_needed_width = omnibox_view_->GetTextWidth();
int available_width = entry_width - location_needed_width;
// The bounds must be wide enough for all the decorations to fit.
gfx::Rect location_bounds(edge_thickness, vertical_padding,
std::max(full_width, full_width - entry_width),
location_height);
leading_decorations.LayoutPass3(&location_bounds, &available_width);
trailing_decorations.LayoutPass3(&location_bounds, &available_width);
// |omnibox_view_| has an opaque background, so ensure it doesn't paint atop
// the rounded ends.
location_bounds.Intersect(GetLocalBoundsWithoutEndcaps());
entry_width = location_bounds.width();
// Layout |ime_inline_autocomplete_view_| next to the user input.
if (ime_inline_autocomplete_view_->visible()) {
int width =
gfx::GetStringWidth(ime_inline_autocomplete_view_->text(),
ime_inline_autocomplete_view_->font_list()) +
ime_inline_autocomplete_view_->GetInsets().width();
// All the target languages (IMEs) are LTR, and we do not need to support
// RTL so far. In other words, no testable RTL environment so far.
int x = location_needed_width;
if (width > entry_width)
x = 0;
else if (location_needed_width + width > entry_width)
x = entry_width - width;
location_bounds.set_width(x);
ime_inline_autocomplete_view_->SetBounds(
location_bounds.right(), location_bounds.y(),
std::min(width, entry_width), location_bounds.height());
}
omnibox_view_->SetBoundsRect(location_bounds);
}
void LocationBarView::OnThemeChanged() {
tint_ = GetTint();
}
void LocationBarView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
// ToolbarView::Init() adds |this| to the view hierarchy before initializing,
// which will trigger an early theme change.
if (!IsInitialized())
return;
RefreshBackground();
RefreshLocationIcon();
RefreshClearAllButtonIcon();
SchedulePaint();
}
void LocationBarView::Update(const WebContents* contents) {
RefreshContentSettingViews();
// TODO(calamity): Refactor Update to use PageActionIconView::Refresh.
RefreshZoomView();
RefreshPageActionIconViews();
// TODO(calamity): Refactor Update to use PageActionIconView::Refresh.
RefreshFindBarIcon();
if (star_view_) {
// TODO(calamity): Refactor Update to use PageActionIconView::Refresh.
UpdateBookmarkStarVisibility();
}
if (contents)
omnibox_view_->OnTabChanged(contents);
else
omnibox_view_->Update();
location_icon_view_->SetTextVisibility(
ShouldShowLocationIconText(),
!contents && ShouldAnimateLocationIconTextVisibilityChange());
OnChanged(); // NOTE: Calls Layout().
last_update_security_level_ = GetToolbarModel()->GetSecurityLevel(false);
}
void LocationBarView::ResetTabState(WebContents* contents) {
omnibox_view_->ResetTabState(contents);
}
bool LocationBarView::ActivateFirstInactiveBubbleForAccessibility() {
auto result = std::find_if(
page_action_icons_.begin(), page_action_icons_.end(),
[](PageActionIconView* view) {
if (!view || !view->visible() || !view->GetBubble())
return false;
views::Widget* widget = view->GetBubble()->GetWidget();
return widget && widget->IsVisible() && !widget->IsActive();
});
if (result != page_action_icons_.end())
(*result)->GetBubble()->GetWidget()->Show();
return result != page_action_icons_.end();
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, public OmniboxEditController implementation:
void LocationBarView::UpdateWithoutTabRestore() {
Update(nullptr);
}
ToolbarModel* LocationBarView::GetToolbarModel() {
return delegate_->GetToolbarModel();
}
WebContents* LocationBarView::GetWebContents() {
return delegate_->GetWebContents();
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, public ContentSettingImageView::Delegate implementation:
content::WebContents* LocationBarView::GetContentSettingWebContents() {
return GetToolbarModel()->input_in_progress() ? nullptr : GetWebContents();
}
ContentSettingBubbleModelDelegate*
LocationBarView::GetContentSettingBubbleModelDelegate() {
return delegate_->GetContentSettingBubbleModelDelegate();
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, public PageActionIconView::Delegate implementation:
WebContents* LocationBarView::GetWebContentsForPageActionIconView() {
return GetWebContents();
}
OmniboxTint LocationBarView::GetTint() {
ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile());
if (theme_service->UsingDefaultTheme()) {
return profile()->GetProfileType() == Profile::INCOGNITO_PROFILE
? OmniboxTint::DARK
: OmniboxTint::LIGHT;
}
// Check for GTK on Desktop Linux.
if (theme_service->IsSystemThemeDistinctFromDefaultTheme() &&
theme_service->UsingSystemTheme())
return OmniboxTint::NATIVE;
// TODO(tapted): Infer a tint from theme colors?
return OmniboxTint::LIGHT;
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, public static methods:
// static
bool LocationBarView::IsVirtualKeyboardVisible(views::Widget* widget) {
if (auto* input_method = widget->GetInputMethod()) {
return input_method->GetInputMethodKeyboardController()
->IsKeyboardVisible();
}
return false;
}
// static
int LocationBarView::GetAvailableTextHeight() {
return std::max(0, GetLayoutConstant(LOCATION_BAR_HEIGHT) -
2 * GetTotalVerticalPadding());
}
void LocationBarView::OnOmniboxFocused() {
if (ShouldUseFocusRingView(show_focus_rect_))
focus_ring_ = InstallFocusRing(this);
}
void LocationBarView::OnOmniboxBlurred() {
focus_ring_ = UninstallFocusRing(this);
}
// static
int LocationBarView::GetAvailableDecorationTextHeight() {
const int bubble_padding =
GetLayoutConstant(LOCATION_BAR_BUBBLE_VERTICAL_PADDING) +
GetLayoutConstant(LOCATION_BAR_BUBBLE_FONT_VERTICAL_PADDING);
return std::max(
0, LocationBarView::GetAvailableTextHeight() - (bubble_padding * 2));
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private:
int LocationBarView::IncrementalMinimumWidth(views::View* view) const {
return view->visible() ? (GetLayoutConstant(LOCATION_BAR_ELEMENT_PADDING) +
view->GetMinimumSize().width())
: 0;
}
SkColor LocationBarView::GetBorderColor() const {
return GetThemeProvider()->GetColor(
ThemeProperties::COLOR_LOCATION_BAR_BORDER);
}
gfx::Rect LocationBarView::GetLocalBoundsWithoutEndcaps() const {
const float device_scale_factor = layer()->device_scale_factor();
const int border_radius =
IsRounded()
? height() / 2
: gfx::ToCeiledInt(BackgroundWith1PxBorder::kLegacyBorderRadiusPx /
device_scale_factor);
gfx::Rect bounds_without_endcaps(GetLocalBounds());
bounds_without_endcaps.Inset(border_radius, 0);
return bounds_without_endcaps;
}
int LocationBarView::GetHorizontalEdgeThickness() const {
return is_popup_mode_ ? 0 : GetBorderThicknessDip();
}
void LocationBarView::RefreshBackground() {
SkColor background_color = GetColor(OmniboxPart::LOCATION_BAR_BACKGROUND);
SkColor border_color = GetBorderColor();
if (InTouchableMode()) {
// When the omnibox dropdown is open, match its color and remove the focus
// ring.
if (GetOmniboxPopupView()->IsOpen()) {
background_color = border_color =
GetColor(OmniboxPart::RESULTS_BACKGROUND);
}
if (focus_ring_)
focus_ring_->SetVisible(!GetOmniboxPopupView()->IsOpen());
}
if (is_popup_mode_) {
SetBackground(views::CreateSolidBackground(background_color));
} else if (GetBorderThicknessDip() == 0) {
SetBackground(
CreateRoundRectBackground(background_color, GetBorderRadius()));
} else {
SetBackground(std::make_unique<BackgroundWith1PxBorder>(background_color,
border_color));
}
// Keep the views::Textfield in sync. It needs an opaque background to
// correctly enable subpixel AA.
omnibox_view_->SetBackgroundColor(background_color);
omnibox_view_->EmphasizeURLComponents();
}
void LocationBarView::RefreshLocationIcon() {
// Cancel any previous outstanding icon requests, as they are now outdated.
icon_fetch_weak_ptr_factory_.InvalidateWeakPtrs();
security_state::SecurityLevel security_level =
GetToolbarModel()->GetSecurityLevel(false);
gfx::ImageSkia icon = omnibox_view_->GetIcon(
GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
GetSecurityChipColor(security_level),
base::BindOnce(&LocationBarView::OnLocationIconFetched,
icon_fetch_weak_ptr_factory_.GetWeakPtr()));
location_icon_view_->SetImage(icon);
location_icon_view_->Update();
}
void LocationBarView::OnLocationIconFetched(const gfx::Image& image) {
location_icon_view_->SetImage(image.AsImageSkia());
}
bool LocationBarView::RefreshContentSettingViews() {
if (extensions::HostedAppBrowserController::IsForExperimentalHostedAppBrowser(
browser_)) {
// For hosted apps, the location bar is normally hidden and icons appear in
// the window frame instead.
GetWidget()->non_client_view()->ResetWindowControls();
}
bool visibility_changed = false;
for (auto* v : content_setting_views_) {
const bool was_visible = v->visible();
v->Update();
if (was_visible != v->visible())
visibility_changed = true;
}
return visibility_changed;
}
bool LocationBarView::RefreshPageActionIconViews() {
if (extensions::HostedAppBrowserController::IsForExperimentalHostedAppBrowser(
browser_)) {
// For hosted apps, the location bar is normally hidden and icons appear in
// the window frame instead.
GetWidget()->non_client_view()->ResetWindowControls();
}
bool visibility_changed = false;
for (auto* v : page_action_icons_) {
visibility_changed |= v->Refresh();
}
return visibility_changed;
}
bool LocationBarView::RefreshZoomView() {
DCHECK(zoom_view_);
WebContents* web_contents = GetWebContents();
if (!web_contents)
return false;
const bool was_visible = zoom_view_->visible();
zoom_view_->Update(zoom::ZoomController::FromWebContents(web_contents));
return was_visible != zoom_view_->visible();
}
void LocationBarView::OnDefaultZoomLevelChanged() {
RefreshZoomView();
}
void LocationBarView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
DCHECK(event.IsMouseEvent() || event.IsGestureEvent());
if (keyword_hint_view_ == sender) {
omnibox_view_->model()->AcceptKeyword(
event.IsMouseEvent() ? KeywordModeEntryMethod::CLICK_ON_VIEW
: KeywordModeEntryMethod::TAP_ON_VIEW);
} else {
DCHECK_EQ(clear_all_button_, sender);
omnibox_view_->SetUserText(base::string16());
}
}
bool LocationBarView::RefreshFindBarIcon() {
// |browser_| may be nullptr since some unit tests pass it in for the
// Browser*. |browser_->window()| may return nullptr because Update() is
// called while BrowserWindow is being constructed.
if (!find_bar_icon_ || !browser_ || !browser_->window() ||
!browser_->HasFindBarController()) {
return false;
}
const bool was_visible = find_bar_icon_->visible();
find_bar_icon_->SetVisible(
browser_->GetFindBarController()->find_bar()->IsFindBarVisible());
return was_visible != find_bar_icon_->visible();
}
void LocationBarView::RefreshClearAllButtonIcon() {
const gfx::VectorIcon& icon =
InTouchableMode() ? omnibox::kTouchableClearIcon : kTabCloseNormalIcon;
SetImageFromVectorIcon(clear_all_button_, icon,
GetColor(OmniboxPart::LOCATION_BAR_CLEAR_ALL));
clear_all_button_->SetBorder(views::CreateEmptyBorder(
gfx::Insets(GetLayoutConstant(LOCATION_BAR_ICON_INTERIOR_PADDING))));
}
base::string16 LocationBarView::GetLocationIconText() const {
if (GetToolbarModel()->GetURL().SchemeIs(content::kChromeUIScheme))
return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
if (delegate_->GetWebContents()) {
// On ChromeOS, this can be called using web_contents from
// SimpleWebViewDialog::GetWebContents() which always returns null.
// TODO(crbug.com/680329) Remove the null check and make
// SimpleWebViewDialog::GetWebContents return the proper web contents
// instead.
const base::string16 extension_name =
extensions::ui_util::GetEnabledExtensionNameForUrl(
GetToolbarModel()->GetURL(),
delegate_->GetWebContents()->GetBrowserContext());
if (!extension_name.empty())
return extension_name;
}
return GetToolbarModel()->GetSecureVerboseText();
}
bool LocationBarView::ShouldShowKeywordBubble() const {
return !omnibox_view_->model()->keyword().empty() &&
!omnibox_view_->model()->is_keyword_hint();
}
bool LocationBarView::ShouldShowLocationIconText() const {
if (!GetToolbarModel()->input_in_progress() &&
(GetToolbarModel()->GetURL().SchemeIs(content::kChromeUIScheme) ||
GetToolbarModel()->GetURL().SchemeIs(extensions::kExtensionScheme)))
return true;
return !GetToolbarModel()->GetSecureVerboseText().empty();
}
bool LocationBarView::ShouldAnimateLocationIconTextVisibilityChange() const {
using SecurityLevel = security_state::SecurityLevel;
SecurityLevel level = GetToolbarModel()->GetSecurityLevel(false);
// Do not animate transitions from HTTP_SHOW_WARNING to DANGEROUS, since the
// transition can look confusing/messy.
if (level == SecurityLevel::DANGEROUS &&
last_update_security_level_ == SecurityLevel::HTTP_SHOW_WARNING)
return false;
return level == SecurityLevel::DANGEROUS ||
level == SecurityLevel::HTTP_SHOW_WARNING;
}
OmniboxPopupView* LocationBarView::GetOmniboxPopupView() {
DCHECK(IsInitialized());
return omnibox_view_->model()->popup_model()->view();
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private LocationBar implementation:
GURL LocationBarView::GetDestinationURL() const {
return destination_url();
}
WindowOpenDisposition LocationBarView::GetWindowOpenDisposition() const {
return disposition();
}
ui::PageTransition LocationBarView::GetPageTransition() const {
return transition();
}
void LocationBarView::AcceptInput() {
omnibox_view_->model()->AcceptInput(WindowOpenDisposition::CURRENT_TAB,
false);
}
void LocationBarView::FocusSearch() {
omnibox_view_->SetFocus();
omnibox_view_->EnterKeywordModeForDefaultSearchProvider();
}
void LocationBarView::UpdateContentSettingsIcons() {
if (RefreshContentSettingViews()) {
Layout();
SchedulePaint();
}
}
void LocationBarView::UpdateManagePasswordsIconAndBubble() {
if (manage_passwords_icon_view_->Refresh()) {
Layout();
SchedulePaint();
}
}
void LocationBarView::UpdateSaveCreditCardIcon() {
if (save_credit_card_icon_view_->Refresh()) {
Layout();
SchedulePaint();
}
}
void LocationBarView::UpdateFindBarIconVisibility() {
const bool visibility_changed = RefreshFindBarIcon();
if (visibility_changed) {
Layout();
SchedulePaint();
}
find_bar_icon_->SetActive(find_bar_icon_->visible(), visibility_changed);
}
void LocationBarView::UpdateBookmarkStarVisibility() {
if (star_view_) {
star_view_->SetVisible(
browser_defaults::bookmarks_enabled && !is_popup_mode_ &&
!GetToolbarModel()->input_in_progress() &&
edit_bookmarks_enabled_.GetValue() &&
!IsBookmarkStarHiddenByExtension());
}
}
void LocationBarView::UpdateZoomViewVisibility() {
RefreshZoomView();
OnChanged();
}
void LocationBarView::UpdateLocationBarVisibility(bool visible, bool animate) {
if (!animate) {
size_animation_.Reset(visible ? 1 : 0);
SetVisible(visible);
return;
}
if (visible) {
SetVisible(true);
size_animation_.Show();
} else {
size_animation_.Hide();
}
}
void LocationBarView::SaveStateToContents(WebContents* contents) {
omnibox_view_->SaveStateToTab(contents);
}
const OmniboxView* LocationBarView::GetOmniboxView() const {
return omnibox_view_;
}
LocationBarTesting* LocationBarView::GetLocationBarForTesting() {
return this;
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private LocationBarTesting implementation:
bool LocationBarView::GetBookmarkStarVisibility() {
DCHECK(star_view_);
return star_view_->visible();
}
bool LocationBarView::TestContentSettingImagePressed(size_t index) {
if (index >= content_setting_views_.size())
return false;
views::View* image_view = content_setting_views_[index];
image_view->SetSize(gfx::Size(24, 24));
image_view->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, ui::EF_NONE));
image_view->OnKeyReleased(
ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_SPACE, ui::EF_NONE));
return true;
}
bool LocationBarView::IsContentSettingBubbleShowing(size_t index) {
return index < content_setting_views_.size() &&
content_setting_views_[index]->IsBubbleShowing();
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private views::View implementation:
const char* LocationBarView::GetClassName() const {
return kViewClassName;
}
void LocationBarView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
OmniboxPopupView* popup = GetOmniboxPopupView();
if (popup->IsOpen())
popup->UpdatePopupAppearance();
RefreshBackground();
}
void LocationBarView::OnFocus() {
omnibox_view_->SetFocus();
}
void LocationBarView::OnPaint(gfx::Canvas* canvas) {
View::OnPaint(canvas);
if (show_focus_rect_ && omnibox_view_->HasFocus() && !focus_ring_) {
static_cast<BackgroundWith1PxBorder*>(background())
->PaintFocusRing(canvas, GetNativeTheme(), GetLocalBounds());
}
}
void LocationBarView::OnPaintBorder(gfx::Canvas* canvas) {
if (!is_popup_mode_)
return; // The border is painted by our Background.
gfx::Rect bounds(GetContentsBounds());
const SkColor border_color =
GetOpaqueBorderColor(profile()->IsOffTheRecord());
BrowserView::Paint1pxHorizontalLine(canvas, border_color, bounds, false);
BrowserView::Paint1pxHorizontalLine(canvas, border_color, bounds, true);
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private views::DragController implementation:
void LocationBarView::WriteDragDataForView(views::View* sender,
const gfx::Point& press_pt,
OSExchangeData* data) {
DCHECK_NE(GetDragOperationsForView(sender, press_pt),
ui::DragDropTypes::DRAG_NONE);
WebContents* web_contents = GetWebContents();
favicon::FaviconDriver* favicon_driver =
favicon::ContentFaviconDriver::FromWebContents(web_contents);
gfx::ImageSkia favicon = favicon_driver->GetFavicon().AsImageSkia();
button_drag_utils::SetURLAndDragImage(web_contents->GetURL(),
web_contents->GetTitle(), favicon,
nullptr, *sender->GetWidget(), data);
}
int LocationBarView::GetDragOperationsForView(views::View* sender,
const gfx::Point& p) {
DCHECK_EQ(location_icon_view_, sender);
WebContents* web_contents = delegate_->GetWebContents();
return (web_contents && web_contents->GetURL().is_valid() &&
(!GetOmniboxView()->IsEditingOrEmpty())) ?
(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK) :
ui::DragDropTypes::DRAG_NONE;
}
bool LocationBarView::CanStartDragForView(View* sender,
const gfx::Point& press_pt,
const gfx::Point& p) {
return true;
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private gfx::AnimationDelegate implementation:
void LocationBarView::AnimationProgressed(const gfx::Animation* animation) {
GetWidget()->non_client_view()->Layout();
}
void LocationBarView::AnimationEnded(const gfx::Animation* animation) {
AnimationProgressed(animation);
if (animation->GetCurrentValue() == 0)
SetVisible(false);
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private OmniboxEditController implementation:
void LocationBarView::OnChanged() {
RefreshLocationIcon();
location_icon_view_->set_show_tooltip(!GetOmniboxView()->IsEditingOrEmpty());
clear_all_button_->SetVisible(GetToolbarModel()->input_in_progress() &&
!omnibox_view_->text().empty() &&
IsVirtualKeyboardVisible(GetWidget()));
Layout();
SchedulePaint();
}
void LocationBarView::OnPopupVisibilityChanged() {
RefreshBackground();
}
const ToolbarModel* LocationBarView::GetToolbarModel() const {
return delegate_->GetToolbarModel();
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private DropdownBarHostDelegate implementation:
void LocationBarView::SetFocusAndSelection(bool select_all) {
FocusLocation(select_all);
}
////////////////////////////////////////////////////////////////////////////////
// LocationBarView, private static methods:
// static
int LocationBarView::GetTotalVerticalPadding() {
return GetBorderThicknessDip() +
GetLayoutConstant(LOCATION_BAR_ELEMENT_PADDING);
}