autofill_popup_controller_impl.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <utility>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/autofill/autofill_popup_view.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/autofill/core/browser/autofill_popup_delegate.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/native_web_keyboard_event.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/webkit_resources.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/WebKit/public/web/WebAutofillClient.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/events/event.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/text/text_elider.h"
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/display.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/rect_conversions.h"
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/screen.h"
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/vector2d.h"
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using base::WeakPtr;
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using WebKit::WebAutofillClient;
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace autofill {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Used to indicate that no line is currently selected by the user.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kNoSelection = -1;
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Size difference between name and subtext in pixels.
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kLabelFontSizeDelta = -2;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The vertical height of each row in pixels.
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kRowHeight = 24;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The vertical height of a separator in pixels.
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kSeparatorHeight = 1;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The maximum amount of characters to display from either the name or subtext.
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaxTextLength = 15;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(OS_ANDROID)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kNamePadding = AutofillPopupView::kNamePadding;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kIconPadding = AutofillPopupView::kIconPadding;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kEndPadding = AutofillPopupView::kEndPadding;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kAutofillIconWidth = AutofillPopupView::kAutofillIconWidth;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct DataResource {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* name;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int id;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const DataResource kDataResources[] = {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  { "americanExpressCC", IDR_AUTOFILL_CC_AMEX },
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  { "dinersCC", IDR_AUTOFILL_CC_DINERS },
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  { "discoverCC", IDR_AUTOFILL_CC_DISCOVER },
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  { "genericCC", IDR_AUTOFILL_CC_GENERIC },
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  { "jcbCC", IDR_AUTOFILL_CC_JCB },
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD },
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  { "visaCC", IDR_AUTOFILL_CC_VISA },
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetOrCreate(
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WeakPtr<AutofillPopupControllerImpl> previous,
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WeakPtr<AutofillPopupDelegate> delegate,
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::NativeView container_view,
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::RectF& element_bounds,
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::i18n::TextDirection text_direction) {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!previous.get() || previous->delegate_.get() == delegate.get());
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (previous.get() && previous->container_view() == container_view &&
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      previous->element_bounds() == element_bounds) {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    previous->ClearState();
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return previous;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (previous.get())
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    previous->Hide();
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AutofillPopupControllerImpl* controller =
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new AutofillPopupControllerImpl(
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          delegate, container_view, element_bounds, text_direction);
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return controller->GetWeakPtr();
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AutofillPopupControllerImpl::AutofillPopupControllerImpl(
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WeakPtr<AutofillPopupDelegate> delegate,
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::NativeView container_view,
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::RectF& element_bounds,
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::i18n::TextDirection text_direction)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : view_(NULL),
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delegate_(delegate),
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      container_view_(container_view),
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      element_bounds_(element_bounds),
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      text_direction_(text_direction),
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      weak_ptr_factory_(this) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClearState();
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(OS_ANDROID)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  subtext_font_ = name_font_.DeriveFont(kLabelFontSizeDelta);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  warning_font_ = name_font_.DeriveFont(0, gfx::Font::ITALIC);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {}
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::Show(
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<string16>& names,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<string16>& subtexts,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<string16>& icons,
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<int>& identifiers) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetValues(names, subtexts, icons, identifiers);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(OS_ANDROID)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Android displays the long text with ellipsis using the view attributes.
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdatePopupBounds();
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int popup_width = popup_bounds().width();
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Elide the name and subtext strings so that the popup fits in the available
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // space.
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < names_.size(); ++i) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int name_width = GetNameFontForRow(i).GetStringWidth(names_[i]);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int subtext_width = subtext_font().GetStringWidth(subtexts_[i]);
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int total_text_length = name_width + subtext_width;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The line can have no strings if it represents a UI element, such as
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // a separator line.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (total_text_length == 0)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int available_width = popup_width - RowWidthWithoutText(i);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Each field recieves space in proportion to its length.
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int name_size = available_width * name_width / total_text_length;
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    names_[i] = ui::ElideText(names_[i],
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              GetNameFontForRow(i),
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              name_size,
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              ui::ELIDE_AT_END);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int subtext_size = available_width * subtext_width / total_text_length;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    subtexts_[i] = ui::ElideText(subtexts_[i],
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 subtext_font(),
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 subtext_size,
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 ui::ELIDE_AT_END);
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!view_) {
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    view_ = AutofillPopupView::Create(this);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // It is possible to fail to create the popup, in this case
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // treat the popup as hiding right away.
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!view_) {
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Hide();
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ShowView();
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UpdateBoundsAndRedrawPopup();
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delegate_->OnPopupShown(this);
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::Hide() {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delegate_.get())
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delegate_->OnPopupHidden(this);
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (view_)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    view_->Hide();
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete this;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::ViewDestroyed() {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The view has already been destroyed so clear the reference to it.
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  view_ = NULL;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Hide();
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool AutofillPopupControllerImpl::HandleKeyPressEvent(
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const content::NativeWebKeyboardEvent& event) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (event.windowsKeyCode) {
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::VKEY_UP:
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SelectPreviousLine();
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::VKEY_DOWN:
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SelectNextLine();
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::VKEY_PRIOR:  // Page up.
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetSelectedLine(0);
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::VKEY_NEXT:  // Page down.
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      SetSelectedLine(names().size() - 1);
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::VKEY_ESCAPE:
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Hide();
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::VKEY_DELETE:
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return (event.modifiers & content::NativeWebKeyboardEvent::ShiftKey) &&
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             RemoveSelectedLine();
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case ui::VKEY_TAB:
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // A tab press should cause the highlighted line to be selected, but still
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // return false so the tab key press propagates and changes the cursor
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // location.
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AcceptSelectedLine();
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ui::VKEY_RETURN:
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AcceptSelectedLine();
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::UpdateBoundsAndRedrawPopup() {
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(OS_ANDROID)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(csharp): Since UpdatePopupBounds can change the position of the popup,
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the popup could end up jumping from above the element to below it.
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // It is unclear if it is better to keep the popup where it was, or if it
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // should try and move to its desired position.
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdatePopupBounds();
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  view_->UpdateBoundsAndRedrawPopup();
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::MouseHovered(int x, int y) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetSelectedLine(LineFromY(y));
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::MouseClicked(int x, int y) {
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MouseHovered(x, y);
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AcceptSelectedLine();
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::MouseExitedPopup() {
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetSelectedLine(kNoSelection);
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) {
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]);
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int AutofillPopupControllerImpl::GetIconResourceID(
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const string16& resource_name) {
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < arraysize(kDataResources); ++i) {
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (resource_name == ASCIIToUTF16(kDataResources[i].name))
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return kDataResources[i].id;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return -1;
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AutofillPopupControllerImpl::CanDelete(size_t index) const {
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(isherman): Native AddressBook suggestions on Mac and Android should
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // not be considered to be deleteable.
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int id = identifiers_[index];
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return id > 0 ||
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      id == WebAutofillClient::MenuItemIDAutocompleteEntry ||
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      id == WebAutofillClient::MenuItemIDPasswordEntry;
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AutofillPopupControllerImpl::IsWarning(size_t index) const {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return identifiers_[index] == WebAutofillClient::MenuItemIDWarningMessage;
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) {
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int top = 0;
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < index; ++i) {
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    top += GetRowHeightFromId(identifiers()[i]);
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return gfx::Rect(
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0,
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      top,
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      popup_bounds_.width(),
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetRowHeightFromId(identifiers()[index]));
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) {
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  popup_bounds_ = bounds;
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UpdateBoundsAndRedrawPopup();
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const {
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return popup_bounds_;
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::NativeView AutofillPopupControllerImpl::container_view() const {
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return container_view_;
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const {
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return element_bounds_;
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AutofillPopupControllerImpl::IsRTL() const {
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return text_direction_ == base::i18n::RIGHT_TO_LEFT;
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<string16>& AutofillPopupControllerImpl::names() const {
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return names_;
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<string16>& AutofillPopupControllerImpl::subtexts() const {
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return subtexts_;
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<string16>& AutofillPopupControllerImpl::icons() const {
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return icons_;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<int>& AutofillPopupControllerImpl::identifiers() const {
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return identifiers_;
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(OS_ANDROID)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const gfx::Font& AutofillPopupControllerImpl::GetNameFontForRow(size_t index)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const {
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (identifiers_[index] == WebAutofillClient::MenuItemIDWarningMessage)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return warning_font_;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return name_font_;
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const gfx::Font& AutofillPopupControllerImpl::subtext_font() const {
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return subtext_font_;
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int AutofillPopupControllerImpl::selected_line() const {
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return selected_line_;
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) {
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (selected_line_ == selected_line)
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (selected_line_ != kNoSelection &&
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<size_t>(selected_line_) < identifiers_.size())
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InvalidateRow(selected_line_);
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (selected_line != kNoSelection)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InvalidateRow(selected_line);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  selected_line_ = selected_line;
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (selected_line_ != kNoSelection)
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delegate_->DidSelectSuggestion(identifiers_[selected_line_]);
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delegate_->ClearPreviewedForm();
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::SelectNextLine() {
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int new_selected_line = selected_line_ + 1;
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Skip over any lines that can't be selected.
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (static_cast<size_t>(new_selected_line) < names_.size() &&
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         !CanAccept(identifiers()[new_selected_line])) {
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++new_selected_line;
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_selected_line >= static_cast<int>(names_.size()))
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    new_selected_line = 0;
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetSelectedLine(new_selected_line);
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::SelectPreviousLine() {
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int new_selected_line = selected_line_ - 1;
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Skip over any lines that can't be selected.
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (new_selected_line > kNoSelection &&
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         !CanAccept(identifiers()[new_selected_line])) {
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    --new_selected_line;
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_selected_line <= kNoSelection)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    new_selected_line = names_.size() - 1;
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetSelectedLine(new_selected_line);
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AutofillPopupControllerImpl::AcceptSelectedLine() {
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (selected_line_ == kNoSelection)
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GE(selected_line_, 0);
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(selected_line_, static_cast<int>(names_.size()));
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CanAccept(identifiers_[selected_line_]))
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AcceptSuggestion(selected_line_);
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AutofillPopupControllerImpl::RemoveSelectedLine() {
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (selected_line_ == kNoSelection)
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GE(selected_line_, 0);
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(selected_line_, static_cast<int>(names_.size()));
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CanDelete(selected_line_))
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delegate_->RemoveSuggestion(full_names_[selected_line_],
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              identifiers_[selected_line_]);
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Remove the deleted element.
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  names_.erase(names_.begin() + selected_line_);
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  full_names_.erase(full_names_.begin() + selected_line_);
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  subtexts_.erase(subtexts_.begin() + selected_line_);
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icons_.erase(icons_.begin() + selected_line_);
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  identifiers_.erase(identifiers_.begin() + selected_line_);
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetSelectedLine(kNoSelection);
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (HasSuggestions()) {
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delegate_->ClearPreviewedForm();
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UpdateBoundsAndRedrawPopup();
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Hide();
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int AutofillPopupControllerImpl::LineFromY(int y) {
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int current_height = 0;
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < identifiers().size(); ++i) {
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    current_height += GetRowHeightFromId(identifiers()[i]);
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (y <= current_height)
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return i;
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The y value goes beyond the popup so stop the selection at the last line.
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return identifiers().size() - 1;
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const {
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (identifier == WebAutofillClient::MenuItemIDSeparator)
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kSeparatorHeight;
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return kRowHeight;
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AutofillPopupControllerImpl::CanAccept(int id) {
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return id != WebAutofillClient::MenuItemIDSeparator &&
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      id != WebAutofillClient::MenuItemIDWarningMessage;
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AutofillPopupControllerImpl::HasSuggestions() {
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return identifiers_.size() != 0 &&
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (identifiers_[0] > 0 ||
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       identifiers_[0] ==
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           WebAutofillClient::MenuItemIDAutocompleteEntry ||
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       identifiers_[0] == WebAutofillClient::MenuItemIDPasswordEntry ||
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       identifiers_[0] == WebAutofillClient::MenuItemIDDataListEntry);
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::SetValues(
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<string16>& names,
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<string16>& subtexts,
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<string16>& icons,
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<int>& identifiers) {
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  names_ = names;
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  full_names_ = names;
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  subtexts_ = subtexts;
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icons_ = icons;
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  identifiers_ = identifiers;
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::ShowView() {
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  view_->Show();
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutofillPopupControllerImpl::InvalidateRow(size_t row) {
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(0 <= row);
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(row < identifiers_.size());
493  view_->InvalidateRow(row);
494}
495
496#if !defined(OS_ANDROID)
497int AutofillPopupControllerImpl::GetDesiredPopupWidth() const {
498  if (!name_font_.platform_font() || !subtext_font_.platform_font()) {
499    // We can't calculate the size of the popup if the fonts
500    // aren't present.
501    return 0;
502  }
503
504  int popup_width = RoundedElementBounds().width();
505  DCHECK_EQ(names().size(), subtexts().size());
506  for (size_t i = 0; i < names().size(); ++i) {
507    int row_size = name_font_.GetStringWidth(names()[i]) +
508        subtext_font_.GetStringWidth(subtexts()[i]) +
509        RowWidthWithoutText(i);
510
511    popup_width = std::max(popup_width, row_size);
512  }
513
514  return popup_width;
515}
516
517int AutofillPopupControllerImpl::GetDesiredPopupHeight() const {
518  int popup_height = 0;
519
520  for (size_t i = 0; i < identifiers().size(); ++i) {
521    popup_height += GetRowHeightFromId(identifiers()[i]);
522  }
523
524  return popup_height;
525}
526
527int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const {
528  int row_size = kEndPadding;
529
530  if (!subtexts_[row].empty())
531    row_size += kNamePadding;
532
533  // Add the Autofill icon size, if required.
534  if (!icons_[row].empty())
535    row_size += kAutofillIconWidth + kIconPadding;
536
537  // Add the padding at the end
538  row_size += kEndPadding;
539
540  return row_size;
541}
542
543void AutofillPopupControllerImpl::UpdatePopupBounds() {
544  int popup_required_width = GetDesiredPopupWidth();
545  int popup_height = GetDesiredPopupHeight();
546  // This is the top left point of the popup if the popup is above the element
547  // and grows to the left (since that is the highest and furthest left the
548  // popup go could).
549  gfx::Point top_left_corner_of_popup = RoundedElementBounds().origin() +
550      gfx::Vector2d(RoundedElementBounds().width() - popup_required_width,
551                    -popup_height);
552
553  // This is the bottom right point of the popup if the popup is below the
554  // element and grows to the right (since the is the lowest and furthest right
555  // the popup could go).
556  gfx::Point bottom_right_corner_of_popup = RoundedElementBounds().origin() +
557      gfx::Vector2d(popup_required_width,
558                    RoundedElementBounds().height() + popup_height);
559
560  gfx::Display top_left_display = GetDisplayNearestPoint(
561      top_left_corner_of_popup);
562  gfx::Display bottom_right_display = GetDisplayNearestPoint(
563      bottom_right_corner_of_popup);
564
565  std::pair<int, int> popup_x_and_width = CalculatePopupXAndWidth(
566      top_left_display, bottom_right_display, popup_required_width);
567  std::pair<int, int> popup_y_and_height = CalculatePopupYAndHeight(
568      top_left_display, bottom_right_display, popup_height);
569
570  popup_bounds_ = gfx::Rect(popup_x_and_width.first,
571                            popup_y_and_height.first,
572                            popup_x_and_width.second,
573                            popup_y_and_height.second);
574}
575#endif  // !defined(OS_ANDROID)
576
577WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() {
578  return weak_ptr_factory_.GetWeakPtr();
579}
580
581void AutofillPopupControllerImpl::ClearState() {
582  // Don't clear view_, because otherwise the popup will have to get regenerated
583  // and this will cause flickering.
584
585  popup_bounds_ = gfx::Rect();
586
587  names_.clear();
588  subtexts_.clear();
589  icons_.clear();
590  identifiers_.clear();
591  full_names_.clear();
592
593  selected_line_ = kNoSelection;
594}
595
596const gfx::Rect AutofillPopupControllerImpl::RoundedElementBounds() const {
597  return gfx::ToEnclosingRect(element_bounds_);
598}
599
600gfx::Display AutofillPopupControllerImpl::GetDisplayNearestPoint(
601    const gfx::Point& point) const {
602  return gfx::Screen::GetScreenFor(container_view())->GetDisplayNearestPoint(
603      point);
604}
605
606std::pair<int, int> AutofillPopupControllerImpl::CalculatePopupXAndWidth(
607    const gfx::Display& left_display,
608    const gfx::Display& right_display,
609    int popup_required_width) const {
610  int leftmost_display_x = left_display.bounds().x();
611  int rightmost_display_x =
612      right_display.GetSizeInPixel().width() + right_display.bounds().x();
613
614  // Calculate the start coordinates for the popup if it is growing right or
615  // the end position if it is growing to the left, capped to screen space.
616  int right_growth_start = std::max(leftmost_display_x,
617                                    std::min(rightmost_display_x,
618                                             RoundedElementBounds().x()));
619  int left_growth_end = std::max(leftmost_display_x,
620                                   std::min(rightmost_display_x,
621                                            RoundedElementBounds().right()));
622
623  int right_available = rightmost_display_x - right_growth_start;
624  int left_available = left_growth_end - leftmost_display_x;
625
626  int popup_width = std::min(popup_required_width,
627                             std::max(right_available, left_available));
628
629  // If there is enough space for the popup on the right, show it there,
630  // otherwise choose the larger size.
631  if (right_available >= popup_width || right_available >= left_available)
632    return std::make_pair(right_growth_start, popup_width);
633  else
634    return std::make_pair(left_growth_end - popup_width, popup_width);
635}
636
637std::pair<int,int> AutofillPopupControllerImpl::CalculatePopupYAndHeight(
638    const gfx::Display& top_display,
639    const gfx::Display& bottom_display,
640    int popup_required_height) const {
641  int topmost_display_y = top_display.bounds().y();
642  int bottommost_display_y =
643      bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y();
644
645  // Calculate the start coordinates for the popup if it is growing down or
646  // the end position if it is growing up, capped to screen space.
647  int top_growth_end = std::max(topmost_display_y,
648                                std::min(bottommost_display_y,
649                                         RoundedElementBounds().y()));
650  int bottom_growth_start = std::max(topmost_display_y,
651      std::min(bottommost_display_y, RoundedElementBounds().bottom()));
652
653  int top_available = bottom_growth_start - topmost_display_y;
654  int bottom_available = bottommost_display_y - top_growth_end;
655
656  // TODO(csharp): Restrict the popup height to what is available.
657  if (bottom_available >= popup_required_height ||
658      bottom_available >= top_available) {
659    // The popup can appear below the field.
660    return std::make_pair(bottom_growth_start, popup_required_height);
661  } else {
662    // The popup must appear above the field.
663    return std::make_pair(top_growth_end - popup_required_height,
664                          popup_required_height);
665  }
666}
667
668}  // namespace autofill
669