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
24using base::WeakPtr;
25using WebKit::WebAutofillClient;
26
27namespace autofill {
28namespace {
29
30// Used to indicate that no line is currently selected by the user.
31const int kNoSelection = -1;
32
33// Size difference between name and subtext in pixels.
34const int kLabelFontSizeDelta = -2;
35
36// The vertical height of each row in pixels.
37const size_t kRowHeight = 24;
38
39// The vertical height of a separator in pixels.
40const size_t kSeparatorHeight = 1;
41
42// The maximum amount of characters to display from either the name or subtext.
43const size_t kMaxTextLength = 15;
44
45#if !defined(OS_ANDROID)
46const size_t kNamePadding = AutofillPopupView::kNamePadding;
47const size_t kIconPadding = AutofillPopupView::kIconPadding;
48const size_t kEndPadding = AutofillPopupView::kEndPadding;
49const size_t kAutofillIconWidth = AutofillPopupView::kAutofillIconWidth;
50#endif
51
52struct DataResource {
53  const char* name;
54  int id;
55};
56
57const 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
70WeakPtr<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
93AutofillPopupControllerImpl::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
111AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {}
112
113void 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
173void 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
229void AutofillPopupControllerImpl::Hide() {
230  if (delegate_.get())
231    delegate_->OnPopupHidden(this);
232
233  if (view_)
234    view_->Hide();
235
236  delete this;
237}
238
239void AutofillPopupControllerImpl::ViewDestroyed() {
240  // The view has already been destroyed so clear the reference to it.
241  view_ = NULL;
242
243  Hide();
244}
245
246bool 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
280void 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
292void AutofillPopupControllerImpl::MouseHovered(int x, int y) {
293  SetSelectedLine(LineFromY(y));
294}
295
296void AutofillPopupControllerImpl::MouseClicked(int x, int y) {
297  MouseHovered(x, y);
298  AcceptSelectedLine();
299}
300
301void AutofillPopupControllerImpl::MouseExitedPopup() {
302  SetSelectedLine(kNoSelection);
303}
304
305void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) {
306  delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]);
307}
308
309int 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
319bool 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
328bool AutofillPopupControllerImpl::IsWarning(size_t index) const {
329  return identifiers_[index] == WebAutofillClient::MenuItemIDWarningMessage;
330}
331
332gfx::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
345void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) {
346  popup_bounds_ = bounds;
347  UpdateBoundsAndRedrawPopup();
348}
349
350const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const {
351  return popup_bounds_;
352}
353
354gfx::NativeView AutofillPopupControllerImpl::container_view() const {
355  return container_view_;
356}
357
358const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const {
359  return element_bounds_;
360}
361
362bool AutofillPopupControllerImpl::IsRTL() const {
363  return text_direction_ == base::i18n::RIGHT_TO_LEFT;
364}
365
366const std::vector<string16>& AutofillPopupControllerImpl::names() const {
367  return names_;
368}
369
370const std::vector<string16>& AutofillPopupControllerImpl::subtexts() const {
371  return subtexts_;
372}
373
374const std::vector<string16>& AutofillPopupControllerImpl::icons() const {
375  return icons_;
376}
377
378const std::vector<int>& AutofillPopupControllerImpl::identifiers() const {
379  return identifiers_;
380}
381
382#if !defined(OS_ANDROID)
383const 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
391const gfx::Font& AutofillPopupControllerImpl::subtext_font() const {
392  return subtext_font_;
393}
394#endif
395
396int AutofillPopupControllerImpl::selected_line() const {
397  return selected_line_;
398}
399
400void 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
419void 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
434void 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
449bool 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
463bool 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
495int 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
509int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const {
510  if (identifier == WebAutofillClient::MenuItemIDSeparator)
511    return kSeparatorHeight;
512
513  return kRowHeight;
514}
515
516bool AutofillPopupControllerImpl::CanAccept(int id) {
517  return id != WebAutofillClient::MenuItemIDSeparator &&
518      id != WebAutofillClient::MenuItemIDWarningMessage;
519}
520
521bool 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
530void 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
542void AutofillPopupControllerImpl::ShowView() {
543  view_->Show();
544}
545
546void 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)
553int 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
573int 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
583int 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
599void 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
633WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() {
634  return weak_ptr_factory_.GetWeakPtr();
635}
636
637void 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
652const gfx::Rect AutofillPopupControllerImpl::RoundedElementBounds() const {
653  return gfx::ToEnclosingRect(element_bounds_);
654}
655
656gfx::Display AutofillPopupControllerImpl::GetDisplayNearestPoint(
657    const gfx::Point& point) const {
658  return gfx::Screen::GetScreenFor(container_view())->GetDisplayNearestPoint(
659      point);
660}
661
662std::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
693std::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