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