| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" | 5 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "chrome/browser/ui/autofill/autofill_popup_view.h" | 12 #include "chrome/browser/ui/autofill/autofill_popup_view.h" |
| 13 #include "chrome/browser/ui/autofill/popup_constants.h" | 13 #include "chrome/browser/ui/autofill/popup_constants.h" |
| 14 #include "components/autofill/core/browser/autofill_popup_delegate.h" | 14 #include "components/autofill/core/browser/autofill_popup_delegate.h" |
| 15 #include "components/autofill/core/browser/popup_item_ids.h" | 15 #include "components/autofill/core/browser/popup_item_ids.h" |
| 16 #include "components/autofill/core/browser/suggestion.h" |
| 16 #include "content/public/browser/native_web_keyboard_event.h" | 17 #include "content/public/browser/native_web_keyboard_event.h" |
| 17 #include "grit/components_scaled_resources.h" | 18 #include "grit/components_scaled_resources.h" |
| 18 #include "ui/base/resource/resource_bundle.h" | 19 #include "ui/base/resource/resource_bundle.h" |
| 19 #include "ui/events/event.h" | 20 #include "ui/events/event.h" |
| 20 #include "ui/gfx/rect_conversions.h" | 21 #include "ui/gfx/rect_conversions.h" |
| 21 #include "ui/gfx/screen.h" | 22 #include "ui/gfx/screen.h" |
| 22 #include "ui/gfx/text_elider.h" | 23 #include "ui/gfx/text_elider.h" |
| 23 #include "ui/gfx/text_utils.h" | 24 #include "ui/gfx/text_utils.h" |
| 24 #include "ui/gfx/vector2d.h" | 25 #include "ui/gfx/vector2d.h" |
| 25 | 26 |
| 26 using base::WeakPtr; | 27 using base::WeakPtr; |
| 27 | 28 |
| 28 namespace autofill { | 29 namespace autofill { |
| 29 namespace { | 30 namespace { |
| 30 | 31 |
| 31 // Used to indicate that no line is currently selected by the user. | 32 // Used to indicate that no line is currently selected by the user. |
| 32 const int kNoSelection = -1; | 33 const int kNoSelection = -1; |
| 33 | 34 |
| 34 // The vertical height of each row in pixels. | 35 // The vertical height of each row in pixels. |
| 35 const size_t kRowHeight = 24; | 36 const size_t kRowHeight = 24; |
| 36 | 37 |
| 37 // The vertical height of a separator in pixels. | 38 // The vertical height of a separator in pixels. |
| 38 const size_t kSeparatorHeight = 1; | 39 const size_t kSeparatorHeight = 1; |
| 39 | 40 |
| 40 #if !defined(OS_ANDROID) | 41 #if !defined(OS_ANDROID) |
| 41 // Size difference between name and subtext in pixels. | 42 // Size difference between name and label in pixels. |
| 42 const int kLabelFontSizeDelta = -2; | 43 const int kLabelFontSizeDelta = -2; |
| 43 | 44 |
| 44 const size_t kNamePadding = AutofillPopupView::kNamePadding; | 45 const size_t kNamePadding = AutofillPopupView::kNamePadding; |
| 45 const size_t kIconPadding = AutofillPopupView::kIconPadding; | 46 const size_t kIconPadding = AutofillPopupView::kIconPadding; |
| 46 const size_t kEndPadding = AutofillPopupView::kEndPadding; | 47 const size_t kEndPadding = AutofillPopupView::kEndPadding; |
| 47 #endif | 48 #endif |
| 48 | 49 |
| 49 struct DataResource { | 50 struct DataResource { |
| 50 const char* name; | 51 const char* name; |
| 51 int id; | 52 int id; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 web_contents)), | 104 web_contents)), |
| 104 view_(NULL), | 105 view_(NULL), |
| 105 delegate_(delegate), | 106 delegate_(delegate), |
| 106 text_direction_(text_direction), | 107 text_direction_(text_direction), |
| 107 weak_ptr_factory_(this) { | 108 weak_ptr_factory_(this) { |
| 108 ClearState(); | 109 ClearState(); |
| 109 controller_common_->SetKeyPressCallback( | 110 controller_common_->SetKeyPressCallback( |
| 110 base::Bind(&AutofillPopupControllerImpl::HandleKeyPressEvent, | 111 base::Bind(&AutofillPopupControllerImpl::HandleKeyPressEvent, |
| 111 base::Unretained(this))); | 112 base::Unretained(this))); |
| 112 #if !defined(OS_ANDROID) | 113 #if !defined(OS_ANDROID) |
| 113 subtext_font_list_ = name_font_list_.DeriveWithSizeDelta(kLabelFontSizeDelta); | 114 label_font_list_ = value_font_list_.DeriveWithSizeDelta(kLabelFontSizeDelta); |
| 114 title_font_list_ = name_font_list_.DeriveWithStyle(gfx::Font::BOLD); | 115 title_font_list_ = value_font_list_.DeriveWithStyle(gfx::Font::BOLD); |
| 115 #if defined(OS_MACOSX) | 116 #if defined(OS_MACOSX) |
| 116 // There is no italic version of the system font. | 117 // There is no italic version of the system font. |
| 117 warning_font_list_ = name_font_list_; | 118 warning_font_list_ = value_font_list_; |
| 118 #else | 119 #else |
| 119 warning_font_list_ = name_font_list_.DeriveWithStyle(gfx::Font::ITALIC); | 120 warning_font_list_ = value_font_list_.DeriveWithStyle(gfx::Font::ITALIC); |
| 120 #endif | 121 #endif |
| 121 #endif | 122 #endif |
| 122 } | 123 } |
| 123 | 124 |
| 124 AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {} | 125 AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {} |
| 125 | 126 |
| 126 void AutofillPopupControllerImpl::Show( | 127 void AutofillPopupControllerImpl::Show( |
| 127 const std::vector<base::string16>& names, | 128 const std::vector<autofill::Suggestion>& suggestions) { |
| 128 const std::vector<base::string16>& subtexts, | 129 SetValues(suggestions); |
| 129 const std::vector<base::string16>& icons, | 130 DCHECK_EQ(suggestions_.size(), elided_values_.size()); |
| 130 const std::vector<int>& identifiers) { | 131 DCHECK_EQ(suggestions_.size(), elided_labels_.size()); |
| 131 SetValues(names, subtexts, icons, identifiers); | |
| 132 | 132 |
| 133 #if !defined(OS_ANDROID) | 133 #if !defined(OS_ANDROID) |
| 134 // Android displays the long text with ellipsis using the view attributes. | 134 // Android displays the long text with ellipsis using the view attributes. |
| 135 | 135 |
| 136 UpdatePopupBounds(); | 136 UpdatePopupBounds(); |
| 137 int popup_width = popup_bounds().width(); | 137 int popup_width = popup_bounds().width(); |
| 138 | 138 |
| 139 // Elide the name and subtext strings so that the popup fits in the available | 139 // Elide the name and label strings so that the popup fits in the available |
| 140 // space. | 140 // space. |
| 141 for (size_t i = 0; i < names_.size(); ++i) { | 141 for (size_t i = 0; i < suggestions_.size(); ++i) { |
| 142 int name_width = gfx::GetStringWidth(names_[i], GetNameFontListForRow(i)); | 142 int value_width = |
| 143 int subtext_width = gfx::GetStringWidth(subtexts_[i], subtext_font_list()); | 143 gfx::GetStringWidth(suggestions_[i].value, GetValueFontListForRow(i)); |
| 144 int total_text_length = name_width + subtext_width; | 144 int label_width = |
| 145 gfx::GetStringWidth(suggestions_[i].label, GetLabelFontList()); |
| 146 int total_text_length = value_width + label_width; |
| 145 | 147 |
| 146 // The line can have no strings if it represents a UI element, such as | 148 // The line can have no strings if it represents a UI element, such as |
| 147 // a separator line. | 149 // a separator line. |
| 148 if (total_text_length == 0) | 150 if (total_text_length == 0) |
| 149 continue; | 151 continue; |
| 150 | 152 |
| 151 int available_width = popup_width - RowWidthWithoutText(i); | 153 int available_width = popup_width - RowWidthWithoutText(i); |
| 152 | 154 |
| 153 // Each field receives space in proportion to its length. | 155 // Each field receives space in proportion to its length. |
| 154 int name_size = available_width * name_width / total_text_length; | 156 int value_size = available_width * value_width / total_text_length; |
| 155 names_[i] = gfx::ElideText(names_[i], GetNameFontListForRow(i), | 157 elided_values_[i] = gfx::ElideText(suggestions_[i].value, |
| 156 name_size, gfx::ELIDE_TAIL); | 158 GetValueFontListForRow(i), |
| 159 value_size, gfx::ELIDE_TAIL); |
| 157 | 160 |
| 158 int subtext_size = available_width * subtext_width / total_text_length; | 161 int label_size = available_width * label_width / total_text_length; |
| 159 subtexts_[i] = gfx::ElideText(subtexts_[i], subtext_font_list(), | 162 elided_labels_[i] = gfx::ElideText(suggestions_[i].label, |
| 160 subtext_size, gfx::ELIDE_TAIL); | 163 GetLabelFontList(), |
| 164 label_size, gfx::ELIDE_TAIL); |
| 161 } | 165 } |
| 162 #endif | 166 #endif |
| 163 | 167 |
| 164 if (!view_) { | 168 if (!view_) { |
| 165 view_ = AutofillPopupView::Create(this); | 169 view_ = AutofillPopupView::Create(this); |
| 166 | 170 |
| 167 // It is possible to fail to create the popup, in this case | 171 // It is possible to fail to create the popup, in this case |
| 168 // treat the popup as hiding right away. | 172 // treat the popup as hiding right away. |
| 169 if (!view_) { | 173 if (!view_) { |
| 170 Hide(); | 174 Hide(); |
| 171 return; | 175 return; |
| 172 } | 176 } |
| 173 | 177 |
| 174 ShowView(); | 178 ShowView(); |
| 175 } else { | 179 } else { |
| 176 UpdateBoundsAndRedrawPopup(); | 180 UpdateBoundsAndRedrawPopup(); |
| 177 } | 181 } |
| 178 | 182 |
| 179 controller_common_->RegisterKeyPressCallback(); | 183 controller_common_->RegisterKeyPressCallback(); |
| 180 delegate_->OnPopupShown(); | 184 delegate_->OnPopupShown(); |
| 181 } | 185 } |
| 182 | 186 |
| 183 void AutofillPopupControllerImpl::UpdateDataListValues( | 187 void AutofillPopupControllerImpl::UpdateDataListValues( |
| 184 const std::vector<base::string16>& values, | 188 const std::vector<base::string16>& values, |
| 185 const std::vector<base::string16>& labels) { | 189 const std::vector<base::string16>& labels) { |
| 186 // Remove all the old data list values, which should always be at the top of | 190 // Remove all the old data list values, which should always be at the top of |
| 187 // the list if they are present. | 191 // the list if they are present. |
| 188 while (!identifiers_.empty() && | 192 while (!suggestions_.empty() && |
| 189 identifiers_[0] == POPUP_ITEM_ID_DATALIST_ENTRY) { | 193 suggestions_[0].frontend_id == POPUP_ITEM_ID_DATALIST_ENTRY) { |
| 190 names_.erase(names_.begin()); | 194 suggestions_.erase(suggestions_.begin()); |
| 191 subtexts_.erase(subtexts_.begin()); | 195 elided_values_.erase(elided_values_.begin()); |
| 192 icons_.erase(icons_.begin()); | 196 elided_labels_.erase(elided_labels_.begin()); |
| 193 identifiers_.erase(identifiers_.begin()); | |
| 194 } | 197 } |
| 195 | 198 |
| 196 // If there are no new data list values, exit (clearing the separator if there | 199 // If there are no new data list values, exit (clearing the separator if there |
| 197 // is one). | 200 // is one). |
| 198 if (values.empty()) { | 201 if (values.empty()) { |
| 199 if (!identifiers_.empty() && identifiers_[0] == POPUP_ITEM_ID_SEPARATOR) { | 202 if (!suggestions_.empty() && |
| 200 names_.erase(names_.begin()); | 203 suggestions_[0].frontend_id == POPUP_ITEM_ID_SEPARATOR) { |
| 201 subtexts_.erase(subtexts_.begin()); | 204 suggestions_.erase(suggestions_.begin()); |
| 202 icons_.erase(icons_.begin()); | 205 elided_values_.erase(elided_values_.begin()); |
| 203 identifiers_.erase(identifiers_.begin()); | 206 elided_labels_.erase(elided_labels_.begin()); |
| 204 } | 207 } |
| 205 | 208 |
| 206 // The popup contents have changed, so either update the bounds or hide it. | 209 // The popup contents have changed, so either update the bounds or hide it. |
| 207 if (HasSuggestions()) | 210 if (HasSuggestions()) |
| 208 UpdateBoundsAndRedrawPopup(); | 211 UpdateBoundsAndRedrawPopup(); |
| 209 else | 212 else |
| 210 Hide(); | 213 Hide(); |
| 211 | 214 |
| 212 return; | 215 return; |
| 213 } | 216 } |
| 214 | 217 |
| 215 // Add a separator if there are any other values. | 218 // Add a separator if there are any other values. |
| 216 if (!identifiers_.empty() && identifiers_[0] != POPUP_ITEM_ID_SEPARATOR) { | 219 if (!suggestions_.empty() && |
| 217 names_.insert(names_.begin(), base::string16()); | 220 suggestions_[0].frontend_id != POPUP_ITEM_ID_SEPARATOR) { |
| 218 subtexts_.insert(subtexts_.begin(), base::string16()); | 221 suggestions_.insert(suggestions_.begin(), autofill::Suggestion()); |
| 219 icons_.insert(icons_.begin(), base::string16()); | 222 suggestions_[0].frontend_id = POPUP_ITEM_ID_SEPARATOR; |
| 220 identifiers_.insert(identifiers_.begin(), POPUP_ITEM_ID_SEPARATOR); | 223 elided_values_.insert(elided_values_.begin(), base::string16()); |
| 224 elided_labels_.insert(elided_labels_.begin(), base::string16()); |
| 221 } | 225 } |
| 222 | 226 |
| 223 | 227 // Prepend the parameters to the suggestions we already have. |
| 224 names_.insert(names_.begin(), values.begin(), values.end()); | 228 suggestions_.insert(suggestions_.begin(), values.size(), Suggestion()); |
| 225 subtexts_.insert(subtexts_.begin(), labels.begin(), labels.end()); | 229 for (size_t i = 0; i < values.size(); i++) { |
| 226 | 230 suggestions_[i].value = values[i]; |
| 227 // Add the values that are the same for all data list elements. | 231 suggestions_[i].label = labels[i]; |
| 228 icons_.insert(icons_.begin(), values.size(), base::string16()); | 232 suggestions_[i].frontend_id = POPUP_ITEM_ID_DATALIST_ENTRY; |
| 229 identifiers_.insert( | 233 } |
| 230 identifiers_.begin(), values.size(), POPUP_ITEM_ID_DATALIST_ENTRY); | |
| 231 | 234 |
| 232 UpdateBoundsAndRedrawPopup(); | 235 UpdateBoundsAndRedrawPopup(); |
| 233 } | 236 } |
| 234 | 237 |
| 235 void AutofillPopupControllerImpl::Hide() { | 238 void AutofillPopupControllerImpl::Hide() { |
| 236 controller_common_->RemoveKeyPressCallback(); | 239 controller_common_->RemoveKeyPressCallback(); |
| 237 if (delegate_) | 240 if (delegate_) |
| 238 delegate_->OnPopupHidden(); | 241 delegate_->OnPopupHidden(); |
| 239 | 242 |
| 240 if (view_) | 243 if (view_) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 259 case ui::VKEY_DOWN: | 262 case ui::VKEY_DOWN: |
| 260 SelectNextLine(); | 263 SelectNextLine(); |
| 261 return true; | 264 return true; |
| 262 case ui::VKEY_PRIOR: // Page up. | 265 case ui::VKEY_PRIOR: // Page up. |
| 263 // Set no line and then select the next line in case the first line is not | 266 // Set no line and then select the next line in case the first line is not |
| 264 // selectable. | 267 // selectable. |
| 265 SetSelectedLine(kNoSelection); | 268 SetSelectedLine(kNoSelection); |
| 266 SelectNextLine(); | 269 SelectNextLine(); |
| 267 return true; | 270 return true; |
| 268 case ui::VKEY_NEXT: // Page down. | 271 case ui::VKEY_NEXT: // Page down. |
| 269 SetSelectedLine(names().size() - 1); | 272 SetSelectedLine(GetLineCount() - 1); |
| 270 return true; | 273 return true; |
| 271 case ui::VKEY_ESCAPE: | 274 case ui::VKEY_ESCAPE: |
| 272 Hide(); | 275 Hide(); |
| 273 return true; | 276 return true; |
| 274 case ui::VKEY_DELETE: | 277 case ui::VKEY_DELETE: |
| 275 return (event.modifiers & content::NativeWebKeyboardEvent::ShiftKey) && | 278 return (event.modifiers & content::NativeWebKeyboardEvent::ShiftKey) && |
| 276 RemoveSelectedLine(); | 279 RemoveSelectedLine(); |
| 277 case ui::VKEY_TAB: | 280 case ui::VKEY_TAB: |
| 278 // A tab press should cause the selected line to be accepted, but still | 281 // A tab press should cause the selected line to be accepted, but still |
| 279 // return false so the tab key press propagates and changes the cursor | 282 // return false so the tab key press propagates and changes the cursor |
| (...skipping 21 matching lines...) Expand all Loading... |
| 301 | 304 |
| 302 void AutofillPopupControllerImpl::SetSelectionAtPoint(const gfx::Point& point) { | 305 void AutofillPopupControllerImpl::SetSelectionAtPoint(const gfx::Point& point) { |
| 303 SetSelectedLine(LineFromY(point.y())); | 306 SetSelectedLine(LineFromY(point.y())); |
| 304 } | 307 } |
| 305 | 308 |
| 306 bool AutofillPopupControllerImpl::AcceptSelectedLine() { | 309 bool AutofillPopupControllerImpl::AcceptSelectedLine() { |
| 307 if (selected_line_ == kNoSelection) | 310 if (selected_line_ == kNoSelection) |
| 308 return false; | 311 return false; |
| 309 | 312 |
| 310 DCHECK_GE(selected_line_, 0); | 313 DCHECK_GE(selected_line_, 0); |
| 311 DCHECK_LT(selected_line_, static_cast<int>(names_.size())); | 314 DCHECK_LT(selected_line_, static_cast<int>(GetLineCount())); |
| 312 | 315 |
| 313 if (!CanAccept(identifiers_[selected_line_])) | 316 if (!CanAccept(suggestions_[selected_line_].frontend_id)) |
| 314 return false; | 317 return false; |
| 315 | 318 |
| 316 AcceptSuggestion(selected_line_); | 319 AcceptSuggestion(selected_line_); |
| 317 return true; | 320 return true; |
| 318 } | 321 } |
| 319 | 322 |
| 320 void AutofillPopupControllerImpl::SelectionCleared() { | 323 void AutofillPopupControllerImpl::SelectionCleared() { |
| 321 SetSelectedLine(kNoSelection); | 324 SetSelectedLine(kNoSelection); |
| 322 } | 325 } |
| 323 | 326 |
| 324 void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) { | 327 void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) { |
| 325 delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]); | 328 const autofill::Suggestion& suggestion = suggestions_[index]; |
| 329 delegate_->DidAcceptSuggestion(suggestion.value, suggestion.frontend_id); |
| 326 } | 330 } |
| 327 | 331 |
| 328 int AutofillPopupControllerImpl::GetIconResourceID( | 332 int AutofillPopupControllerImpl::GetIconResourceID( |
| 329 const base::string16& resource_name) const { | 333 const base::string16& resource_name) const { |
| 330 for (size_t i = 0; i < arraysize(kDataResources); ++i) { | 334 for (size_t i = 0; i < arraysize(kDataResources); ++i) { |
| 331 if (resource_name == base::ASCIIToUTF16(kDataResources[i].name)) | 335 if (resource_name == base::ASCIIToUTF16(kDataResources[i].name)) |
| 332 return kDataResources[i].id; | 336 return kDataResources[i].id; |
| 333 } | 337 } |
| 334 | 338 |
| 335 return -1; | 339 return -1; |
| 336 } | 340 } |
| 337 | 341 |
| 338 bool AutofillPopupControllerImpl::CanDelete(size_t index) const { | 342 bool AutofillPopupControllerImpl::CanDelete(size_t index) const { |
| 339 // TODO(isherman): Native AddressBook suggestions on Mac and Android should | 343 // TODO(isherman): Native AddressBook suggestions on Mac and Android should |
| 340 // not be considered to be deleteable. | 344 // not be considered to be deleteable. |
| 341 int id = identifiers_[index]; | 345 int id = suggestions_[index].frontend_id; |
| 342 return id > 0 || id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || | 346 return id > 0 || id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || |
| 343 id == POPUP_ITEM_ID_PASSWORD_ENTRY; | 347 id == POPUP_ITEM_ID_PASSWORD_ENTRY; |
| 344 } | 348 } |
| 345 | 349 |
| 346 bool AutofillPopupControllerImpl::IsWarning(size_t index) const { | 350 bool AutofillPopupControllerImpl::IsWarning(size_t index) const { |
| 347 return identifiers_[index] == POPUP_ITEM_ID_WARNING_MESSAGE; | 351 return suggestions_[index].frontend_id == POPUP_ITEM_ID_WARNING_MESSAGE; |
| 348 } | 352 } |
| 349 | 353 |
| 350 gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) { | 354 gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) { |
| 351 int top = kPopupBorderThickness; | 355 int top = kPopupBorderThickness; |
| 352 for (size_t i = 0; i < index; ++i) { | 356 for (size_t i = 0; i < index; ++i) { |
| 353 top += GetRowHeightFromId(identifiers()[i]); | 357 top += GetRowHeightFromId(suggestions_[i].frontend_id); |
| 354 } | 358 } |
| 355 | 359 |
| 356 return gfx::Rect( | 360 return gfx::Rect( |
| 357 kPopupBorderThickness, | 361 kPopupBorderThickness, |
| 358 top, | 362 top, |
| 359 popup_bounds_.width() - 2 * kPopupBorderThickness, | 363 popup_bounds_.width() - 2 * kPopupBorderThickness, |
| 360 GetRowHeightFromId(identifiers()[index])); | 364 GetRowHeightFromId(suggestions_[index].frontend_id)); |
| 361 } | 365 } |
| 362 | 366 |
| 363 void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) { | 367 void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) { |
| 364 popup_bounds_ = bounds; | 368 popup_bounds_ = bounds; |
| 365 UpdateBoundsAndRedrawPopup(); | 369 UpdateBoundsAndRedrawPopup(); |
| 366 } | 370 } |
| 367 | 371 |
| 368 const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const { | 372 const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const { |
| 369 return popup_bounds_; | 373 return popup_bounds_; |
| 370 } | 374 } |
| 371 | 375 |
| 372 content::WebContents* AutofillPopupControllerImpl::web_contents() { | 376 content::WebContents* AutofillPopupControllerImpl::web_contents() { |
| 373 return controller_common_->web_contents(); | 377 return controller_common_->web_contents(); |
| 374 } | 378 } |
| 375 | 379 |
| 376 gfx::NativeView AutofillPopupControllerImpl::container_view() { | 380 gfx::NativeView AutofillPopupControllerImpl::container_view() { |
| 377 return controller_common_->container_view(); | 381 return controller_common_->container_view(); |
| 378 } | 382 } |
| 379 | 383 |
| 380 const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const { | 384 const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const { |
| 381 return controller_common_->element_bounds(); | 385 return controller_common_->element_bounds(); |
| 382 } | 386 } |
| 383 | 387 |
| 384 bool AutofillPopupControllerImpl::IsRTL() const { | 388 bool AutofillPopupControllerImpl::IsRTL() const { |
| 385 return text_direction_ == base::i18n::RIGHT_TO_LEFT; | 389 return text_direction_ == base::i18n::RIGHT_TO_LEFT; |
| 386 } | 390 } |
| 387 | 391 |
| 388 const std::vector<base::string16>& AutofillPopupControllerImpl::names() const { | 392 size_t AutofillPopupControllerImpl::GetLineCount() const { |
| 389 return names_; | 393 return suggestions_.size(); |
| 390 } | 394 } |
| 391 | 395 |
| 392 const std::vector<base::string16>& AutofillPopupControllerImpl::subtexts() | 396 const autofill::Suggestion& AutofillPopupControllerImpl::GetSuggestionAt( |
| 393 const { | 397 size_t row) const { |
| 394 return subtexts_; | 398 return suggestions_[row]; |
| 395 } | 399 } |
| 396 | 400 |
| 397 const std::vector<base::string16>& AutofillPopupControllerImpl::icons() const { | 401 const base::string16& AutofillPopupControllerImpl::GetElidedValueAt( |
| 398 return icons_; | 402 size_t row) const { |
| 403 return elided_values_[row]; |
| 399 } | 404 } |
| 400 | 405 |
| 401 const std::vector<int>& AutofillPopupControllerImpl::identifiers() const { | 406 const base::string16& AutofillPopupControllerImpl::GetElidedLabelAt( |
| 402 return identifiers_; | 407 size_t row) const { |
| 408 return elided_labels_[row]; |
| 403 } | 409 } |
| 404 | 410 |
| 405 #if !defined(OS_ANDROID) | 411 #if !defined(OS_ANDROID) |
| 406 const gfx::FontList& AutofillPopupControllerImpl::GetNameFontListForRow( | 412 const gfx::FontList& AutofillPopupControllerImpl::GetValueFontListForRow( |
| 407 size_t index) const { | 413 size_t index) const { |
| 408 if (identifiers_[index] == POPUP_ITEM_ID_WARNING_MESSAGE) | 414 if (suggestions_[index].frontend_id == POPUP_ITEM_ID_WARNING_MESSAGE) |
| 409 return warning_font_list_; | 415 return warning_font_list_; |
| 410 | 416 |
| 411 if (identifiers_[index] == POPUP_ITEM_ID_TITLE) | 417 if (suggestions_[index].frontend_id == POPUP_ITEM_ID_TITLE) |
| 412 return title_font_list_; | 418 return title_font_list_; |
| 413 | 419 |
| 414 return name_font_list_; | 420 return value_font_list_; |
| 415 } | 421 } |
| 416 | 422 |
| 417 const gfx::FontList& AutofillPopupControllerImpl::subtext_font_list() const { | 423 const gfx::FontList& AutofillPopupControllerImpl::GetLabelFontList() const { |
| 418 return subtext_font_list_; | 424 return label_font_list_; |
| 419 } | 425 } |
| 420 #endif | 426 #endif |
| 421 | 427 |
| 422 int AutofillPopupControllerImpl::selected_line() const { | 428 int AutofillPopupControllerImpl::selected_line() const { |
| 423 return selected_line_; | 429 return selected_line_; |
| 424 } | 430 } |
| 425 | 431 |
| 426 void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) { | 432 void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) { |
| 427 if (selected_line_ == selected_line) | 433 if (selected_line_ == selected_line) |
| 428 return; | 434 return; |
| 429 | 435 |
| 430 if (selected_line_ != kNoSelection && | 436 if (selected_line_ != kNoSelection && |
| 431 static_cast<size_t>(selected_line_) < identifiers_.size()) | 437 static_cast<size_t>(selected_line_) < suggestions_.size()) |
| 432 InvalidateRow(selected_line_); | 438 InvalidateRow(selected_line_); |
| 433 | 439 |
| 434 if (selected_line != kNoSelection) { | 440 if (selected_line != kNoSelection) { |
| 435 InvalidateRow(selected_line); | 441 InvalidateRow(selected_line); |
| 436 | 442 |
| 437 if (!CanAccept(identifiers_[selected_line])) | 443 if (!CanAccept(suggestions_[selected_line].frontend_id)) |
| 438 selected_line = kNoSelection; | 444 selected_line = kNoSelection; |
| 439 } | 445 } |
| 440 | 446 |
| 441 selected_line_ = selected_line; | 447 selected_line_ = selected_line; |
| 442 | 448 |
| 443 if (selected_line_ != kNoSelection) { | 449 if (selected_line_ != kNoSelection) { |
| 444 delegate_->DidSelectSuggestion(names_[selected_line_], | 450 delegate_->DidSelectSuggestion(elided_values_[selected_line_], |
| 445 identifiers_[selected_line_]); | 451 suggestions_[selected_line_].frontend_id); |
| 446 } else { | 452 } else { |
| 447 delegate_->ClearPreviewedForm(); | 453 delegate_->ClearPreviewedForm(); |
| 448 } | 454 } |
| 449 } | 455 } |
| 450 | 456 |
| 451 void AutofillPopupControllerImpl::SelectNextLine() { | 457 void AutofillPopupControllerImpl::SelectNextLine() { |
| 452 int new_selected_line = selected_line_ + 1; | 458 int new_selected_line = selected_line_ + 1; |
| 453 | 459 |
| 454 // Skip over any lines that can't be selected. | 460 // Skip over any lines that can't be selected. |
| 455 while (static_cast<size_t>(new_selected_line) < names_.size() && | 461 while (static_cast<size_t>(new_selected_line) < GetLineCount() && |
| 456 !CanAccept(identifiers()[new_selected_line])) { | 462 !CanAccept(suggestions_[new_selected_line].frontend_id)) { |
| 457 ++new_selected_line; | 463 ++new_selected_line; |
| 458 } | 464 } |
| 459 | 465 |
| 460 if (new_selected_line >= static_cast<int>(names_.size())) | 466 if (new_selected_line >= static_cast<int>(GetLineCount())) |
| 461 new_selected_line = 0; | 467 new_selected_line = 0; |
| 462 | 468 |
| 463 SetSelectedLine(new_selected_line); | 469 SetSelectedLine(new_selected_line); |
| 464 } | 470 } |
| 465 | 471 |
| 466 void AutofillPopupControllerImpl::SelectPreviousLine() { | 472 void AutofillPopupControllerImpl::SelectPreviousLine() { |
| 467 int new_selected_line = selected_line_ - 1; | 473 int new_selected_line = selected_line_ - 1; |
| 468 | 474 |
| 469 // Skip over any lines that can't be selected. | 475 // Skip over any lines that can't be selected. |
| 470 while (new_selected_line > kNoSelection && | 476 while (new_selected_line > kNoSelection && |
| 471 !CanAccept(identifiers()[new_selected_line])) { | 477 !CanAccept(GetSuggestionAt(new_selected_line).frontend_id)) { |
| 472 --new_selected_line; | 478 --new_selected_line; |
| 473 } | 479 } |
| 474 | 480 |
| 475 if (new_selected_line <= kNoSelection) | 481 if (new_selected_line <= kNoSelection) |
| 476 new_selected_line = names_.size() - 1; | 482 new_selected_line = GetLineCount() - 1; |
| 477 | 483 |
| 478 SetSelectedLine(new_selected_line); | 484 SetSelectedLine(new_selected_line); |
| 479 } | 485 } |
| 480 | 486 |
| 481 bool AutofillPopupControllerImpl::RemoveSelectedLine() { | 487 bool AutofillPopupControllerImpl::RemoveSelectedLine() { |
| 482 if (selected_line_ == kNoSelection) | 488 if (selected_line_ == kNoSelection) |
| 483 return false; | 489 return false; |
| 484 | 490 |
| 485 DCHECK_GE(selected_line_, 0); | 491 DCHECK_GE(selected_line_, 0); |
| 486 DCHECK_LT(selected_line_, static_cast<int>(names_.size())); | 492 DCHECK_LT(selected_line_, static_cast<int>(GetLineCount())); |
| 487 | 493 |
| 488 if (!CanDelete(selected_line_)) | 494 if (!CanDelete(selected_line_)) |
| 489 return false; | 495 return false; |
| 490 | 496 |
| 491 delegate_->RemoveSuggestion(full_names_[selected_line_], | 497 delegate_->RemoveSuggestion(suggestions_[selected_line_].value, |
| 492 identifiers_[selected_line_]); | 498 suggestions_[selected_line_].frontend_id); |
| 493 | 499 |
| 494 // Remove the deleted element. | 500 // Remove the deleted element. |
| 495 names_.erase(names_.begin() + selected_line_); | 501 suggestions_.erase(suggestions_.begin() + selected_line_); |
| 496 full_names_.erase(full_names_.begin() + selected_line_); | 502 elided_values_.erase(elided_values_.begin() + selected_line_); |
| 497 subtexts_.erase(subtexts_.begin() + selected_line_); | 503 elided_labels_.erase(elided_labels_.begin() + selected_line_); |
| 498 icons_.erase(icons_.begin() + selected_line_); | |
| 499 identifiers_.erase(identifiers_.begin() + selected_line_); | |
| 500 | 504 |
| 501 SetSelectedLine(kNoSelection); | 505 SetSelectedLine(kNoSelection); |
| 502 | 506 |
| 503 if (HasSuggestions()) { | 507 if (HasSuggestions()) { |
| 504 delegate_->ClearPreviewedForm(); | 508 delegate_->ClearPreviewedForm(); |
| 505 UpdateBoundsAndRedrawPopup(); | 509 UpdateBoundsAndRedrawPopup(); |
| 506 } else { | 510 } else { |
| 507 Hide(); | 511 Hide(); |
| 508 } | 512 } |
| 509 | 513 |
| 510 return true; | 514 return true; |
| 511 } | 515 } |
| 512 | 516 |
| 513 int AutofillPopupControllerImpl::LineFromY(int y) { | 517 int AutofillPopupControllerImpl::LineFromY(int y) { |
| 514 int current_height = kPopupBorderThickness; | 518 int current_height = kPopupBorderThickness; |
| 515 | 519 |
| 516 for (size_t i = 0; i < identifiers().size(); ++i) { | 520 for (size_t i = 0; i < suggestions_.size(); ++i) { |
| 517 current_height += GetRowHeightFromId(identifiers()[i]); | 521 current_height += GetRowHeightFromId(suggestions_[i].frontend_id); |
| 518 | 522 |
| 519 if (y <= current_height) | 523 if (y <= current_height) |
| 520 return i; | 524 return i; |
| 521 } | 525 } |
| 522 | 526 |
| 523 // The y value goes beyond the popup so stop the selection at the last line. | 527 // The y value goes beyond the popup so stop the selection at the last line. |
| 524 return identifiers().size() - 1; | 528 return GetLineCount() - 1; |
| 525 } | 529 } |
| 526 | 530 |
| 527 int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const { | 531 int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const { |
| 528 if (identifier == POPUP_ITEM_ID_SEPARATOR) | 532 if (identifier == POPUP_ITEM_ID_SEPARATOR) |
| 529 return kSeparatorHeight; | 533 return kSeparatorHeight; |
| 530 | 534 |
| 531 return kRowHeight; | 535 return kRowHeight; |
| 532 } | 536 } |
| 533 | 537 |
| 534 bool AutofillPopupControllerImpl::CanAccept(int id) { | 538 bool AutofillPopupControllerImpl::CanAccept(int id) { |
| 535 return id != POPUP_ITEM_ID_SEPARATOR && id != POPUP_ITEM_ID_WARNING_MESSAGE && | 539 return id != POPUP_ITEM_ID_SEPARATOR && id != POPUP_ITEM_ID_WARNING_MESSAGE && |
| 536 id != POPUP_ITEM_ID_TITLE; | 540 id != POPUP_ITEM_ID_TITLE; |
| 537 } | 541 } |
| 538 | 542 |
| 539 bool AutofillPopupControllerImpl::HasSuggestions() { | 543 bool AutofillPopupControllerImpl::HasSuggestions() { |
| 540 return identifiers_.size() != 0 && | 544 if (suggestions_.empty()) |
| 541 (identifiers_[0] > 0 || | 545 return false; |
| 542 identifiers_[0] == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || | 546 int id = suggestions_[0].frontend_id; |
| 543 identifiers_[0] == POPUP_ITEM_ID_PASSWORD_ENTRY || | 547 return id > 0 || |
| 544 identifiers_[0] == POPUP_ITEM_ID_DATALIST_ENTRY || | 548 id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || |
| 545 identifiers_[0] == POPUP_ITEM_ID_MAC_ACCESS_CONTACTS); | 549 id == POPUP_ITEM_ID_PASSWORD_ENTRY || |
| 550 id == POPUP_ITEM_ID_DATALIST_ENTRY || |
| 551 id == POPUP_ITEM_ID_MAC_ACCESS_CONTACTS; |
| 546 } | 552 } |
| 547 | 553 |
| 548 void AutofillPopupControllerImpl::SetValues( | 554 void AutofillPopupControllerImpl::SetValues( |
| 549 const std::vector<base::string16>& names, | 555 const std::vector<autofill::Suggestion>& suggestions) { |
| 550 const std::vector<base::string16>& subtexts, | 556 suggestions_ = suggestions; |
| 551 const std::vector<base::string16>& icons, | 557 elided_values_.resize(suggestions.size()); |
| 552 const std::vector<int>& identifiers) { | 558 elided_labels_.resize(suggestions.size()); |
| 553 names_ = names; | 559 for (size_t i = 0; i < suggestions.size(); i++) { |
| 554 full_names_ = names; | 560 elided_values_[i] = suggestions[i].value; |
| 555 subtexts_ = subtexts; | 561 elided_labels_[i] = suggestions[i].label; |
| 556 icons_ = icons; | 562 } |
| 557 identifiers_ = identifiers; | |
| 558 } | 563 } |
| 559 | 564 |
| 560 void AutofillPopupControllerImpl::ShowView() { | 565 void AutofillPopupControllerImpl::ShowView() { |
| 561 view_->Show(); | 566 view_->Show(); |
| 562 } | 567 } |
| 563 | 568 |
| 564 void AutofillPopupControllerImpl::InvalidateRow(size_t row) { | 569 void AutofillPopupControllerImpl::InvalidateRow(size_t row) { |
| 565 DCHECK(0 <= row); | 570 DCHECK(0 <= row); |
| 566 DCHECK(row < identifiers_.size()); | 571 DCHECK(row < suggestions_.size()); |
| 567 view_->InvalidateRow(row); | 572 view_->InvalidateRow(row); |
| 568 } | 573 } |
| 569 | 574 |
| 570 #if !defined(OS_ANDROID) | 575 #if !defined(OS_ANDROID) |
| 571 int AutofillPopupControllerImpl::GetDesiredPopupWidth() const { | 576 int AutofillPopupControllerImpl::GetDesiredPopupWidth() const { |
| 572 int popup_width = controller_common_->RoundedElementBounds().width(); | 577 int popup_width = controller_common_->RoundedElementBounds().width(); |
| 573 DCHECK_EQ(names().size(), subtexts().size()); | 578 for (size_t i = 0; i < GetLineCount(); ++i) { |
| 574 for (size_t i = 0; i < names().size(); ++i) { | |
| 575 int row_size = | 579 int row_size = |
| 576 gfx::GetStringWidth(names()[i], name_font_list_) + | 580 gfx::GetStringWidth(GetElidedValueAt(i), value_font_list_) + |
| 577 gfx::GetStringWidth(subtexts()[i], subtext_font_list_) + | 581 gfx::GetStringWidth(GetElidedLabelAt(i), label_font_list_) + |
| 578 RowWidthWithoutText(i); | 582 RowWidthWithoutText(i); |
| 579 | 583 |
| 580 popup_width = std::max(popup_width, row_size); | 584 popup_width = std::max(popup_width, row_size); |
| 581 } | 585 } |
| 582 | 586 |
| 583 return popup_width; | 587 return popup_width; |
| 584 } | 588 } |
| 585 | 589 |
| 586 int AutofillPopupControllerImpl::GetDesiredPopupHeight() const { | 590 int AutofillPopupControllerImpl::GetDesiredPopupHeight() const { |
| 587 int popup_height = 2 * kPopupBorderThickness; | 591 int popup_height = 2 * kPopupBorderThickness; |
| 588 | 592 |
| 589 for (size_t i = 0; i < identifiers().size(); ++i) { | 593 for (size_t i = 0; i < suggestions_.size(); ++i) { |
| 590 popup_height += GetRowHeightFromId(identifiers()[i]); | 594 popup_height += GetRowHeightFromId(suggestions_[i].frontend_id); |
| 591 } | 595 } |
| 592 | 596 |
| 593 return popup_height; | 597 return popup_height; |
| 594 } | 598 } |
| 595 | 599 |
| 596 int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const { | 600 int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const { |
| 597 int row_size = kEndPadding; | 601 int row_size = kEndPadding; |
| 598 | 602 |
| 599 if (!subtexts_[row].empty()) | 603 if (!elided_labels_[row].empty()) |
| 600 row_size += kNamePadding; | 604 row_size += kNamePadding; |
| 601 | 605 |
| 602 // Add the Autofill icon size, if required. | 606 // Add the Autofill icon size, if required. |
| 603 if (!icons_[row].empty()) { | 607 const base::string16& icon = suggestions_[row].icon; |
| 608 if (!icon.empty()) { |
| 604 int icon_width = ui::ResourceBundle::GetSharedInstance().GetImageNamed( | 609 int icon_width = ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
| 605 GetIconResourceID(icons_[row])).Width(); | 610 GetIconResourceID(icon)).Width(); |
| 606 row_size += icon_width + kIconPadding; | 611 row_size += icon_width + kIconPadding; |
| 607 } | 612 } |
| 608 | 613 |
| 609 // Add the padding at the end. | 614 // Add the padding at the end. |
| 610 row_size += kEndPadding; | 615 row_size += kEndPadding; |
| 611 | 616 |
| 612 // Add room for the popup border. | 617 // Add room for the popup border. |
| 613 row_size += 2 * kPopupBorderThickness; | 618 row_size += 2 * kPopupBorderThickness; |
| 614 | 619 |
| 615 return row_size; | 620 return row_size; |
| 616 } | 621 } |
| 617 | 622 |
| 618 void AutofillPopupControllerImpl::UpdatePopupBounds() { | 623 void AutofillPopupControllerImpl::UpdatePopupBounds() { |
| 619 int popup_width = GetDesiredPopupWidth(); | 624 int popup_width = GetDesiredPopupWidth(); |
| 620 int popup_height = GetDesiredPopupHeight(); | 625 int popup_height = GetDesiredPopupHeight(); |
| 621 | 626 |
| 622 popup_bounds_ = controller_common_->GetPopupBounds(popup_width, | 627 popup_bounds_ = controller_common_->GetPopupBounds(popup_width, popup_height); |
| 623 popup_height); | |
| 624 } | 628 } |
| 625 #endif // !defined(OS_ANDROID) | 629 #endif // !defined(OS_ANDROID) |
| 626 | 630 |
| 627 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() { | 631 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() { |
| 628 return weak_ptr_factory_.GetWeakPtr(); | 632 return weak_ptr_factory_.GetWeakPtr(); |
| 629 } | 633 } |
| 630 | 634 |
| 631 void AutofillPopupControllerImpl::ClearState() { | 635 void AutofillPopupControllerImpl::ClearState() { |
| 632 // Don't clear view_, because otherwise the popup will have to get regenerated | 636 // Don't clear view_, because otherwise the popup will have to get regenerated |
| 633 // and this will cause flickering. | 637 // and this will cause flickering. |
| 634 | 638 |
| 635 popup_bounds_ = gfx::Rect(); | 639 popup_bounds_ = gfx::Rect(); |
| 636 | 640 |
| 637 names_.clear(); | 641 suggestions_.clear(); |
| 638 subtexts_.clear(); | 642 elided_values_.clear(); |
| 639 icons_.clear(); | 643 elided_labels_.clear(); |
| 640 identifiers_.clear(); | |
| 641 full_names_.clear(); | |
| 642 | 644 |
| 643 selected_line_ = kNoSelection; | 645 selected_line_ = kNoSelection; |
| 644 } | 646 } |
| 645 | 647 |
| 646 } // namespace autofill | 648 } // namespace autofill |
| OLD | NEW |