Home | History | Annotate | Download | only in autofill
      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.
      4 
      5 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
      6 
      7 #include <algorithm>
      8 #include <utility>
      9 
     10 #include "base/logging.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
     13 #include "components/autofill/core/browser/autofill_popup_delegate.h"
     14 #include "content/public/browser/native_web_keyboard_event.h"
     15 #include "grit/webkit_resources.h"
     16 #include "third_party/WebKit/public/web/WebAutofillClient.h"
     17 #include "ui/base/events/event.h"
     18 #include "ui/base/text/text_elider.h"
     19 #include "ui/gfx/display.h"
     20 #include "ui/gfx/rect_conversions.h"
     21 #include "ui/gfx/screen.h"
     22 #include "ui/gfx/vector2d.h"
     23 
     24 using base::WeakPtr;
     25 using WebKit::WebAutofillClient;
     26 
     27 namespace autofill {
     28 namespace {
     29 
     30 // Used to indicate that no line is currently selected by the user.
     31 const int kNoSelection = -1;
     32 
     33 // Size difference between name and subtext in pixels.
     34 const int kLabelFontSizeDelta = -2;
     35 
     36 // The vertical height of each row in pixels.
     37 const size_t kRowHeight = 24;
     38 
     39 // The vertical height of a separator in pixels.
     40 const size_t kSeparatorHeight = 1;
     41 
     42 // The maximum amount of characters to display from either the name or subtext.
     43 const size_t kMaxTextLength = 15;
     44 
     45 #if !defined(OS_ANDROID)
     46 const size_t kNamePadding = AutofillPopupView::kNamePadding;
     47 const size_t kIconPadding = AutofillPopupView::kIconPadding;
     48 const size_t kEndPadding = AutofillPopupView::kEndPadding;
     49 const size_t kAutofillIconWidth = AutofillPopupView::kAutofillIconWidth;
     50 #endif
     51 
     52 struct DataResource {
     53   const char* name;
     54   int id;
     55 };
     56 
     57 const DataResource kDataResources[] = {
     58   { "americanExpressCC", IDR_AUTOFILL_CC_AMEX },
     59   { "dinersCC", IDR_AUTOFILL_CC_DINERS },
     60   { "discoverCC", IDR_AUTOFILL_CC_DISCOVER },
     61   { "genericCC", IDR_AUTOFILL_CC_GENERIC },
     62   { "jcbCC", IDR_AUTOFILL_CC_JCB },
     63   { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD },
     64   { "visaCC", IDR_AUTOFILL_CC_VISA },
     65 };
     66 
     67 }  // namespace
     68 
     69 // static
     70 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetOrCreate(
     71     WeakPtr<AutofillPopupControllerImpl> previous,
     72     WeakPtr<AutofillPopupDelegate> delegate,
     73     gfx::NativeView container_view,
     74     const gfx::RectF& element_bounds,
     75     base::i18n::TextDirection text_direction) {
     76   DCHECK(!previous.get() || previous->delegate_.get() == delegate.get());
     77 
     78   if (previous.get() && previous->container_view() == container_view &&
     79       previous->element_bounds() == element_bounds) {
     80     previous->ClearState();
     81     return previous;
     82   }
     83 
     84   if (previous.get())
     85     previous->Hide();
     86 
     87   AutofillPopupControllerImpl* controller =
     88       new AutofillPopupControllerImpl(
     89           delegate, container_view, element_bounds, text_direction);
     90   return controller->GetWeakPtr();
     91 }
     92 
     93 AutofillPopupControllerImpl::AutofillPopupControllerImpl(
     94     base::WeakPtr<AutofillPopupDelegate> delegate,
     95     gfx::NativeView container_view,
     96     const gfx::RectF& element_bounds,
     97     base::i18n::TextDirection text_direction)
     98     : view_(NULL),
     99       delegate_(delegate),
    100       container_view_(container_view),
    101       element_bounds_(element_bounds),
    102       text_direction_(text_direction),
    103       weak_ptr_factory_(this) {
    104   ClearState();
    105 #if !defined(OS_ANDROID)
    106   subtext_font_ = name_font_.DeriveFont(kLabelFontSizeDelta);
    107   warning_font_ = name_font_.DeriveFont(0, gfx::Font::ITALIC);
    108 #endif
    109 }
    110 
    111 AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {}
    112 
    113 void AutofillPopupControllerImpl::Show(
    114     const std::vector<string16>& names,
    115     const std::vector<string16>& subtexts,
    116     const std::vector<string16>& icons,
    117     const std::vector<int>& identifiers) {
    118   SetValues(names, subtexts, icons, identifiers);
    119 
    120 #if !defined(OS_ANDROID)
    121   // Android displays the long text with ellipsis using the view attributes.
    122 
    123   UpdatePopupBounds();
    124   int popup_width = popup_bounds().width();
    125 
    126   // Elide the name and subtext strings so that the popup fits in the available
    127   // space.
    128   for (size_t i = 0; i < names_.size(); ++i) {
    129     int name_width = GetNameFontForRow(i).GetStringWidth(names_[i]);
    130     int subtext_width = subtext_font().GetStringWidth(subtexts_[i]);
    131     int total_text_length = name_width + subtext_width;
    132 
    133     // The line can have no strings if it represents a UI element, such as
    134     // a separator line.
    135     if (total_text_length == 0)
    136       continue;
    137 
    138     int available_width = popup_width - RowWidthWithoutText(i);
    139 
    140     // Each field recieves space in proportion to its length.
    141     int name_size = available_width * name_width / total_text_length;
    142     names_[i] = ui::ElideText(names_[i],
    143                               GetNameFontForRow(i),
    144                               name_size,
    145                               ui::ELIDE_AT_END);
    146 
    147     int subtext_size = available_width * subtext_width / total_text_length;
    148     subtexts_[i] = ui::ElideText(subtexts_[i],
    149                                  subtext_font(),
    150                                  subtext_size,
    151                                  ui::ELIDE_AT_END);
    152   }
    153 #endif
    154 
    155   if (!view_) {
    156     view_ = AutofillPopupView::Create(this);
    157 
    158     // It is possible to fail to create the popup, in this case
    159     // treat the popup as hiding right away.
    160     if (!view_) {
    161       Hide();
    162       return;
    163     }
    164 
    165     ShowView();
    166   } else {
    167     UpdateBoundsAndRedrawPopup();
    168   }
    169 
    170   delegate_->OnPopupShown(this);
    171 }
    172 
    173 void AutofillPopupControllerImpl::UpdateDataListValues(
    174     const std::vector<base::string16>& values,
    175     const std::vector<base::string16>& labels) {
    176   // Remove all the old data list values, which should always be at the top of
    177   // the list if they are present.
    178   while (!identifiers_.empty() &&
    179          identifiers_[0] == WebAutofillClient::MenuItemIDDataListEntry) {
    180     names_.erase(names_.begin());
    181     subtexts_.erase(subtexts_.begin());
    182     icons_.erase(icons_.begin());
    183     identifiers_.erase(identifiers_.begin());
    184   }
    185 
    186   // If there are no new data list values, exit (clearing the separator if there
    187   // is one).
    188   if (values.empty()) {
    189     if (!identifiers_.empty() &&
    190         identifiers_[0] == WebAutofillClient::MenuItemIDSeparator) {
    191       names_.erase(names_.begin());
    192       subtexts_.erase(subtexts_.begin());
    193       icons_.erase(icons_.begin());
    194       identifiers_.erase(identifiers_.begin());
    195     }
    196 
    197      // The popup contents have changed, so either update the bounds or hide it.
    198     if (HasSuggestions())
    199       UpdateBoundsAndRedrawPopup();
    200     else
    201       Hide();
    202 
    203     return;
    204   }
    205 
    206   // Add a separator if there are any other values.
    207   if (!identifiers_.empty() &&
    208       identifiers_[0] != WebAutofillClient::MenuItemIDSeparator) {
    209     names_.insert(names_.begin(), string16());
    210     subtexts_.insert(subtexts_.begin(), string16());
    211     icons_.insert(icons_.begin(), string16());
    212     identifiers_.insert(identifiers_.begin(),
    213                         WebAutofillClient::MenuItemIDSeparator);
    214   }
    215 
    216 
    217   names_.insert(names_.begin(), values.begin(), values.end());
    218   subtexts_.insert(subtexts_.begin(), labels.begin(), labels.end());
    219 
    220   // Add the values that are the same for all data list elements.
    221   icons_.insert(icons_.begin(), values.size(), base::string16());
    222   identifiers_.insert(identifiers_.begin(),
    223                       values.size(),
    224                       WebAutofillClient::MenuItemIDDataListEntry);
    225 
    226   UpdateBoundsAndRedrawPopup();
    227 }
    228 
    229 void AutofillPopupControllerImpl::Hide() {
    230   if (delegate_.get())
    231     delegate_->OnPopupHidden(this);
    232 
    233   if (view_)
    234     view_->Hide();
    235 
    236   delete this;
    237 }
    238 
    239 void AutofillPopupControllerImpl::ViewDestroyed() {
    240   // The view has already been destroyed so clear the reference to it.
    241   view_ = NULL;
    242 
    243   Hide();
    244 }
    245 
    246 bool AutofillPopupControllerImpl::HandleKeyPressEvent(
    247     const content::NativeWebKeyboardEvent& event) {
    248   switch (event.windowsKeyCode) {
    249     case ui::VKEY_UP:
    250       SelectPreviousLine();
    251       return true;
    252     case ui::VKEY_DOWN:
    253       SelectNextLine();
    254       return true;
    255     case ui::VKEY_PRIOR:  // Page up.
    256       SetSelectedLine(0);
    257       return true;
    258     case ui::VKEY_NEXT:  // Page down.
    259       SetSelectedLine(names().size() - 1);
    260       return true;
    261     case ui::VKEY_ESCAPE:
    262       Hide();
    263       return true;
    264     case ui::VKEY_DELETE:
    265       return (event.modifiers & content::NativeWebKeyboardEvent::ShiftKey) &&
    266              RemoveSelectedLine();
    267     case ui::VKEY_TAB:
    268       // A tab press should cause the highlighted line to be selected, but still
    269       // return false so the tab key press propagates and changes the cursor
    270       // location.
    271       AcceptSelectedLine();
    272       return false;
    273     case ui::VKEY_RETURN:
    274       return AcceptSelectedLine();
    275     default:
    276       return false;
    277   }
    278 }
    279 
    280 void AutofillPopupControllerImpl::UpdateBoundsAndRedrawPopup() {
    281 #if !defined(OS_ANDROID)
    282   // TODO(csharp): Since UpdatePopupBounds can change the position of the popup,
    283   // the popup could end up jumping from above the element to below it.
    284   // It is unclear if it is better to keep the popup where it was, or if it
    285   // should try and move to its desired position.
    286   UpdatePopupBounds();
    287 #endif
    288 
    289   view_->UpdateBoundsAndRedrawPopup();
    290 }
    291 
    292 void AutofillPopupControllerImpl::MouseHovered(int x, int y) {
    293   SetSelectedLine(LineFromY(y));
    294 }
    295 
    296 void AutofillPopupControllerImpl::MouseClicked(int x, int y) {
    297   MouseHovered(x, y);
    298   AcceptSelectedLine();
    299 }
    300 
    301 void AutofillPopupControllerImpl::MouseExitedPopup() {
    302   SetSelectedLine(kNoSelection);
    303 }
    304 
    305 void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) {
    306   delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]);
    307 }
    308 
    309 int AutofillPopupControllerImpl::GetIconResourceID(
    310     const string16& resource_name) {
    311   for (size_t i = 0; i < arraysize(kDataResources); ++i) {
    312     if (resource_name == ASCIIToUTF16(kDataResources[i].name))
    313       return kDataResources[i].id;
    314   }
    315 
    316   return -1;
    317 }
    318 
    319 bool AutofillPopupControllerImpl::CanDelete(size_t index) const {
    320   // TODO(isherman): Native AddressBook suggestions on Mac and Android should
    321   // not be considered to be deleteable.
    322   int id = identifiers_[index];
    323   return id > 0 ||
    324       id == WebAutofillClient::MenuItemIDAutocompleteEntry ||
    325       id == WebAutofillClient::MenuItemIDPasswordEntry;
    326 }
    327 
    328 bool AutofillPopupControllerImpl::IsWarning(size_t index) const {
    329   return identifiers_[index] == WebAutofillClient::MenuItemIDWarningMessage;
    330 }
    331 
    332 gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) {
    333   int top = 0;
    334   for (size_t i = 0; i < index; ++i) {
    335     top += GetRowHeightFromId(identifiers()[i]);
    336   }
    337 
    338   return gfx::Rect(
    339       0,
    340       top,
    341       popup_bounds_.width(),
    342       GetRowHeightFromId(identifiers()[index]));
    343 }
    344 
    345 void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) {
    346   popup_bounds_ = bounds;
    347   UpdateBoundsAndRedrawPopup();
    348 }
    349 
    350 const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const {
    351   return popup_bounds_;
    352 }
    353 
    354 gfx::NativeView AutofillPopupControllerImpl::container_view() const {
    355   return container_view_;
    356 }
    357 
    358 const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const {
    359   return element_bounds_;
    360 }
    361 
    362 bool AutofillPopupControllerImpl::IsRTL() const {
    363   return text_direction_ == base::i18n::RIGHT_TO_LEFT;
    364 }
    365 
    366 const std::vector<string16>& AutofillPopupControllerImpl::names() const {
    367   return names_;
    368 }
    369 
    370 const std::vector<string16>& AutofillPopupControllerImpl::subtexts() const {
    371   return subtexts_;
    372 }
    373 
    374 const std::vector<string16>& AutofillPopupControllerImpl::icons() const {
    375   return icons_;
    376 }
    377 
    378 const std::vector<int>& AutofillPopupControllerImpl::identifiers() const {
    379   return identifiers_;
    380 }
    381 
    382 #if !defined(OS_ANDROID)
    383 const gfx::Font& AutofillPopupControllerImpl::GetNameFontForRow(size_t index)
    384     const {
    385   if (identifiers_[index] == WebAutofillClient::MenuItemIDWarningMessage)
    386     return warning_font_;
    387 
    388   return name_font_;
    389 }
    390 
    391 const gfx::Font& AutofillPopupControllerImpl::subtext_font() const {
    392   return subtext_font_;
    393 }
    394 #endif
    395 
    396 int AutofillPopupControllerImpl::selected_line() const {
    397   return selected_line_;
    398 }
    399 
    400 void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) {
    401   if (selected_line_ == selected_line)
    402     return;
    403 
    404   if (selected_line_ != kNoSelection &&
    405       static_cast<size_t>(selected_line_) < identifiers_.size())
    406     InvalidateRow(selected_line_);
    407 
    408   if (selected_line != kNoSelection)
    409     InvalidateRow(selected_line);
    410 
    411   selected_line_ = selected_line;
    412 
    413   if (selected_line_ != kNoSelection)
    414     delegate_->DidSelectSuggestion(identifiers_[selected_line_]);
    415   else
    416     delegate_->ClearPreviewedForm();
    417 }
    418 
    419 void AutofillPopupControllerImpl::SelectNextLine() {
    420   int new_selected_line = selected_line_ + 1;
    421 
    422   // Skip over any lines that can't be selected.
    423   while (static_cast<size_t>(new_selected_line) < names_.size() &&
    424          !CanAccept(identifiers()[new_selected_line])) {
    425     ++new_selected_line;
    426   }
    427 
    428   if (new_selected_line >= static_cast<int>(names_.size()))
    429     new_selected_line = 0;
    430 
    431   SetSelectedLine(new_selected_line);
    432 }
    433 
    434 void AutofillPopupControllerImpl::SelectPreviousLine() {
    435   int new_selected_line = selected_line_ - 1;
    436 
    437   // Skip over any lines that can't be selected.
    438   while (new_selected_line > kNoSelection &&
    439          !CanAccept(identifiers()[new_selected_line])) {
    440     --new_selected_line;
    441   }
    442 
    443   if (new_selected_line <= kNoSelection)
    444     new_selected_line = names_.size() - 1;
    445 
    446   SetSelectedLine(new_selected_line);
    447 }
    448 
    449 bool AutofillPopupControllerImpl::AcceptSelectedLine() {
    450   if (selected_line_ == kNoSelection)
    451     return false;
    452 
    453   DCHECK_GE(selected_line_, 0);
    454   DCHECK_LT(selected_line_, static_cast<int>(names_.size()));
    455 
    456   if (!CanAccept(identifiers_[selected_line_]))
    457     return false;
    458 
    459   AcceptSuggestion(selected_line_);
    460   return true;
    461 }
    462 
    463 bool AutofillPopupControllerImpl::RemoveSelectedLine() {
    464   if (selected_line_ == kNoSelection)
    465     return false;
    466 
    467   DCHECK_GE(selected_line_, 0);
    468   DCHECK_LT(selected_line_, static_cast<int>(names_.size()));
    469 
    470   if (!CanDelete(selected_line_))
    471     return false;
    472 
    473   delegate_->RemoveSuggestion(full_names_[selected_line_],
    474                               identifiers_[selected_line_]);
    475 
    476   // Remove the deleted element.
    477   names_.erase(names_.begin() + selected_line_);
    478   full_names_.erase(full_names_.begin() + selected_line_);
    479   subtexts_.erase(subtexts_.begin() + selected_line_);
    480   icons_.erase(icons_.begin() + selected_line_);
    481   identifiers_.erase(identifiers_.begin() + selected_line_);
    482 
    483   SetSelectedLine(kNoSelection);
    484 
    485   if (HasSuggestions()) {
    486     delegate_->ClearPreviewedForm();
    487     UpdateBoundsAndRedrawPopup();
    488   } else {
    489     Hide();
    490   }
    491 
    492   return true;
    493 }
    494 
    495 int AutofillPopupControllerImpl::LineFromY(int y) {
    496   int current_height = 0;
    497 
    498   for (size_t i = 0; i < identifiers().size(); ++i) {
    499     current_height += GetRowHeightFromId(identifiers()[i]);
    500 
    501     if (y <= current_height)
    502       return i;
    503   }
    504 
    505   // The y value goes beyond the popup so stop the selection at the last line.
    506   return identifiers().size() - 1;
    507 }
    508 
    509 int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const {
    510   if (identifier == WebAutofillClient::MenuItemIDSeparator)
    511     return kSeparatorHeight;
    512 
    513   return kRowHeight;
    514 }
    515 
    516 bool AutofillPopupControllerImpl::CanAccept(int id) {
    517   return id != WebAutofillClient::MenuItemIDSeparator &&
    518       id != WebAutofillClient::MenuItemIDWarningMessage;
    519 }
    520 
    521 bool AutofillPopupControllerImpl::HasSuggestions() {
    522   return identifiers_.size() != 0 &&
    523       (identifiers_[0] > 0 ||
    524        identifiers_[0] ==
    525            WebAutofillClient::MenuItemIDAutocompleteEntry ||
    526        identifiers_[0] == WebAutofillClient::MenuItemIDPasswordEntry ||
    527        identifiers_[0] == WebAutofillClient::MenuItemIDDataListEntry);
    528 }
    529 
    530 void AutofillPopupControllerImpl::SetValues(
    531     const std::vector<string16>& names,
    532     const std::vector<string16>& subtexts,
    533     const std::vector<string16>& icons,
    534     const std::vector<int>& identifiers) {
    535   names_ = names;
    536   full_names_ = names;
    537   subtexts_ = subtexts;
    538   icons_ = icons;
    539   identifiers_ = identifiers;
    540 }
    541 
    542 void AutofillPopupControllerImpl::ShowView() {
    543   view_->Show();
    544 }
    545 
    546 void AutofillPopupControllerImpl::InvalidateRow(size_t row) {
    547   DCHECK(0 <= row);
    548   DCHECK(row < identifiers_.size());
    549   view_->InvalidateRow(row);
    550 }
    551 
    552 #if !defined(OS_ANDROID)
    553 int AutofillPopupControllerImpl::GetDesiredPopupWidth() const {
    554   if (!name_font_.platform_font() || !subtext_font_.platform_font()) {
    555     // We can't calculate the size of the popup if the fonts
    556     // aren't present.
    557     return 0;
    558   }
    559 
    560   int popup_width = RoundedElementBounds().width();
    561   DCHECK_EQ(names().size(), subtexts().size());
    562   for (size_t i = 0; i < names().size(); ++i) {
    563     int row_size = name_font_.GetStringWidth(names()[i]) +
    564         subtext_font_.GetStringWidth(subtexts()[i]) +
    565         RowWidthWithoutText(i);
    566 
    567     popup_width = std::max(popup_width, row_size);
    568   }
    569 
    570   return popup_width;
    571 }
    572 
    573 int AutofillPopupControllerImpl::GetDesiredPopupHeight() const {
    574   int popup_height = 0;
    575 
    576   for (size_t i = 0; i < identifiers().size(); ++i) {
    577     popup_height += GetRowHeightFromId(identifiers()[i]);
    578   }
    579 
    580   return popup_height;
    581 }
    582 
    583 int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const {
    584   int row_size = kEndPadding;
    585 
    586   if (!subtexts_[row].empty())
    587     row_size += kNamePadding;
    588 
    589   // Add the Autofill icon size, if required.
    590   if (!icons_[row].empty())
    591     row_size += kAutofillIconWidth + kIconPadding;
    592 
    593   // Add the padding at the end
    594   row_size += kEndPadding;
    595 
    596   return row_size;
    597 }
    598 
    599 void AutofillPopupControllerImpl::UpdatePopupBounds() {
    600   int popup_required_width = GetDesiredPopupWidth();
    601   int popup_height = GetDesiredPopupHeight();
    602   // This is the top left point of the popup if the popup is above the element
    603   // and grows to the left (since that is the highest and furthest left the
    604   // popup go could).
    605   gfx::Point top_left_corner_of_popup = RoundedElementBounds().origin() +
    606       gfx::Vector2d(RoundedElementBounds().width() - popup_required_width,
    607                     -popup_height);
    608 
    609   // This is the bottom right point of the popup if the popup is below the
    610   // element and grows to the right (since the is the lowest and furthest right
    611   // the popup could go).
    612   gfx::Point bottom_right_corner_of_popup = RoundedElementBounds().origin() +
    613       gfx::Vector2d(popup_required_width,
    614                     RoundedElementBounds().height() + popup_height);
    615 
    616   gfx::Display top_left_display = GetDisplayNearestPoint(
    617       top_left_corner_of_popup);
    618   gfx::Display bottom_right_display = GetDisplayNearestPoint(
    619       bottom_right_corner_of_popup);
    620 
    621   std::pair<int, int> popup_x_and_width = CalculatePopupXAndWidth(
    622       top_left_display, bottom_right_display, popup_required_width);
    623   std::pair<int, int> popup_y_and_height = CalculatePopupYAndHeight(
    624       top_left_display, bottom_right_display, popup_height);
    625 
    626   popup_bounds_ = gfx::Rect(popup_x_and_width.first,
    627                             popup_y_and_height.first,
    628                             popup_x_and_width.second,
    629                             popup_y_and_height.second);
    630 }
    631 #endif  // !defined(OS_ANDROID)
    632 
    633 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() {
    634   return weak_ptr_factory_.GetWeakPtr();
    635 }
    636 
    637 void AutofillPopupControllerImpl::ClearState() {
    638   // Don't clear view_, because otherwise the popup will have to get regenerated
    639   // and this will cause flickering.
    640 
    641   popup_bounds_ = gfx::Rect();
    642 
    643   names_.clear();
    644   subtexts_.clear();
    645   icons_.clear();
    646   identifiers_.clear();
    647   full_names_.clear();
    648 
    649   selected_line_ = kNoSelection;
    650 }
    651 
    652 const gfx::Rect AutofillPopupControllerImpl::RoundedElementBounds() const {
    653   return gfx::ToEnclosingRect(element_bounds_);
    654 }
    655 
    656 gfx::Display AutofillPopupControllerImpl::GetDisplayNearestPoint(
    657     const gfx::Point& point) const {
    658   return gfx::Screen::GetScreenFor(container_view())->GetDisplayNearestPoint(
    659       point);
    660 }
    661 
    662 std::pair<int, int> AutofillPopupControllerImpl::CalculatePopupXAndWidth(
    663     const gfx::Display& left_display,
    664     const gfx::Display& right_display,
    665     int popup_required_width) const {
    666   int leftmost_display_x = left_display.bounds().x();
    667   int rightmost_display_x =
    668       right_display.GetSizeInPixel().width() + right_display.bounds().x();
    669 
    670   // Calculate the start coordinates for the popup if it is growing right or
    671   // the end position if it is growing to the left, capped to screen space.
    672   int right_growth_start = std::max(leftmost_display_x,
    673                                     std::min(rightmost_display_x,
    674                                              RoundedElementBounds().x()));
    675   int left_growth_end = std::max(leftmost_display_x,
    676                                    std::min(rightmost_display_x,
    677                                             RoundedElementBounds().right()));
    678 
    679   int right_available = rightmost_display_x - right_growth_start;
    680   int left_available = left_growth_end - leftmost_display_x;
    681 
    682   int popup_width = std::min(popup_required_width,
    683                              std::max(right_available, left_available));
    684 
    685   // If there is enough space for the popup on the right, show it there,
    686   // otherwise choose the larger size.
    687   if (right_available >= popup_width || right_available >= left_available)
    688     return std::make_pair(right_growth_start, popup_width);
    689   else
    690     return std::make_pair(left_growth_end - popup_width, popup_width);
    691 }
    692 
    693 std::pair<int,int> AutofillPopupControllerImpl::CalculatePopupYAndHeight(
    694     const gfx::Display& top_display,
    695     const gfx::Display& bottom_display,
    696     int popup_required_height) const {
    697   int topmost_display_y = top_display.bounds().y();
    698   int bottommost_display_y =
    699       bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y();
    700 
    701   // Calculate the start coordinates for the popup if it is growing down or
    702   // the end position if it is growing up, capped to screen space.
    703   int top_growth_end = std::max(topmost_display_y,
    704                                 std::min(bottommost_display_y,
    705                                          RoundedElementBounds().y()));
    706   int bottom_growth_start = std::max(topmost_display_y,
    707       std::min(bottommost_display_y, RoundedElementBounds().bottom()));
    708 
    709   int top_available = bottom_growth_start - topmost_display_y;
    710   int bottom_available = bottommost_display_y - top_growth_end;
    711 
    712   // TODO(csharp): Restrict the popup height to what is available.
    713   if (bottom_available >= popup_required_height ||
    714       bottom_available >= top_available) {
    715     // The popup can appear below the field.
    716     return std::make_pair(bottom_growth_start, popup_required_height);
    717   } else {
    718     // The popup must appear above the field.
    719     return std::make_pair(top_growth_end - popup_required_height,
    720                           popup_required_height);
    721   }
    722 }
    723 
    724 }  // namespace autofill
    725