Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2985)

Unified Diff: chrome/browser/ui/autofill/autofill_popup_controller_impl.cc

Issue 11817051: Elide text in the new Autofill UI (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index 9c14c0b5111ecc32bb4dfa7248e7caa9a19759db..7e28e376c01d1f46981d08adedc6f8fedd9f4110 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
+#include <algorithm>
+#include <utility>
+
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/autofill/autofill_popup_delegate.h"
@@ -12,6 +15,10 @@
#include "grit/webkit_resources.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h"
#include "ui/base/events/event.h"
+#include "ui/base/text/text_elider.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/screen.h"
+#include "ui/gfx/vector2d.h"
using WebKit::WebAutofillClient;
@@ -111,6 +118,7 @@ void AutofillPopupControllerImpl::Show(
const std::vector<string16>& icons,
const std::vector<int>& identifiers) {
names_ = names;
+ full_names_ = names;
subtexts_ = subtexts;
icons_ = icons;
identifiers_ = identifiers;
@@ -118,12 +126,35 @@ void AutofillPopupControllerImpl::Show(
#if !defined(OS_ANDROID)
// Android displays the long text with ellipsis using the view attributes.
- // TODO(csharp): Fix crbug.com/156163 and use better logic when clipping.
+ UpdatePopupBounds();
+ int popup_width = popup_bounds().width();
+
+ // Elide the name and subtext strings so that the popup fits in the available
+ // space.
for (size_t i = 0; i < names_.size(); ++i) {
- if (names_[i].length() > 15)
- names_[i].erase(15);
- if (subtexts[i].length() > 15)
- subtexts_[i].erase(15);
+ int name_width = name_font().GetStringWidth(names_[i]);
+ int subtext_width = subtext_font().GetStringWidth(subtexts_[i]);
+ int total_text_length = name_width + subtext_width;
+
+ // The line can have no strings if it represents a UI element, such as
+ // a separator line.
+ if (total_text_length == 0)
+ continue;
+
+ int available_width = popup_width - RowWidthWithoutText(i);
+
+ // Each field recieves space in proportion to its length.
+ int name_size = available_width * name_width / total_text_length;
+ names_[i] = ui::ElideText(names_[i],
+ name_font(),
+ name_size,
+ ui::ELIDE_AT_END);
+
+ int subtext_size = available_width * subtext_width / total_text_length;
+ subtexts_[i] = ui::ElideText(subtexts_[i],
+ subtext_font(),
+ subtext_size,
+ ui::ELIDE_AT_END);
}
#endif
@@ -174,8 +205,11 @@ void AutofillPopupControllerImpl::ViewDestroyed() {
void AutofillPopupControllerImpl::UpdateBoundsAndRedrawPopup() {
#if !defined(OS_ANDROID)
- popup_bounds_.set_width(GetPopupRequiredWidth());
- popup_bounds_.set_height(GetPopupRequiredHeight());
+ // TODO(csharp): Since UpdatePopupBounds can change the position of the popup,
+ // the popup could end up jumping from above the element to below it.
+ // It is unclear if it is better to keep the popup where it was, or if it
+ // should try and move to its desired position.
+ UpdatePopupBounds();
#endif
view_->UpdateBoundsAndRedrawPopup();
@@ -205,7 +239,7 @@ void AutofillPopupControllerImpl::MouseExitedPopup() {
}
void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) {
- delegate_->DidAcceptSuggestion(names_[index], identifiers_[index]);
+ delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]);
}
int AutofillPopupControllerImpl::GetIconResourceID(
@@ -218,7 +252,7 @@ int AutofillPopupControllerImpl::GetIconResourceID(
return -1;
}
-bool AutofillPopupControllerImpl::CanDelete(size_t index) {
+bool AutofillPopupControllerImpl::CanDelete(size_t index) const {
// TODO(isherman): AddressBook suggestions on Mac should not be drawn as
// deleteable.
int id = identifiers_[index];
@@ -227,51 +261,6 @@ bool AutofillPopupControllerImpl::CanDelete(size_t index) {
id == WebAutofillClient::MenuItemIDPasswordEntry;
}
-#if !defined(OS_ANDROID)
-int AutofillPopupControllerImpl::GetPopupRequiredWidth() {
- if (name_font_.platform_font() == NULL ||
- subtext_font_.platform_font() == NULL) {
- // We can't calculate the size of the popup if the fonts
- // aren't present.
- return 0;
- }
-
- int popup_width = element_bounds().width();
- DCHECK_EQ(names().size(), subtexts().size());
- for (size_t i = 0; i < names().size(); ++i) {
- int row_size = kEndPadding +
- name_font_.GetStringWidth(names()[i]) +
- kNamePadding +
- subtext_font_.GetStringWidth(subtexts()[i]);
-
- // Add the Autofill icon size, if required.
- if (!icons()[i].empty())
- row_size += kAutofillIconWidth + kIconPadding;
-
- // Add delete icon, if required.
- if (CanDelete(i))
- row_size += kDeleteIconWidth + kIconPadding;
-
- // Add the padding at the end
- row_size += kEndPadding;
-
- popup_width = std::max(popup_width, row_size);
- }
-
- return popup_width;
-}
-
-int AutofillPopupControllerImpl::GetPopupRequiredHeight() {
- int popup_height = 0;
-
- for (size_t i = 0; i < identifiers().size(); ++i) {
- popup_height += GetRowHeightFromId(identifiers()[i]);
- }
-
- return popup_height;
-}
-#endif // !defined(OS_ANDROID)
-
gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) {
int top = 0;
for (size_t i = 0; i < index; ++i) {
@@ -421,11 +410,12 @@ bool AutofillPopupControllerImpl::RemoveSelectedLine() {
if (!CanDelete(selected_line_))
return false;
- delegate_->RemoveSuggestion(names_[selected_line_],
+ delegate_->RemoveSuggestion(full_names_[selected_line_],
identifiers_[selected_line_]);
// Remove the deleted element.
names_.erase(names_.begin() + selected_line_);
+ full_names_.erase(full_names_.begin() + selected_line_);
subtexts_.erase(subtexts_.begin() + selected_line_);
icons_.erase(icons_.begin() + selected_line_);
identifiers_.erase(identifiers_.begin() + selected_line_);
@@ -456,7 +446,7 @@ int AutofillPopupControllerImpl::LineFromY(int y) {
return identifiers().size() - 1;
}
-int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) {
+int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const {
if (identifier == WebAutofillClient::MenuItemIDSeparator)
return kSeparatorHeight;
@@ -476,7 +466,7 @@ bool AutofillPopupControllerImpl::DeleteIconIsUnder(int x, int y) {
}
gfx::Rect delete_icon_bounds = gfx::Rect(
- GetPopupRequiredWidth() - kDeleteIconWidth - kIconPadding,
+ popup_bounds().width() - kDeleteIconWidth - kIconPadding,
row_start_y + ((kRowHeight - kDeleteIconHeight) / 2),
kDeleteIconWidth,
kDeleteIconHeight);
@@ -506,3 +496,157 @@ void AutofillPopupControllerImpl::ShowView() {
void AutofillPopupControllerImpl::InvalidateRow(size_t row) {
view_->InvalidateRow(row);
}
+
+#if !defined(OS_ANDROID)
+int AutofillPopupControllerImpl::GetDesiredPopupWidth() const {
+ if (!name_font_.platform_font() || !subtext_font_.platform_font()) {
+ // We can't calculate the size of the popup if the fonts
+ // aren't present.
+ return 0;
+ }
+
+ int popup_width = element_bounds().width();
+ DCHECK_EQ(names().size(), subtexts().size());
+ for (size_t i = 0; i < names().size(); ++i) {
+ int row_size = name_font_.GetStringWidth(names()[i]) +
+ subtext_font_.GetStringWidth(subtexts()[i]) +
+ RowWidthWithoutText(i);
+
+ popup_width = std::max(popup_width, row_size);
+ }
+
+ return popup_width;
+}
+
+int AutofillPopupControllerImpl::GetDesiredPopupHeight() const {
+ int popup_height = 0;
+
+ for (size_t i = 0; i < identifiers().size(); ++i) {
+ popup_height += GetRowHeightFromId(identifiers()[i]);
+ }
+
+ return popup_height;
+}
+
+int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const {
+ int row_size = kEndPadding + kNamePadding;
+
+ // Add the Autofill icon size, if required.
+ if (!icons_[row].empty())
+ row_size += kAutofillIconWidth + kIconPadding;
+
+ // Add the delete icon size, if required.
+ if (CanDelete(row))
+ row_size += kDeleteIconWidth + kIconPadding;
+
+ // Add the padding at the end
+ row_size += kEndPadding;
+
+ return row_size;
+}
+
+void AutofillPopupControllerImpl::UpdatePopupBounds() {
+ int popup_required_width = GetDesiredPopupWidth();
+ int popup_height = GetDesiredPopupHeight();
+ // This is the top left point of the popup if the popup is above the element
+ // and grows to the left (since that is the highest and furthest left the
+ // popup go could).
+ gfx::Point top_left_corner_of_popup = element_bounds().origin() +
+ gfx::Vector2d(element_bounds().width() - popup_required_width,
+ -popup_height);
+
+ // This is the bottom right point of the popup if the popup is below the
+ // element and grows to the right (since the is the lowest and furthest right
+ // the popup could go).
+ gfx::Point bottom_right_corner_of_popup = element_bounds().origin() +
+ gfx::Vector2d(popup_required_width,
+ element_bounds().height() + popup_height);
+
+ gfx::Display top_left_display = GetDisplayNearestPoint(
+ top_left_corner_of_popup);
+ gfx::Display bottom_right_display = GetDisplayNearestPoint(
+ bottom_right_corner_of_popup);
+
+ std::pair<int, int> popup_x_and_width = CalculatePopupXAndWidth(
+ top_left_display, bottom_right_display, popup_required_width);
+ std::pair<int, int> popup_y_and_height = CalculatePopupYAndHeight(
+ top_left_display, bottom_right_display, popup_height);
+
+ popup_bounds_ = gfx::Rect(popup_x_and_width.first,
+ popup_y_and_height.first,
+ popup_x_and_width.second,
+ popup_y_and_height.second);
+}
+#endif // !defined(OS_ANDROID)
+
+gfx::Display AutofillPopupControllerImpl::GetDisplayNearestPoint(
+ const gfx::Point& point) const {
+ return gfx::Screen::GetScreenFor(container_view())->GetDisplayNearestPoint(
+ point);
+}
+
+std::pair<int, int> AutofillPopupControllerImpl::CalculatePopupXAndWidth(
+ const gfx::Display& left_display,
+ const gfx::Display& right_display,
+ int popup_required_width) const {
+ int leftmost_display_x = left_display.bounds().x() *
+ left_display.device_scale_factor();
+ int rightmost_display_x = right_display.GetSizeInPixel().width() +
+ right_display.bounds().x() * right_display.device_scale_factor();
+
+ // Calculate the start coordinates for the popup if it is growing right or
+ // the end position if it is growing to the left, capped to screen space.
+ int right_growth_start = std::max(leftmost_display_x,
+ std::min(rightmost_display_x,
+ element_bounds().x()));
+ int left_growth_end = std::max(leftmost_display_x,
+ std::min(rightmost_display_x,
+ element_bounds().right()));
+
+ int right_available = rightmost_display_x - right_growth_start;
+ int left_available = left_growth_end - leftmost_display_x;
+
+ int popup_width = std::min(popup_required_width,
+ std::max(right_available, left_available));
+
+ // If there is enough space for the popup on the right, show it there,
+ // otherwise choose the larger size.
+ if (right_available >= popup_width || right_available >= left_available)
+ return std::make_pair(right_growth_start, popup_width);
+ else
+ return std::make_pair(left_growth_end - popup_width, popup_width);
+}
+
+std::pair<int,int> AutofillPopupControllerImpl::CalculatePopupYAndHeight(
+ const gfx::Display& top_display,
+ const gfx::Display& bottom_display,
+ int popup_required_height) const {
+ int topmost_display_y = top_display.bounds().y() *
+ top_display.device_scale_factor();
+ int bottommost_display_y = bottom_display.GetSizeInPixel().height() +
+ (bottom_display.bounds().y() *
+ bottom_display.device_scale_factor());
+
+ // Calculate the start coordinates for the popup if it is growing down or
+ // the end position if it is growing up, capped to screen space.
+ int top_growth_end = std::max(topmost_display_y,
+ std::min(bottommost_display_y,
+ element_bounds().y()));
+ int bottom_growth_start = std::max(topmost_display_y,
+ std::min(bottommost_display_y,
+ element_bounds().bottom()));
+
+ int top_available = bottom_growth_start - topmost_display_y;
+ int bottom_available = bottommost_display_y - top_growth_end;
+
+ // TODO(csharp): Restrict the popup height to what is available.
+ if (bottom_available >= popup_required_height ||
+ bottom_available >= top_available) {
+ // The popup can appear below the field.
+ return std::make_pair(bottom_growth_start, popup_required_height);
+ } else {
+ // The popup must appear above the field.
+ return std::make_pair(top_growth_end - popup_required_height,
+ popup_required_height);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698