Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Side by Side Diff: chrome/browser/ui/autofill/autofill_popup_controller_impl.cc

Issue 1570783003: [Autofill] Move functions from the AutofillPopupController to AutofillPopupLayoutModel (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: remove scoped_ptr and rename mac delegate Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/command_line.h" 10 #include "base/command_line.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "build/build_config.h" 14 #include "build/build_config.h"
15 #include "chrome/browser/ui/autofill/autofill_popup_view.h" 15 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
16 #include "chrome/browser/ui/autofill/popup_constants.h"
17 #include "components/autofill/core/browser/autofill_popup_delegate.h" 16 #include "components/autofill/core/browser/autofill_popup_delegate.h"
18 #include "components/autofill/core/browser/popup_item_ids.h" 17 #include "components/autofill/core/browser/popup_item_ids.h"
19 #include "components/autofill/core/browser/suggestion.h" 18 #include "components/autofill/core/browser/suggestion.h"
20 #include "components/autofill/core/common/autofill_util.h"
21 #include "content/public/browser/native_web_keyboard_event.h" 19 #include "content/public/browser/native_web_keyboard_event.h"
22 #include "grit/components_scaled_resources.h"
23 #include "ui/base/resource/resource_bundle.h"
24 #include "ui/events/event.h" 20 #include "ui/events/event.h"
25 #include "ui/gfx/geometry/rect_conversions.h"
26 #include "ui/gfx/geometry/vector2d.h"
27 #include "ui/gfx/screen.h"
28 #include "ui/gfx/text_elider.h" 21 #include "ui/gfx/text_elider.h"
29 #include "ui/gfx/text_utils.h" 22 #include "ui/gfx/text_utils.h"
30 23
31 using base::WeakPtr; 24 using base::WeakPtr;
32 25
33 namespace autofill { 26 namespace autofill {
34 namespace { 27 namespace {
35 28
36 // Used to indicate that no line is currently selected by the user. 29 // Used to indicate that no line is currently selected by the user.
37 const int kNoSelection = -1; 30 const int kNoSelection = -1;
38 31
39 // The vertical height of each row in pixels.
40 const size_t kRowHeight = 24;
41
42 // The vertical height of a separator in pixels.
43 const size_t kSeparatorHeight = 1;
44 32
45 #if !defined(OS_ANDROID) 33 #if !defined(OS_ANDROID)
46 // Size difference between name and label in pixels. 34 // Size difference between name and label in pixels.
47 const int kLabelFontSizeDelta = -2; 35 const int kLabelFontSizeDelta = -2;
48
49 const size_t kNamePadding = AutofillPopupView::kNamePadding;
50 const size_t kIconPadding = AutofillPopupView::kIconPadding;
51 const size_t kEndPadding = AutofillPopupView::kEndPadding;
52 #endif 36 #endif
53 37
54 struct DataResource {
55 const char* name;
56 int id;
57 };
58
59 const DataResource kDataResources[] = {
60 { "americanExpressCC", IDR_AUTOFILL_CC_AMEX },
61 { "dinersCC", IDR_AUTOFILL_CC_GENERIC },
62 { "discoverCC", IDR_AUTOFILL_CC_DISCOVER },
63 { "genericCC", IDR_AUTOFILL_CC_GENERIC },
64 { "jcbCC", IDR_AUTOFILL_CC_GENERIC },
65 { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD },
66 { "visaCC", IDR_AUTOFILL_CC_VISA },
67 #if defined(OS_ANDROID)
68 { "scanCreditCardIcon", IDR_AUTOFILL_CC_SCAN_NEW },
69 { "settings", IDR_AUTOFILL_SETTINGS },
70 #endif
71 };
72
73 } // namespace 38 } // namespace
74 39
75 // static 40 // static
76 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetOrCreate( 41 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetOrCreate(
77 WeakPtr<AutofillPopupControllerImpl> previous, 42 WeakPtr<AutofillPopupControllerImpl> previous,
78 WeakPtr<AutofillPopupDelegate> delegate, 43 WeakPtr<AutofillPopupDelegate> delegate,
79 content::WebContents* web_contents, 44 content::WebContents* web_contents,
80 gfx::NativeView container_view, 45 gfx::NativeView container_view,
81 const gfx::RectF& element_bounds, 46 const gfx::RectF& element_bounds,
82 base::i18n::TextDirection text_direction) { 47 base::i18n::TextDirection text_direction) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 } 93 }
129 94
130 AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {} 95 AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {}
131 96
132 void AutofillPopupControllerImpl::Show( 97 void AutofillPopupControllerImpl::Show(
133 const std::vector<autofill::Suggestion>& suggestions) { 98 const std::vector<autofill::Suggestion>& suggestions) {
134 SetValues(suggestions); 99 SetValues(suggestions);
135 DCHECK_EQ(suggestions_.size(), elided_values_.size()); 100 DCHECK_EQ(suggestions_.size(), elided_values_.size());
136 DCHECK_EQ(suggestions_.size(), elided_labels_.size()); 101 DCHECK_EQ(suggestions_.size(), elided_labels_.size());
137 102
138 #if !defined(OS_ANDROID) 103 bool just_created = false;
139 // Android displays the long text with ellipsis using the view attributes.
140
141 UpdatePopupBounds();
142 int popup_width = popup_bounds().width();
143
144 // Elide the name and label strings so that the popup fits in the available
145 // space.
146 for (size_t i = 0; i < suggestions_.size(); ++i) {
147 int value_width =
148 gfx::GetStringWidth(suggestions_[i].value, GetValueFontListForRow(i));
149 int label_width =
150 gfx::GetStringWidth(suggestions_[i].label, GetLabelFontList());
151 int total_text_length = value_width + label_width;
152
153 // The line can have no strings if it represents a UI element, such as
154 // a separator line.
155 if (total_text_length == 0)
156 continue;
157
158 int available_width = popup_width - RowWidthWithoutText(i);
159
160 // Each field receives space in proportion to its length.
161 int value_size = available_width * value_width / total_text_length;
162 elided_values_[i] = gfx::ElideText(suggestions_[i].value,
163 GetValueFontListForRow(i),
164 value_size, gfx::ELIDE_TAIL);
165
166 int label_size = available_width * label_width / total_text_length;
167 elided_labels_[i] = gfx::ElideText(suggestions_[i].label,
168 GetLabelFontList(),
169 label_size, gfx::ELIDE_TAIL);
170 }
171 #endif
172
173 if (!view_) { 104 if (!view_) {
174 view_ = AutofillPopupView::Create(this); 105 view_ = AutofillPopupView::Create(this);
175 106
176 // It is possible to fail to create the popup, in this case 107 // It is possible to fail to create the popup, in this case
177 // treat the popup as hiding right away. 108 // treat the popup as hiding right away.
178 if (!view_) { 109 if (!view_) {
179 Hide(); 110 Hide();
180 return; 111 return;
181 } 112 }
113 just_created = true;
114 }
182 115
116 #if !defined(OS_ANDROID)
117 // Android displays the long text with ellipsis using the view attributes.
118
119 view_->UpdatePopupBounds();
120
121 // Elide the name and label strings so that the popup fits in the available
122 // space.
123 for (size_t i = 0; i < suggestions_.size(); ++i) {
124 bool has_label = !suggestions_[i].label.empty();
125 ElideValueAndLabelForRow(i, view_->GetAvailableWidthForRow(i, has_label));
126 }
127 #endif
128
129 if (just_created) {
183 ShowView(); 130 ShowView();
184 } else { 131 } else {
185 UpdateBoundsAndRedrawPopup(); 132 UpdateBoundsAndRedrawPopup();
186 } 133 }
187 134
188 controller_common_->RegisterKeyPressCallback(); 135 controller_common_->RegisterKeyPressCallback();
189 delegate_->OnPopupShown(); 136 delegate_->OnPopupShown();
190 137
191 DCHECK_EQ(suggestions_.size(), elided_values_.size()); 138 DCHECK_EQ(suggestions_.size(), elided_values_.size());
192 DCHECK_EQ(suggestions_.size(), elided_labels_.size()); 139 DCHECK_EQ(suggestions_.size(), elided_labels_.size());
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 return false; 257 return false;
311 } 258 }
312 } 259 }
313 260
314 void AutofillPopupControllerImpl::UpdateBoundsAndRedrawPopup() { 261 void AutofillPopupControllerImpl::UpdateBoundsAndRedrawPopup() {
315 #if !defined(OS_ANDROID) 262 #if !defined(OS_ANDROID)
316 // TODO(csharp): Since UpdatePopupBounds can change the position of the popup, 263 // TODO(csharp): Since UpdatePopupBounds can change the position of the popup,
317 // the popup could end up jumping from above the element to below it. 264 // the popup could end up jumping from above the element to below it.
318 // It is unclear if it is better to keep the popup where it was, or if it 265 // It is unclear if it is better to keep the popup where it was, or if it
319 // should try and move to its desired position. 266 // should try and move to its desired position.
320 UpdatePopupBounds(); 267 view_->UpdatePopupBounds();
321 #endif 268 #endif
322 269
270 // Platform-specific draw call.
323 view_->UpdateBoundsAndRedrawPopup(); 271 view_->UpdateBoundsAndRedrawPopup();
324 } 272 }
325 273
326 void AutofillPopupControllerImpl::SetSelectionAtPoint(const gfx::Point& point) { 274 void AutofillPopupControllerImpl::SetSelectionAtPoint(const gfx::Point& point) {
327 SetSelectedLine(LineFromY(point.y())); 275 SetSelectedLine(view_->LineFromY(point.y()));
Evan Stade 2016/01/13 04:30:27 so in Model-View-Controller (or Model-View-Present
Mathieu 2016/01/13 17:04:27 I think we should move towards having the PopupCon
Evan Stade 2016/01/13 18:18:56 To me it's a code smell when you have to add a lot
328 } 276 }
329 277
330 bool AutofillPopupControllerImpl::AcceptSelectedLine() { 278 bool AutofillPopupControllerImpl::AcceptSelectedLine() {
331 if (selected_line_ == kNoSelection) 279 if (selected_line_ == kNoSelection)
332 return false; 280 return false;
333 281
334 DCHECK_GE(selected_line_, 0); 282 DCHECK_GE(selected_line_, 0);
335 DCHECK_LT(selected_line_, static_cast<int>(GetLineCount())); 283 DCHECK_LT(selected_line_, static_cast<int>(GetLineCount()));
336 284
337 if (!CanAccept(suggestions_[selected_line_].frontend_id)) 285 if (!CanAccept(suggestions_[selected_line_].frontend_id))
338 return false; 286 return false;
339 287
340 AcceptSuggestion(selected_line_); 288 AcceptSuggestion(selected_line_);
341 return true; 289 return true;
342 } 290 }
343 291
344 void AutofillPopupControllerImpl::SelectionCleared() { 292 void AutofillPopupControllerImpl::SelectionCleared() {
345 SetSelectedLine(kNoSelection); 293 SetSelectedLine(kNoSelection);
346 } 294 }
347 295
348 void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) { 296 void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) {
349 const autofill::Suggestion& suggestion = suggestions_[index]; 297 const autofill::Suggestion& suggestion = suggestions_[index];
350 delegate_->DidAcceptSuggestion(suggestion.value, suggestion.frontend_id, 298 delegate_->DidAcceptSuggestion(suggestion.value, suggestion.frontend_id,
351 index); 299 index);
352 } 300 }
353 301
354 int AutofillPopupControllerImpl::GetIconResourceID(
355 const base::string16& resource_name) const {
356 int result = -1;
357 for (size_t i = 0; i < arraysize(kDataResources); ++i) {
358 if (resource_name == base::ASCIIToUTF16(kDataResources[i].name)) {
359 result = kDataResources[i].id;
360 break;
361 }
362 }
363
364 #if defined(OS_ANDROID)
365 if (result == IDR_AUTOFILL_CC_SCAN_NEW && IsKeyboardAccessoryEnabled())
366 result = IDR_AUTOFILL_CC_SCAN_NEW_KEYBOARD_ACCESSORY;
367 #endif // OS_ANDROID
368
369 return result;
370 }
371
372 bool AutofillPopupControllerImpl::IsWarning(size_t index) const { 302 bool AutofillPopupControllerImpl::IsWarning(size_t index) const {
373 return suggestions_[index].frontend_id == POPUP_ITEM_ID_WARNING_MESSAGE; 303 return suggestions_[index].frontend_id == POPUP_ITEM_ID_WARNING_MESSAGE;
374 } 304 }
375 305
376 gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) { 306 gfx::Rect AutofillPopupControllerImpl::popup_bounds() const {
377 int top = kPopupBorderThickness; 307 return view_->GetPopupBounds();
378 for (size_t i = 0; i < index; ++i) {
379 top += GetRowHeightFromId(suggestions_[i].frontend_id);
380 }
381
382 return gfx::Rect(
383 kPopupBorderThickness,
384 top,
385 popup_bounds_.width() - 2 * kPopupBorderThickness,
386 GetRowHeightFromId(suggestions_[index].frontend_id));
387 }
388
389 const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const {
390 return popup_bounds_;
391 } 308 }
392 309
393 content::WebContents* AutofillPopupControllerImpl::web_contents() { 310 content::WebContents* AutofillPopupControllerImpl::web_contents() {
394 return controller_common_->web_contents(); 311 return controller_common_->web_contents();
395 } 312 }
396 313
397 gfx::NativeView AutofillPopupControllerImpl::container_view() { 314 gfx::NativeView AutofillPopupControllerImpl::container_view() {
398 return controller_common_->container_view(); 315 return controller_common_->container_view();
399 } 316 }
400 317
401 const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const { 318 const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const {
402 return controller_common_->element_bounds(); 319 return controller_common_->element_bounds();
403 } 320 }
404 321
405 bool AutofillPopupControllerImpl::IsRTL() const { 322 bool AutofillPopupControllerImpl::IsRTL() const {
406 return controller_common_->is_rtl(); 323 return controller_common_->is_rtl();
407 } 324 }
408 325
326 const std::vector<autofill::Suggestion>
327 AutofillPopupControllerImpl::GetSuggestions() {
328 return suggestions_;
329 }
330
331 #if !defined(OS_ANDROID)
332 int AutofillPopupControllerImpl::GetElidedValueWidthForRow(size_t row) {
333 return gfx::GetStringWidth(GetElidedValueAt(row), value_font_list_);
334 }
335
336 int AutofillPopupControllerImpl::GetElidedLabelWidthForRow(size_t row) {
337 return gfx::GetStringWidth(GetElidedValueAt(row), label_font_list_);
338 }
339 #endif
340
409 size_t AutofillPopupControllerImpl::GetLineCount() const { 341 size_t AutofillPopupControllerImpl::GetLineCount() const {
410 return suggestions_.size(); 342 return suggestions_.size();
411 } 343 }
412 344
413 const autofill::Suggestion& AutofillPopupControllerImpl::GetSuggestionAt( 345 const autofill::Suggestion& AutofillPopupControllerImpl::GetSuggestionAt(
414 size_t row) const { 346 size_t row) const {
415 return suggestions_[row]; 347 return suggestions_[row];
416 } 348 }
417 349
418 const base::string16& AutofillPopupControllerImpl::GetElidedValueAt( 350 const base::string16& AutofillPopupControllerImpl::GetElidedValueAt(
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 467
536 bool AutofillPopupControllerImpl::RemoveSelectedLine() { 468 bool AutofillPopupControllerImpl::RemoveSelectedLine() {
537 if (selected_line_ == kNoSelection) 469 if (selected_line_ == kNoSelection)
538 return false; 470 return false;
539 471
540 DCHECK_GE(selected_line_, 0); 472 DCHECK_GE(selected_line_, 0);
541 DCHECK_LT(selected_line_, static_cast<int>(GetLineCount())); 473 DCHECK_LT(selected_line_, static_cast<int>(GetLineCount()));
542 return RemoveSuggestion(selected_line_); 474 return RemoveSuggestion(selected_line_);
543 } 475 }
544 476
545 int AutofillPopupControllerImpl::LineFromY(int y) {
546 int current_height = kPopupBorderThickness;
547
548 for (size_t i = 0; i < suggestions_.size(); ++i) {
549 current_height += GetRowHeightFromId(suggestions_[i].frontend_id);
550
551 if (y <= current_height)
552 return i;
553 }
554
555 // The y value goes beyond the popup so stop the selection at the last line.
556 return GetLineCount() - 1;
557 }
558
559 int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const {
560 if (identifier == POPUP_ITEM_ID_SEPARATOR)
561 return kSeparatorHeight;
562
563 return kRowHeight;
564 }
565
566 bool AutofillPopupControllerImpl::CanAccept(int id) { 477 bool AutofillPopupControllerImpl::CanAccept(int id) {
567 return id != POPUP_ITEM_ID_SEPARATOR && id != POPUP_ITEM_ID_WARNING_MESSAGE && 478 return id != POPUP_ITEM_ID_SEPARATOR && id != POPUP_ITEM_ID_WARNING_MESSAGE &&
568 id != POPUP_ITEM_ID_TITLE; 479 id != POPUP_ITEM_ID_TITLE;
569 } 480 }
570 481
571 bool AutofillPopupControllerImpl::HasSuggestions() { 482 bool AutofillPopupControllerImpl::HasSuggestions() {
572 if (suggestions_.empty()) 483 if (suggestions_.empty())
573 return false; 484 return false;
574 int id = suggestions_[0].frontend_id; 485 int id = suggestions_[0].frontend_id;
575 return id > 0 || 486 return id > 0 ||
(...skipping 17 matching lines...) Expand all
593 void AutofillPopupControllerImpl::ShowView() { 504 void AutofillPopupControllerImpl::ShowView() {
594 view_->Show(); 505 view_->Show();
595 } 506 }
596 507
597 void AutofillPopupControllerImpl::InvalidateRow(size_t row) { 508 void AutofillPopupControllerImpl::InvalidateRow(size_t row) {
598 DCHECK(0 <= row); 509 DCHECK(0 <= row);
599 DCHECK(row < suggestions_.size()); 510 DCHECK(row < suggestions_.size());
600 view_->InvalidateRow(row); 511 view_->InvalidateRow(row);
601 } 512 }
602 513
603 #if !defined(OS_ANDROID)
604 int AutofillPopupControllerImpl::GetDesiredPopupWidth() const {
605 int popup_width = controller_common_->RoundedElementBounds().width();
606 for (size_t i = 0; i < GetLineCount(); ++i) {
607 int row_size =
608 gfx::GetStringWidth(GetElidedValueAt(i), value_font_list_) +
609 gfx::GetStringWidth(GetElidedLabelAt(i), label_font_list_) +
610 RowWidthWithoutText(i);
611
612 popup_width = std::max(popup_width, row_size);
613 }
614
615 return popup_width;
616 }
617
618 int AutofillPopupControllerImpl::GetDesiredPopupHeight() const {
619 int popup_height = 2 * kPopupBorderThickness;
620
621 for (size_t i = 0; i < suggestions_.size(); ++i) {
622 popup_height += GetRowHeightFromId(suggestions_[i].frontend_id);
623 }
624
625 return popup_height;
626 }
627
628 int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const {
629 int row_size = kEndPadding;
630
631 if (!elided_labels_[row].empty())
632 row_size += kNamePadding;
633
634 // Add the Autofill icon size, if required.
635 const base::string16& icon = suggestions_[row].icon;
636 if (!icon.empty()) {
637 int icon_width = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
638 GetIconResourceID(icon)).Width();
639 row_size += icon_width + kIconPadding;
640 }
641
642 // Add the padding at the end.
643 row_size += kEndPadding;
644
645 // Add room for the popup border.
646 row_size += 2 * kPopupBorderThickness;
647
648 return row_size;
649 }
650
651 void AutofillPopupControllerImpl::UpdatePopupBounds() {
652 int popup_width = GetDesiredPopupWidth();
653 int popup_height = GetDesiredPopupHeight();
654
655 popup_bounds_ = controller_common_->GetPopupBounds(popup_width, popup_height);
656 }
657 #endif // !defined(OS_ANDROID)
658
659 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() { 514 WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() {
660 return weak_ptr_factory_.GetWeakPtr(); 515 return weak_ptr_factory_.GetWeakPtr();
661 } 516 }
662 517
518 #if !defined(OS_ANDROID)
519 void AutofillPopupControllerImpl::ElideValueAndLabelForRow(
520 size_t row,
521 int available_width) {
522 int value_width =
523 gfx::GetStringWidth(suggestions_[row].value, GetValueFontListForRow(row));
524 int label_width =
525 gfx::GetStringWidth(suggestions_[row].label, GetLabelFontList());
526 int total_text_length = value_width + label_width;
527
528 // The line can have no strings if it represents a UI element, such as
529 // a separator line.
530 if (total_text_length == 0)
531 return;
532
533 // Each field receives space in proportion to its length.
534 int value_size = available_width * value_width / total_text_length;
535 elided_values_[row] =
536 gfx::ElideText(suggestions_[row].value, GetValueFontListForRow(row),
537 value_size, gfx::ELIDE_TAIL);
538
539 int label_size = available_width * label_width / total_text_length;
540 elided_labels_[row] = gfx::ElideText(
541 suggestions_[row].label, GetLabelFontList(), label_size, gfx::ELIDE_TAIL);
542 }
543 #endif
544
663 void AutofillPopupControllerImpl::ClearState() { 545 void AutofillPopupControllerImpl::ClearState() {
664 // Don't clear view_, because otherwise the popup will have to get regenerated 546 // Don't clear view_, because otherwise the popup will have to get regenerated
665 // and this will cause flickering. 547 // and this will cause flickering.
666
667 popup_bounds_ = gfx::Rect();
668
669 suggestions_.clear(); 548 suggestions_.clear();
670 elided_values_.clear(); 549 elided_values_.clear();
671 elided_labels_.clear(); 550 elided_labels_.clear();
672 551
673 selected_line_ = kNoSelection; 552 selected_line_ = kNoSelection;
674 } 553 }
675 554
676 } // namespace autofill 555 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698