Index: chrome/browser/ui/views/autofill/autofill_popup_view_views.cc |
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc |
index 89925cee23efa839e82e4105a6ff2f6b6bc68806..b8b3837865eecb48a18de93b22f76feb3ba0fb0d 100644 |
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc |
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc |
@@ -4,10 +4,14 @@ |
#include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h" |
+#include "base/optional.h" |
#include "chrome/browser/ui/autofill/autofill_popup_controller.h" |
#include "chrome/browser/ui/autofill/autofill_popup_layout_model.h" |
+#include "chrome/grit/generated_resources.h" |
#include "components/autofill/core/browser/popup_item_ids.h" |
#include "components/autofill/core/browser/suggestion.h" |
+#include "ui/accessibility/ax_node_data.h" |
+#include "ui/base/l10n/l10n_util.h" |
#include "ui/events/keycodes/keyboard_codes.h" |
#include "ui/gfx/canvas.h" |
#include "ui/gfx/geometry/point.h" |
@@ -16,30 +20,67 @@ |
#include "ui/gfx/native_widget_types.h" |
#include "ui/gfx/text_utils.h" |
#include "ui/views/border.h" |
+#include "ui/views/view.h" |
#include "ui/views/widget/widget.h" |
namespace autofill { |
+namespace { |
+ |
+// Child view only for triggering accessibility events. Rendering is handled |
+// by |AutofillPopupViewViews|. |
+class AutofillPopupChildView : public views::View { |
+ public: |
+ explicit AutofillPopupChildView(const Suggestion& suggestion) |
+ : suggestion_(suggestion) { |
+ SetFocusBehavior(FocusBehavior::ALWAYS); |
+ } |
+ |
+ private: |
+ ~AutofillPopupChildView() override {} |
+ |
+ // views::Views implementation |
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override { |
+ node_data->role = ui::AX_ROLE_MENU_ITEM; |
+ node_data->SetName(suggestion_.value); |
+ } |
+ |
+ const Suggestion& suggestion_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AutofillPopupChildView); |
+}; |
+ |
+} // namespace |
+ |
AutofillPopupViewViews::AutofillPopupViewViews( |
AutofillPopupController* controller, |
views::Widget* parent_widget) |
: AutofillPopupBaseView(controller, parent_widget), |
- controller_(controller) {} |
+ controller_(controller) { |
+ CreateChildViews(); |
+ SetFocusBehavior(FocusBehavior::ALWAYS); |
+} |
AutofillPopupViewViews::~AutofillPopupViewViews() {} |
void AutofillPopupViewViews::Show() { |
DoShow(); |
+ NotifyAccessibilityEvent(ui::AX_EVENT_MENU_START, true); |
} |
void AutofillPopupViewViews::Hide() { |
// The controller is no longer valid after it hides us. |
controller_ = NULL; |
- |
DoHide(); |
+ NotifyAccessibilityEvent(ui::AX_EVENT_MENU_END, true); |
} |
-void AutofillPopupViewViews::UpdateBoundsAndRedrawPopup() { |
+void AutofillPopupViewViews::OnSuggestionsChanged() { |
+ // We recreate the child views so we can be sure the |controller_|'s |
+ // |GetLineCount()| will match the number of child views. Otherwise, |
+ // the number of suggestions i.e. |GetLineCount()| may not match 1x1 with the |
+ // child views. See crbug.com/697466. |
+ CreateChildViews(); |
DoUpdateBoundsAndRedrawPopup(); |
} |
@@ -51,6 +92,7 @@ void AutofillPopupViewViews::OnPaint(gfx::Canvas* canvas) { |
ui::NativeTheme::kColorId_ResultsTableNormalBackground)); |
OnPaintBorder(canvas); |
+ DCHECK_EQ(controller_->GetLineCount(), static_cast<size_t>(child_count())); |
for (size_t i = 0; i < controller_->GetLineCount(); ++i) { |
gfx::Rect line_rect = controller_->layout_model().GetRowBounds(i); |
@@ -66,8 +108,22 @@ void AutofillPopupViewViews::OnPaint(gfx::Canvas* canvas) { |
} |
} |
-void AutofillPopupViewViews::InvalidateRow(size_t row) { |
- SchedulePaintInRect(controller_->layout_model().GetRowBounds(row)); |
+void AutofillPopupViewViews::OnSelectedRowChanged( |
+ base::Optional<size_t> previous_row_selection, |
+ base::Optional<size_t> current_row_selection) { |
+ if (previous_row_selection && |
+ previous_row_selection < controller_->GetLineCount()) { |
+ SchedulePaintInRect( |
+ controller_->layout_model().GetRowBounds(*previous_row_selection)); |
+ } |
+ |
+ if (current_row_selection) { |
+ SchedulePaintInRect( |
+ controller_->layout_model().GetRowBounds(*current_row_selection)); |
+ DCHECK_LT(*current_row_selection, static_cast<size_t>(child_count())); |
+ child_at(*current_row_selection) |
+ ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); |
+ } |
} |
/** |
@@ -189,6 +245,20 @@ void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas, |
} |
} |
+void AutofillPopupViewViews::GetAccessibleNodeData(ui::AXNodeData* node_data) { |
+ node_data->role = ui::AX_ROLE_MENU; |
+ node_data->SetName( |
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_POPUP_ACCESSIBLE_NODE_DATA)); |
+} |
+ |
+void AutofillPopupViewViews::CreateChildViews() { |
+ RemoveAllChildViews(true /* delete_children */); |
+ |
+ for (size_t i = 0; i < controller_->GetLineCount(); ++i) { |
+ AddChildView(new AutofillPopupChildView(controller_->GetSuggestionAt(i))); |
+ } |
+} |
+ |
AutofillPopupView* AutofillPopupView::Create( |
AutofillPopupController* controller) { |
views::Widget* observing_widget = |