Chromium Code Reviews| 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 f1eafa70673fdf21ee99b7323aa1822b2c684237..df95d9787cc1b74c442061f1eb98c03f6e383538 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; |
| @@ -118,12 +125,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 |
| @@ -199,51 +229,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) { |
| @@ -506,3 +491,135 @@ void AutofillPopupControllerImpl::ShowView() { |
| void AutofillPopupControllerImpl::InvalidateRow(size_t row) { |
| view_->InvalidateRow(row); |
| } |
| + |
| +#if !defined(OS_ANDROID) |
| +int AutofillPopupControllerImpl::GetPopupRequiredWidth() { |
|
Ilya Sherman
2013/01/15 01:34:45
nit: Perhaps name this "GetDesiredPopupWidth()", s
csharp
2013/01/15 22:06:39
Done.
|
| + if (name_font_.platform_font() == NULL || |
|
Ilya Sherman
2013/01/15 01:34:45
nit: if (!name_font_.platform_font() || !name_subt
csharp
2013/01/15 22:06:39
Done.
|
| + 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 = 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::GetPopupRequiredHeight() { |
| + 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) { |
| + 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 = GetPopupRequiredWidth(); |
| + int popup_height = GetPopupRequiredHeight(); |
| + // This is the top left point if the popup is above the element and |
| + // grows to the left (since that is the highest and furthest left the |
| + // popup go could). |
|
Ilya Sherman
2013/01/15 01:34:45
nit: It's a little weird to describe top_left_corn
csharp
2013/01/15 22:06:39
Done.
|
| + gfx::Point top_left_corner_of_popup = element_bounds().origin() + |
| + gfx::Vector2d(element_bounds().width() - popup_required_width, |
| + -popup_height); |
| + gfx::Point bottom_right_corner_of_popup = element_bounds().origin() + |
| + gfx::Vector2d(popup_required_width, |
| + element_bounds().height() + popup_height); |
| + |
| + gfx::Screen* screen = |
| + gfx::Screen::GetScreenFor(container_view()); |
| + gfx::Display top_left_display = screen->GetDisplayNearestPoint( |
| + element_bounds().origin()); |
|
Ilya Sherman
2013/01/15 01:34:45
Hmm, why isn't this top_left_corner_of_popup?
csharp
2013/01/15 22:06:39
I blame a brain fart :) Fixed
|
| + gfx::Display bottom_right_display = screen->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) |
| + |
| +std::pair<int, int> AutofillPopupControllerImpl::CalculatePopupXAndWidth( |
| + const gfx::Display& left_display, |
| + const gfx::Display& right_display, |
| + int popup_required_width) { |
| + 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 leftmost and rightmost values the popup can have without |
|
Ilya Sherman
2013/01/15 01:34:45
nit: s/values/coordinates
csharp
2013/01/15 22:06:39
Done.
|
| + // going off the screen. |
| + int popup_left_cutoff = std::max(element_bounds().origin().x(), |
| + leftmost_display_x); |
| + int popup_right_cutoff = std::min(element_bounds().top_right().x(), |
| + rightmost_display_x); |
|
Ilya Sherman
2013/01/15 01:34:45
Optional nit: Mebbe drop the "popup_" prefix?
csharp
2013/01/15 22:06:39
Done.
|
| + |
| + int right_available = rightmost_display_x - popup_left_cutoff; |
| + int left_available = popup_right_cutoff - 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(popup_left_cutoff, popup_width); |
| + else |
| + return std::make_pair(popup_right_cutoff - popup_width, popup_width); |
| +} |
| + |
| +std::pair<int,int> AutofillPopupControllerImpl::CalculatePopupYAndHeight( |
| + const gfx::Display& top_display, |
| + const gfx::Display& bottom_display, |
| + int popup_required_height) { |
| + // Find the correct top position of the popup so that it doesn't go off |
| + // the screen. |
| + int bottom_display_y = bottom_display.GetSizeInPixel().height() + |
| + (bottom_display.bounds().y() * |
| + bottom_display.device_scale_factor()); |
| + int bottom_of_field = element_bounds().bottom(); |
| + |
| + if (bottom_display_y < bottom_of_field + popup_required_height) { |
| + // The popup must appear above the field. |
| + return std::make_pair(element_bounds().y() - popup_required_height, |
| + popup_required_height); |
| + } else { |
| + // The popup can appear below the field. |
| + return std::make_pair(bottom_of_field, popup_required_height); |
| + } |
| +} |