blob: 61774fa6f9bd49ee8c2d05cd9467d0080c20373f [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_icon_view.h"
#include "chrome/browser/extensions/extension_ui_util.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/page_info/page_info_dialog.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/page_info/page_info_bubble_view.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/omnibox/browser/omnibox_field_trial.h"
#include "components/omnibox/browser/toolbar_model.h"
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "extensions/common/constants.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/label.h"
using content::WebContents;
LocationIconView::LocationIconView(const gfx::FontList& font_list,
Delegate* delegate)
: IconLabelBubbleView(font_list), delegate_(delegate) {
label()->SetElideBehavior(gfx::ELIDE_MIDDLE);
set_id(VIEW_ID_LOCATION_ICON);
Update();
SetUpForInOutAnimation();
}
LocationIconView::~LocationIconView() {
}
gfx::Size LocationIconView::GetMinimumSize() const {
return GetMinimumSizeForPreferredSize(GetPreferredSize());
}
bool LocationIconView::OnMousePressed(const ui::MouseEvent& event) {
delegate_->OnLocationIconPressed(event);
IconLabelBubbleView::OnMousePressed(event);
return true;
}
bool LocationIconView::OnMouseDragged(const ui::MouseEvent& event) {
delegate_->OnLocationIconDragged(event);
return IconLabelBubbleView::OnMouseDragged(event);
}
bool LocationIconView::GetTooltipText(const gfx::Point& p,
base::string16* tooltip) const {
if (show_tooltip_)
*tooltip = l10n_util::GetStringUTF16(IDS_TOOLTIP_LOCATION_ICON);
return show_tooltip_;
}
SkColor LocationIconView::GetTextColor() const {
return delegate_->GetSecurityChipColor(
delegate_->GetToolbarModel()->GetSecurityLevel(false));
}
bool LocationIconView::ShouldShowSeparator() const {
if (ShouldShowLabel())
return true;
if (OmniboxFieldTrial::IsJogTextfieldOnPopupEnabled())
return false;
return !delegate_->IsEditingOrEmpty();
}
bool LocationIconView::ShouldShowExtraEndSpace() const {
if (OmniboxFieldTrial::IsJogTextfieldOnPopupEnabled())
return false;
return delegate_->IsEditingOrEmpty();
}
bool LocationIconView::ShowBubble(const ui::Event& event) {
return delegate_->ShowPageInfoDialog();
}
SkColor LocationIconView::GetInkDropBaseColor() const {
return delegate_->GetLocationIconInkDropColor();
}
void LocationIconView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
if (delegate_->IsEditingOrEmpty()) {
node_data->role = ax::mojom::Role::kImage;
node_data->SetName(l10n_util::GetStringUTF8(IDS_ACC_SEARCH_ICON));
return;
}
security_state::SecurityLevel security_level =
delegate_->GetToolbarModel()->GetSecurityLevel(false);
if (label()->text().empty() && (security_level == security_state::EV_SECURE ||
security_level == security_state::SECURE)) {
node_data->AddStringAttribute(
ax::mojom::StringAttribute::kDescription,
l10n_util::GetStringUTF8(IDS_SECURE_VERBOSE_STATE));
}
IconLabelBubbleView::GetAccessibleNodeData(node_data);
node_data->role = ax::mojom::Role::kPopUpButton;
}
bool LocationIconView::IsBubbleShowing() const {
return PageInfoBubbleView::GetShownBubbleType() !=
PageInfoBubbleView::BUBBLE_NONE;
}
int LocationIconView::GetMinimumLabelTextWidth() const {
int width = 0;
base::string16 text = GetText();
if (text == label()->text()) {
// Optimize this common case by not creating a new label.
// GetPreferredSize is not dependent on the label's current
// width, so this returns the same value as the branch below.
width = label()->GetPreferredSize().width();
} else {
views::Label label(text, {font_list()});
width = label.GetPreferredSize().width();
}
return GetMinimumSizeForPreferredSize(GetSizeForLabelWidth(width)).width();
}
bool LocationIconView::ShouldShowText() const {
const auto* toolbar_model = delegate_->GetToolbarModel();
if (!toolbar_model->input_in_progress()) {
const GURL& url = toolbar_model->GetURL();
if (url.SchemeIs(content::kChromeUIScheme) ||
url.SchemeIs(extensions::kExtensionScheme) ||
url.SchemeIs(url::kFileScheme))
return true;
}
return !toolbar_model->GetSecureVerboseText().empty();
}
base::string16 LocationIconView::GetText() const {
if (delegate_->GetToolbarModel()->GetURL().SchemeIs(content::kChromeUIScheme))
return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
if (delegate_->GetToolbarModel()->GetURL().SchemeIs(url::kFileScheme))
return l10n_util::GetStringUTF16(IDS_OMNIBOX_FILE);
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(
delegate_->GetToolbarModel()->GetURL(),
delegate_->GetWebContents()->GetBrowserContext());
if (!extension_name.empty())
return extension_name;
}
return delegate_->GetToolbarModel()->GetSecureVerboseText();
}
bool LocationIconView::ShouldAnimateTextVisibilityChange() const {
using SecurityLevel = security_state::SecurityLevel;
SecurityLevel level = delegate_->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);
}
void LocationIconView::UpdateTextVisibility() {
SetLabel(GetText());
bool should_show = ShouldShowText();
if (!ShouldAnimateTextVisibilityChange())
ResetSlideAnimation(should_show);
else if (should_show)
AnimateIn(base::nullopt);
else
AnimateOut();
// The label text color may have changed.
OnNativeThemeChanged(GetNativeTheme());
}
void LocationIconView::UpdateIcon() {
// Cancel any previous outstanding icon requests, as they are now outdated.
icon_fetch_weak_ptr_factory_.InvalidateWeakPtrs();
gfx::ImageSkia icon = delegate_->GetLocationIcon(
base::BindOnce(&LocationIconView::OnIconFetched,
icon_fetch_weak_ptr_factory_.GetWeakPtr()));
SetImage(icon);
}
void LocationIconView::OnIconFetched(const gfx::Image& image) {
SetImage(image.AsImageSkia());
}
void LocationIconView::Update() {
UpdateTextVisibility();
UpdateIcon();
bool is_editing_or_empty = delegate_->IsEditingOrEmpty();
// The tooltip should be shown if we are not editing or empty.
show_tooltip_ = !is_editing_or_empty;
// If the omnibox is empty or editing, the user should not be able to left
// click on the icon. As such, the icon should not show a highlight or be
// focusable. Note: using the middle mouse to copy-and-paste should still
// work on the icon.
if (is_editing_or_empty) {
SetInkDropMode(InkDropMode::OFF);
SetFocusBehavior(FocusBehavior::NEVER);
return;
}
SetInkDropMode(InkDropMode::ON);
#if defined(OS_MACOSX)
SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
#else
SetFocusBehavior(FocusBehavior::ALWAYS);
#endif
last_update_security_level_ =
delegate_->GetToolbarModel()->GetSecurityLevel(false);
}
bool LocationIconView::IsTriggerableEvent(const ui::Event& event) {
if (delegate_->IsEditingOrEmpty())
return false;
if (event.IsMouseEvent()) {
if (event.AsMouseEvent()->IsOnlyMiddleMouseButton())
return false;
} else if (event.IsGestureEvent() && event.type() != ui::ET_GESTURE_TAP) {
return false;
}
return IconLabelBubbleView::IsTriggerableEvent(event);
}
double LocationIconView::WidthMultiplier() const {
return GetAnimationValue();
}
gfx::Size LocationIconView::GetMinimumSizeForPreferredSize(
gfx::Size size) const {
const int kMinCharacters = 10;
size.SetToMin(
GetSizeForLabelWidth(font_list().GetExpectedTextWidth(kMinCharacters)));
return size;
}
int LocationIconView::GetSlideDurationTime() const {
constexpr int kSlideDurationTimeMs = 150;
return kSlideDurationTimeMs;
}