summaryrefslogtreecommitdiff
path: root/chromium/ui/views
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-06 12:48:11 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:33:43 +0000
commit7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (patch)
treefa14ba0ca8d2683ba2efdabd246dc9b18a1229c6 /chromium/ui/views
parent79b4f909db1049fca459c07cca55af56a9b54fe3 (diff)
downloadqtwebengine-chromium-7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3.tar.gz
BASELINE: Update Chromium to 84.0.4147.141
Change-Id: Ib85eb4cfa1cbe2b2b81e5022c8cad5c493969535 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/ui/views')
-rw-r--r--chromium/ui/views/BUILD.gn67
-rw-r--r--chromium/ui/views/accessibility/accessibility_alert_window.cc2
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.cc18
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc70
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_wrapper.h1
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.cc4
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.h1
-rw-r--r--chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc28
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views.cc4
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views.h1
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.cc4
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.h1
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view.cc69
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view.h2
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view_unittest.cc45
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc5
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view_wrapper.h1
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc4
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.h1
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc18
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.h1
-rw-r--r--chromium/ui/views/accessibility/test_list_grid_view.cc57
-rw-r--r--chromium/ui/views/accessibility/test_list_grid_view.h40
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc80
-rw-r--r--chromium/ui/views/accessibility/views_ax_tree_manager.cc3
-rw-r--r--chromium/ui/views/animation/bounds_animator.cc68
-rw-r--r--chromium/ui/views/animation/bounds_animator.h4
-rw-r--r--chromium/ui/views/animation/bounds_animator_unittest.cc111
-rw-r--r--chromium/ui/views/animation/ink_drop.h3
-rw-r--r--chromium/ui/views/animation/ink_drop_animation_ended_reason.cc4
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.cc21
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view_unittest.cc4
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.cc6
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.h1
-rw-r--r--chromium/ui/views/animation/ink_drop_state.cc3
-rw-r--r--chromium/ui/views/animation/ink_drop_stub.cc2
-rw-r--r--chromium/ui/views/animation/ink_drop_stub.h1
-rw-r--r--chromium/ui/views/animation/ink_drop_util.cc2
-rw-r--r--chromium/ui/views/animation/installable_ink_drop.cc6
-rw-r--r--chromium/ui/views/animation/installable_ink_drop.h1
-rw-r--r--chromium/ui/views/animation/installable_ink_drop_animator.cc3
-rw-r--r--chromium/ui/views/animation/scroll_animator.cc2
-rw-r--r--chromium/ui/views/background.cc2
-rw-r--r--chromium/ui/views/border.cc2
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc3
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.cc87
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.h4
-rw-r--r--chromium/ui/views/bubble/footnote_container_view.cc8
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.cc6
-rw-r--r--chromium/ui/views/controls/button/button_controller.cc3
-rw-r--r--chromium/ui/views/controls/button/button_unittest.cc190
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc2
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.cc1
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.h11
-rw-r--r--chromium/ui/views/controls/button/label_button_border.cc1
-rw-r--r--chromium/ui/views/controls/button/md_text_button.cc27
-rw-r--r--chromium/ui/views/controls/button/md_text_button.h12
-rw-r--r--chromium/ui/views/controls/button/radio_button.cc2
-rw-r--r--chromium/ui/views/controls/button/toggle_button.cc2
-rw-r--r--chromium/ui/views/controls/combobox/combobox.cc7
-rw-r--r--chromium/ui/views/controls/editable_combobox/editable_combobox.cc14
-rw-r--r--chromium/ui/views/controls/editable_combobox/editable_combobox.h2
-rw-r--r--chromium/ui/views/controls/highlight_path_generator.cc55
-rw-r--r--chromium/ui/views/controls/highlight_path_generator.h34
-rw-r--r--chromium/ui/views/controls/image_view.cc2
-rw-r--r--chromium/ui/views/controls/label.cc22
-rw-r--r--chromium/ui/views/controls/label.h9
-rw-r--r--chromium/ui/views/controls/label_unittest.cc40
-rw-r--r--chromium/ui/views/controls/link.cc54
-rw-r--r--chromium/ui/views/controls/link.h25
-rw-r--r--chromium/ui/views/controls/menu/menu_closure_animation_mac.mm3
-rw-r--r--chromium/ui/views/controls/menu/menu_config.h3
-rw-r--r--chromium/ui/views/controls/menu/menu_config_win.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc35
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc117
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_host_root_view.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_host_root_view.h2
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc17
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc4
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm3
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc12
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.h2
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.cc2
-rw-r--r--chromium/ui/views/controls/message_box_view.cc4
-rw-r--r--chromium/ui/views/controls/native/native_view_host.cc2
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.cc2
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura_unittest.cc2
-rw-r--r--chromium/ui/views/controls/progress_bar.cc31
-rw-r--r--chromium/ui/views/controls/progress_bar.h9
-rw-r--r--chromium/ui/views/controls/progress_bar_unittest.cc112
-rw-r--r--chromium/ui/views/controls/resize_area.cc1
-rw-r--r--chromium/ui/views/controls/scroll_view.cc2
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc50
-rw-r--r--chromium/ui/views/controls/scrollbar/scroll_bar_views.cc3
-rw-r--r--chromium/ui/views/controls/slider.cc2
-rw-r--r--chromium/ui/views/controls/styled_label.cc3
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc2
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.h4
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc159
-rw-r--r--chromium/ui/views/controls/table/table_utils.cc2
-rw-r--r--chromium/ui/views/controls/table/table_view.cc24
-rw-r--r--chromium/ui/views/controls/table/table_view.h5
-rw-r--r--chromium/ui/views/controls/table/table_view_unittest.cc24
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc225
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h32
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.cc354
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.h75
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model_unittest.cc713
-rw-r--r--chromium/ui/views/controls/textfield/textfield_test_api.cc6
-rw-r--r--chromium/ui/views/controls/textfield/textfield_test_api.h8
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc193
-rw-r--r--chromium/ui/views/controls/tree/tree_view.cc11
-rw-r--r--chromium/ui/views/controls/tree/tree_view.h2
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu.cc2
-rw-r--r--chromium/ui/views/controls/webview/BUILD.gn2
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc4
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.cc7
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.h1
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view_unittest.cc2
-rw-r--r--chromium/ui/views/corewm/DEPS2
-rw-r--r--chromium/ui/views/corewm/desktop_capture_controller_unittest.cc9
-rw-r--r--chromium/ui/views/corewm/tooltip_aura.cc22
-rw-r--r--chromium/ui/views/corewm/tooltip_controller.cc7
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_test_helper.cc5
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_test_helper.h1
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_unittest.cc30
-rw-r--r--chromium/ui/views/debug_utils.cc8
-rw-r--r--chromium/ui/views/debug_utils.h3
-rw-r--r--chromium/ui/views/event_monitor_aura.cc2
-rw-r--r--chromium/ui/views/event_monitor_mac.mm2
-rw-r--r--chromium/ui/views/examples/BUILD.gn125
-rw-r--r--chromium/ui/views/examples/DEPS2
-rw-r--r--chromium/ui/views/examples/box_layout_example.cc24
-rw-r--r--chromium/ui/views/examples/bubble_example.cc26
-rw-r--r--chromium/ui/views/examples/button_sticker_sheet.cc3
-rw-r--r--chromium/ui/views/examples/checkbox_example.cc4
-rw-r--r--chromium/ui/views/examples/colored_dialog_example.cc176
-rw-r--r--chromium/ui/views/examples/colored_dialog_example.h77
-rw-r--r--chromium/ui/views/examples/combobox_example.cc15
-rw-r--r--chromium/ui/views/examples/create_examples.cc80
-rw-r--r--chromium/ui/views/examples/create_examples.h24
-rw-r--r--chromium/ui/views/examples/dialog_example.cc14
-rw-r--r--chromium/ui/views/examples/example_base.h3
-rw-r--r--chromium/ui/views/examples/examples_exit_code.h25
-rw-r--r--chromium/ui/views/examples/examples_main.cc159
-rw-r--r--chromium/ui/views/examples/examples_main_proc.cc198
-rw-r--r--chromium/ui/views/examples/examples_main_proc.h18
-rw-r--r--chromium/ui/views/examples/examples_skia_gold_pixel_diff.cc60
-rw-r--r--chromium/ui/views/examples/examples_skia_gold_pixel_diff.h39
-rw-r--r--chromium/ui/views/examples/examples_unittest.cc26
-rw-r--r--chromium/ui/views/examples/examples_unittest_main.cc14
-rw-r--r--chromium/ui/views/examples/examples_window.cc126
-rw-r--r--chromium/ui/views/examples/examples_window.h10
-rw-r--r--chromium/ui/views/examples/examples_window_with_content.cc10
-rw-r--r--chromium/ui/views/examples/examples_window_with_content.h1
-rw-r--r--chromium/ui/views/examples/examples_with_content_main.cc (renamed from chromium/ui/views/examples/examples_with_content_main_exe.cc)35
-rw-r--r--chromium/ui/views/examples/flex_layout_example.cc18
-rw-r--r--chromium/ui/views/examples/label_example.cc12
-rw-r--r--chromium/ui/views/examples/layout_example_base.cc145
-rw-r--r--chromium/ui/views/examples/layout_example_base.h49
-rw-r--r--chromium/ui/views/examples/link_example.cc14
-rw-r--r--chromium/ui/views/examples/login_bubble_dialog.cc164
-rw-r--r--chromium/ui/views/examples/login_bubble_dialog.h71
-rw-r--r--chromium/ui/views/examples/menu_example.cc35
-rw-r--r--chromium/ui/views/examples/message_box_example.cc38
-rw-r--r--chromium/ui/views/examples/multiline_example.cc24
-rw-r--r--chromium/ui/views/examples/native_theme_example.cc11
-rw-r--r--chromium/ui/views/examples/progress_bar_example.cc20
-rw-r--r--chromium/ui/views/examples/radio_button_example.cc18
-rw-r--r--chromium/ui/views/examples/scroll_view_example.cc38
-rw-r--r--chromium/ui/views/examples/slider_example.cc11
-rw-r--r--chromium/ui/views/examples/tabbed_pane_example.cc37
-rw-r--r--chromium/ui/views/examples/tabbed_pane_example.h2
-rw-r--r--chromium/ui/views/examples/table_example.cc10
-rw-r--r--chromium/ui/views/examples/text_example.cc6
-rw-r--r--chromium/ui/views/examples/textfield_example.cc119
-rw-r--r--chromium/ui/views/examples/textfield_example.h2
-rw-r--r--chromium/ui/views/examples/throbber_example.cc12
-rw-r--r--chromium/ui/views/examples/toggle_button_example.cc9
-rw-r--r--chromium/ui/views/examples/tree_view_example.cc67
-rw-r--r--chromium/ui/views/examples/vector_example.cc26
-rw-r--r--chromium/ui/views/examples/views_examples_resources.grd411
-rw-r--r--chromium/ui/views/examples/webview_example.cc4
-rw-r--r--chromium/ui/views/examples/widget_example.cc37
-rw-r--r--chromium/ui/views/examples/widget_example.h2
-rw-r--r--chromium/ui/views/focus/external_focus_tracker.cc2
-rw-r--r--chromium/ui/views/focus/focus_manager.cc43
-rw-r--r--chromium/ui/views/focus/focus_manager.h20
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest.cc197
-rw-r--r--chromium/ui/views/layout/animating_layout_manager.cc143
-rw-r--r--chromium/ui/views/layout/animating_layout_manager.h39
-rw-r--r--chromium/ui/views/layout/animating_layout_manager_unittest.cc603
-rw-r--r--chromium/ui/views/layout/box_layout.cc30
-rw-r--r--chromium/ui/views/layout/flex_layout.cc3
-rw-r--r--chromium/ui/views/layout/grid_layout.cc22
-rw-r--r--chromium/ui/views/layout/grid_layout.h20
-rw-r--r--chromium/ui/views/layout/grid_layout_unittest.cc179
-rw-r--r--chromium/ui/views/layout/layout_manager_base.cc2
-rw-r--r--chromium/ui/views/layout/layout_manager_base.h1
-rw-r--r--chromium/ui/views/layout/proposed_layout.cc1
-rw-r--r--chromium/ui/views/metadata/metadata_cache.cc2
-rw-r--r--chromium/ui/views/metadata/metadata_types.cc2
-rw-r--r--chromium/ui/views/metadata/type_conversion.cc2
-rw-r--r--chromium/ui/views/native_cursor_aura.cc2
-rw-r--r--chromium/ui/views/painter.cc2
-rw-r--r--chromium/ui/views/style/typography.cc2
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc12
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.h7
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_views.cc23
-rw-r--r--chromium/ui/views/vector_icons/linux_shutdown.icon16
-rw-r--r--chromium/ui/views/view.cc26
-rw-r--r--chromium/ui/views/view.h6
-rw-r--r--chromium/ui/views/view_model.cc2
-rw-r--r--chromium/ui/views/view_unittest.cc169
-rw-r--r--chromium/ui/views/views_features.cc6
-rw-r--r--chromium/ui/views/views_features.h1
-rw-r--r--chromium/ui/views/widget/any_widget_observer_unittest.cc2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc28
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h14
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc40
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc17
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.h28
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc20
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_win.h11
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc27
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc42
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h14
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc43
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h12
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc19
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc53
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h9
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc31
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc4
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc37
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_move_client_platform.h37
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc56
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h59
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_move_loop.h34
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_move_loop_delegate.h32
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc92
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h56
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc77
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc275
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h105
-rw-r--r--chromium/ui/views/widget/desktop_widget_unittest.cc6
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc2
-rw-r--r--chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc7
-rw-r--r--chromium/ui/views/widget/native_widget_aura_unittest.cc12
-rw-r--r--chromium/ui/views/widget/native_widget_mac_unittest.mm65
-rw-r--r--chromium/ui/views/widget/tooltip_manager_aura.cc1
-rw-r--r--chromium/ui/views/widget/widget.cc20
-rw-r--r--chromium/ui/views/widget/widget.h17
-rw-r--r--chromium/ui/views/widget/widget_aura_utils.cc2
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc107
-rw-r--r--chromium/ui/views/widget/widget_delegate.h89
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc823
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc269
-rw-r--r--chromium/ui/views/win/fullscreen_handler.cc1
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc61
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.h9
-rw-r--r--chromium/ui/views/win/pen_event_processor.cc8
-rw-r--r--chromium/ui/views/win/pen_event_processor_unittest.cc4
-rw-r--r--chromium/ui/views/win/scoped_fullscreen_visibility.cc2
-rw-r--r--chromium/ui/views/window/caption_button_layout_constants.cc1
-rw-r--r--chromium/ui/views/window/client_view.cc2
-rw-r--r--chromium/ui/views/window/dialog_client_view.cc12
-rw-r--r--chromium/ui/views/window/dialog_client_view_unittest.cc110
-rw-r--r--chromium/ui/views/window/dialog_delegate.cc27
-rw-r--r--chromium/ui/views/window/dialog_delegate.h19
-rw-r--r--chromium/ui/views/window/dialog_delegate_unittest.cc11
-rw-r--r--chromium/ui/views/window/window_resize_utils.cc1
282 files changed, 7173 insertions, 3894 deletions
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn
index d3fa4cd08df..bc19dfd88f9 100644
--- a/chromium/ui/views/BUILD.gn
+++ b/chromium/ui/views/BUILD.gn
@@ -36,7 +36,6 @@ aggregate_vector_icons("views_vector_icons") {
"launch.icon",
"linux_high_density.icon",
"linux_low_density.icon",
- "linux_shutdown.icon",
"menu_check.icon",
"menu_drop_arrow.icon",
"menu_radio_empty.icon",
@@ -648,10 +647,6 @@ jumbo_component("views") {
}
if (use_x11) {
- configs += [
- "//build/config/linux:x11",
- "//build/config/linux:xrandr",
- ]
deps += [
"//ui/events/devices",
"//ui/events/devices/x11",
@@ -755,26 +750,21 @@ jumbo_component("views") {
"widget/desktop_aura/desktop_screen_position_client.cc",
"widget/desktop_aura/desktop_window_tree_host.cc",
]
- public_deps += [ "//ui/base/mojom:cursor_type" ]
+ public_deps += [ "//ui/base/cursor/mojom:cursor_type" ]
if (use_x11) {
- deps += [ "//ui/platform_window/x11" ]
+ public_deps += [
+ "//ui/base/x",
+ "//ui/platform_window/x11",
+ ]
public += [
"widget/desktop_aura/desktop_drag_drop_client_aurax11.h",
"widget/desktop_aura/desktop_screen_x11.h",
"widget/desktop_aura/desktop_window_tree_host_x11.h",
- "widget/desktop_aura/x11_desktop_window_move_client.h",
- "widget/desktop_aura/x11_move_loop.h",
- "widget/desktop_aura/x11_move_loop_delegate.h",
- "widget/desktop_aura/x11_topmost_window_finder.h",
- "widget/desktop_aura/x11_whole_screen_move_loop.h",
]
sources += [
"widget/desktop_aura/desktop_drag_drop_client_aurax11.cc",
"widget/desktop_aura/desktop_screen_x11.cc",
"widget/desktop_aura/desktop_window_tree_host_x11.cc",
- "widget/desktop_aura/x11_desktop_window_move_client.cc",
- "widget/desktop_aura/x11_topmost_window_finder.cc",
- "widget/desktop_aura/x11_whole_screen_move_loop.cc",
]
} else if (is_win) {
public += [ "widget/desktop_aura/desktop_window_tree_host_win.h" ]
@@ -788,6 +778,7 @@ jumbo_component("views") {
]
deps += [ "//ui/events:dom_keyboard_layout" ]
} else if (use_ozone) {
+ public += [ "widget/desktop_aura/desktop_screen_ozone.h" ]
sources += [
"widget/desktop_aura/desktop_drag_drop_client_ozone.cc",
"widget/desktop_aura/desktop_drag_drop_client_ozone.h",
@@ -808,9 +799,14 @@ jumbo_component("views") {
]
}
if (is_linux || is_fuchsia) {
- public += [ "widget/desktop_aura/desktop_window_tree_host_platform.h" ]
- sources +=
- [ "widget/desktop_aura/desktop_window_tree_host_platform.cc" ]
+ public += [
+ "widget/desktop_aura/desktop_window_tree_host_platform.h",
+ "widget/desktop_aura/window_move_client_platform.h",
+ ]
+ sources += [
+ "widget/desktop_aura/desktop_window_tree_host_platform.cc",
+ "widget/desktop_aura/window_move_client_platform.cc",
+ ]
deps += [ "//ui/platform_window/extensions" ]
}
if (use_atk) {
@@ -856,6 +852,10 @@ jumbo_component("views") {
if (is_fuchsia) {
sources += [ "controls/menu/menu_config_fuchsia.cc" ]
}
+
+ if (use_ozone) {
+ deps += [ "//ui/ozone" ]
+ }
}
jumbo_source_set("test_support") {
@@ -917,8 +917,6 @@ jumbo_source_set("test_support") {
"test/test_views_delegate.h",
"test/test_widget_observer.cc",
"test/test_widget_observer.h",
- "test/views_interactive_ui_test_base.cc",
- "test/views_interactive_ui_test_base.h",
"test/views_test_base.cc",
"test/views_test_base.h",
"test/views_test_helper.cc",
@@ -927,8 +925,6 @@ jumbo_source_set("test_support") {
"test/widget_test.h",
"test/widget_test_api.cc",
"test/widget_test_api.h",
- "test/x11_property_change_waiter.cc",
- "test/x11_property_change_waiter.h",
"view_test_api.h",
"views_test_suite.cc",
"views_test_suite.h",
@@ -1023,12 +1019,6 @@ jumbo_source_set("test_support") {
if (ozone_platform_x11) {
deps += [ "//ui/base/x" ]
}
- if (use_ozone || !use_x11) {
- sources -= [
- "test/x11_property_change_waiter.cc",
- "test/x11_property_change_waiter.h",
- ]
- }
}
test("views_unittests") {
@@ -1173,6 +1163,8 @@ test("views_unittests") {
"//third_party/wtl",
]
+ deps += [ "//ui/base:data_exchange" ]
+
libs = [
"imm32.lib",
"oleacc.lib",
@@ -1181,6 +1173,8 @@ test("views_unittests") {
]
sources += [
+ "accessibility/test_list_grid_view.cc",
+ "accessibility/test_list_grid_view.h",
"accessibility/view_ax_platform_node_delegate_win_unittest.cc",
"win/pen_event_processor_unittest.cc",
]
@@ -1240,7 +1234,7 @@ test("views_unittests") {
"//ui/accessibility:test_support",
"//ui/aura",
"//ui/aura:test_support",
- "//ui/base/mojom:cursor_type",
+ "//ui/base/cursor/mojom:cursor_type",
"//ui/touch_selection",
"//ui/wm",
"//ui/wm/public",
@@ -1257,10 +1251,6 @@ test("views_unittests") {
}
if (use_x11) {
- configs += [
- "//build/config/linux:x11",
- "//build/config/linux:xext",
- ]
deps += [
"//ui/events/devices",
"//ui/events/platform/x11",
@@ -1280,6 +1270,7 @@ test("views_unittests") {
"widget/desktop_aura/desktop_screen_x11_unittest.cc",
"widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc",
]
+ deps += [ "//ui/base/x:test_support" ]
}
if (is_linux || is_fuchsia) {
sources += [
@@ -1304,6 +1295,10 @@ test("views_unittests") {
[ "accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc" ]
configs += [ "//build/config/linux/atk" ]
}
+
+ if (use_ozone) {
+ deps += [ "//ui/ozone" ]
+ }
}
# This target is added as a dependency of browser interactive_ui_tests. It must
@@ -1372,7 +1367,11 @@ source_set("views_interactive_ui_tests") {
"widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc",
"widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc",
]
- deps += [ "//ui/events/platform/x11:x11" ]
+ deps += [
+ "//ui/base/x:test_support",
+ "//ui/events/platform/x11:x11",
+ "//ui/platform_window/x11",
+ ]
}
if (is_chromeos) {
diff --git a/chromium/ui/views/accessibility/accessibility_alert_window.cc b/chromium/ui/views/accessibility/accessibility_alert_window.cc
index 358b295e012..4c5b0e47f60 100644
--- a/chromium/ui/views/accessibility/accessibility_alert_window.cc
+++ b/chromium/ui/views/accessibility/accessibility_alert_window.cc
@@ -5,7 +5,7 @@
#include "ui/views/accessibility/accessibility_alert_window.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/accessibility/platform/aura_window_properties.h"
+#include "ui/accessibility/aura/aura_window_properties.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer_type.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
index 3197d2eec5c..b8f102137de 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -105,15 +105,19 @@ void AXAuraObjCache::GetTopLevelWindows(
AXAuraObjWrapper* AXAuraObjCache::GetFocus() {
View* focused_view = GetFocusedView();
- if (focused_view) {
- const ViewAccessibility& view_accessibility =
- focused_view->GetViewAccessibility();
- if (view_accessibility.FocusedVirtualChild())
- return view_accessibility.FocusedVirtualChild()->GetOrCreateWrapper(this);
+ while (focused_view && focused_view->GetViewAccessibility().IsIgnored())
+ focused_view = focused_view->parent();
- return GetOrCreate(focused_view);
+ if (!focused_view)
+ return nullptr;
+
+ if (focused_view->GetViewAccessibility().FocusedVirtualChild()) {
+ return focused_view->GetViewAccessibility()
+ .FocusedVirtualChild()
+ ->GetOrCreateWrapper(this);
}
- return nullptr;
+
+ return GetOrCreate(focused_view);
}
void AXAuraObjCache::OnFocusedViewChanged() {
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
index 4008179a8bc..dcdd7515034 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
@@ -17,7 +17,9 @@
#include "ui/aura/window.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/accessibility/ax_tree_source_views.h"
+#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/test/widget_test.h"
@@ -51,6 +53,12 @@ class AXAuraObjCacheTest : public WidgetTest {
public:
AXAuraObjCacheTest() = default;
~AXAuraObjCacheTest() override = default;
+
+ ui::AXNodeData GetData(AXAuraObjWrapper* wrapper) {
+ ui::AXNodeData data;
+ wrapper->Serialize(&data);
+ return data;
+ }
};
TEST_F(AXAuraObjCacheTest, TestViewRemoval) {
@@ -133,6 +141,68 @@ TEST_F(AXAuraObjCacheTest, ValidTree) {
EXPECT_TRUE(HasNodeWithName(ax_tree, "ChildButton"));
}
+TEST_F(AXAuraObjCacheTest, GetFocusIsUnignoredAncestor) {
+ AXAuraObjCache cache;
+ auto widget = std::make_unique<Widget>();
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.activatable = views::Widget::InitParams::ACTIVATABLE_YES;
+ widget->Init(std::move(params));
+ widget->Show();
+
+ // Note that AXAuraObjCache::GetFocusedView has some logic to force focus on
+ // the first child of the client view when one cannot be found from the
+ // FocusManager.
+ auto* client = widget->non_client_view()->client_view();
+ ASSERT_NE(nullptr, client);
+ auto* client_child = client->children().front();
+ ASSERT_NE(nullptr, client_child);
+ client_child->GetViewAccessibility().OverrideRole(ax::mojom::Role::kDialog);
+
+ View* parent = new View();
+ widget->GetRootView()->AddChildView(parent);
+ parent->GetViewAccessibility().OverrideRole(ax::mojom::Role::kTextField);
+ parent->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+
+ View* child = new View();
+ parent->AddChildView(child);
+ child->GetViewAccessibility().OverrideRole(ax::mojom::Role::kGroup);
+ child->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+
+ auto* ax_widget = cache.GetOrCreate(widget.get());
+ ASSERT_NE(nullptr, ax_widget);
+ auto* ax_client_child = cache.GetOrCreate(client_child);
+ ASSERT_NE(nullptr, ax_client_child);
+ auto* ax_parent = cache.GetOrCreate(parent);
+ ASSERT_NE(nullptr, ax_parent);
+ auto* ax_child = cache.GetOrCreate(child);
+ ASSERT_NE(nullptr, ax_child);
+
+ ASSERT_EQ(nullptr, cache.GetFocus());
+ cache.OnRootWindowObjCreated(widget->GetNativeWindow());
+ ASSERT_EQ(ax::mojom::Role::kDialog, GetData(cache.GetFocus()).role);
+ ASSERT_EQ(ax_client_child, cache.GetFocus());
+
+ parent->RequestFocus();
+ ASSERT_EQ(ax::mojom::Role::kTextField, GetData(cache.GetFocus()).role);
+ ASSERT_EQ(ax_parent, cache.GetFocus());
+
+ child->RequestFocus();
+ ASSERT_EQ(ax::mojom::Role::kGroup, GetData(cache.GetFocus()).role);
+ ASSERT_EQ(ax_child, cache.GetFocus());
+
+ child->GetViewAccessibility().OverrideIsIgnored(true);
+ ASSERT_EQ(ax::mojom::Role::kTextField, GetData(cache.GetFocus()).role);
+ ASSERT_EQ(ax_parent, cache.GetFocus());
+
+ parent->GetViewAccessibility().OverrideIsIgnored(true);
+ ASSERT_EQ(ax::mojom::Role::kWindow, GetData(cache.GetFocus()).role);
+ ASSERT_EQ(cache.GetOrCreate(widget->GetRootView()), cache.GetFocus());
+
+ cache.OnRootWindowObjDestroyed(widget->GetNativeWindow());
+}
+
} // namespace
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h b/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
index 39ef97a6c04..6410416ce2b 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
@@ -37,6 +37,7 @@ class VIEWS_EXPORT AXAuraObjWrapper {
virtual void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) = 0;
virtual void Serialize(ui::AXNodeData* out_node_data) = 0;
virtual int32_t GetUniqueId() const = 0;
+ virtual std::string ToString() const = 0;
// Actions.
virtual bool HandleAccessibleAction(const ui::AXActionData& action);
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
index d741387d039..f79b6c0ec10 100644
--- a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
@@ -75,6 +75,10 @@ int32_t AXRootObjWrapper::GetUniqueId() const {
return unique_id_.Get();
}
+std::string AXRootObjWrapper::ToString() const {
+ return "root";
+}
+
void AXRootObjWrapper::OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) {
delegate_->OnEvent(this, ax::mojom::Event::kLoadComplete);
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
index d259c7071d5..168138b9314 100644
--- a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
@@ -35,6 +35,7 @@ class VIEWS_EXPORT AXRootObjWrapper : public views::AXAuraObjWrapper,
std::vector<views::AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
int32_t GetUniqueId() const override;
+ std::string ToString() const override;
private:
// display::DisplayObserver:
diff --git a/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc b/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
index f4315d4fb58..60729545314 100644
--- a/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
+++ b/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
@@ -196,7 +196,7 @@ WinAccessibilityCaretEventMonitor::WinEventHookThunk(HWINEVENTHOOK handle,
}
} // namespace
-TEST_F(AXSystemCaretWinTest, DISABLED_TestOnCaretBoundsChangeInTextField) {
+TEST_F(AXSystemCaretWinTest, TestOnCaretBoundsChangeInTextField) {
TextfieldTestApi textfield_test_api(textfield_);
Microsoft::WRL::ComPtr<IAccessible> caret_accessible;
gfx::NativeWindow native_window = widget_->GetNativeWindow();
@@ -205,9 +205,12 @@ TEST_F(AXSystemCaretWinTest, DISABLED_TestOnCaretBoundsChangeInTextField) {
EXPECT_HRESULT_SUCCEEDED(AccessibleObjectFromWindow(
hwnd, static_cast<DWORD>(OBJID_CARET), IID_PPV_ARGS(&caret_accessible)));
+ gfx::Rect window_bounds = native_window->GetBoundsInScreen();
+
textfield_test_api.ExecuteTextEditCommand(
ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT);
- gfx::Point caret_position = textfield_test_api.GetCursorViewRect().origin();
+ gfx::Point caret_position = textfield_test_api.GetCursorViewRect().origin() +
+ window_bounds.OffsetFromOrigin();
LONG x, y, width, height;
EXPECT_EQ(S_OK,
caret_accessible->accLocation(&x, &y, &width, &height, self_));
@@ -217,7 +220,8 @@ TEST_F(AXSystemCaretWinTest, DISABLED_TestOnCaretBoundsChangeInTextField) {
textfield_test_api.ExecuteTextEditCommand(
ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT);
- gfx::Point caret_position2 = textfield_test_api.GetCursorViewRect().origin();
+ gfx::Point caret_position2 = textfield_test_api.GetCursorViewRect().origin() +
+ window_bounds.OffsetFromOrigin();
EXPECT_NE(caret_position, caret_position2);
EXPECT_EQ(S_OK,
caret_accessible->accLocation(&x, &y, &width, &height, self_));
@@ -226,7 +230,7 @@ TEST_F(AXSystemCaretWinTest, DISABLED_TestOnCaretBoundsChangeInTextField) {
EXPECT_EQ(1, width);
}
-TEST_F(AXSystemCaretWinTest, DISABLED_TestOnInputTypeChangeInTextField) {
+TEST_F(AXSystemCaretWinTest, TestOnInputTypeChangeInTextField) {
Microsoft::WRL::ComPtr<IAccessible> caret_accessible;
gfx::NativeWindow native_window = widget_->GetNativeWindow();
ASSERT_NE(nullptr, native_window);
@@ -255,7 +259,7 @@ TEST_F(AXSystemCaretWinTest, DISABLED_TestOnInputTypeChangeInTextField) {
EXPECT_EQ(height, height2);
}
-TEST_F(AXSystemCaretWinTest, DISABLED_TestMovingWindow) {
+TEST_F(AXSystemCaretWinTest, TestMovingWindow) {
Microsoft::WRL::ComPtr<IAccessible> caret_accessible;
gfx::NativeWindow native_window = widget_->GetNativeWindow();
ASSERT_NE(nullptr, native_window);
@@ -268,9 +272,6 @@ TEST_F(AXSystemCaretWinTest, DISABLED_TestMovingWindow) {
widget_->SetBounds(gfx::Rect(100, 100, 500, 500));
LONG x2, y2, width2, height2;
- caret_accessible.Reset();
- EXPECT_HRESULT_SUCCEEDED(AccessibleObjectFromWindow(
- hwnd, static_cast<DWORD>(OBJID_CARET), IID_PPV_ARGS(&caret_accessible)));
EXPECT_EQ(S_OK,
caret_accessible->accLocation(&x2, &y2, &width2, &height2, self_));
EXPECT_NE(x, x2);
@@ -281,13 +282,14 @@ TEST_F(AXSystemCaretWinTest, DISABLED_TestMovingWindow) {
// Try maximizing the window.
SendMessage(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
- LONG x3, y3, width3, height3;
- EXPECT_HRESULT_FAILED(
- caret_accessible->accLocation(&x3, &y3, &width3, &height3, self_));
- caret_accessible.Reset();
+ // On Win7, maximizing the window causes our caret object to get destroyed and
+ // re-created, so re-acquire it.
+ caret_accessible.Reset();
EXPECT_HRESULT_SUCCEEDED(AccessibleObjectFromWindow(
hwnd, static_cast<DWORD>(OBJID_CARET), IID_PPV_ARGS(&caret_accessible)));
+
+ LONG x3, y3, width3, height3;
EXPECT_EQ(S_OK,
caret_accessible->accLocation(&x3, &y3, &width3, &height3, self_));
EXPECT_NE(x2, x3);
@@ -297,7 +299,7 @@ TEST_F(AXSystemCaretWinTest, DISABLED_TestMovingWindow) {
EXPECT_EQ(height, height3);
}
-TEST_F(AXSystemCaretWinTest, DISABLED_TestCaretMSAAEvents) {
+TEST_F(AXSystemCaretWinTest, TestCaretMSAAEvents) {
TextfieldTestApi textfield_test_api(textfield_);
Microsoft::WRL::ComPtr<IAccessible> caret_accessible;
gfx::NativeWindow native_window = widget_->GetNativeWindow();
diff --git a/chromium/ui/views/accessibility/ax_tree_source_views.cc b/chromium/ui/views/accessibility/ax_tree_source_views.cc
index fbbca160b51..8733f5e1ebe 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views.cc
+++ b/chromium/ui/views/accessibility/ax_tree_source_views.cc
@@ -117,6 +117,10 @@ AXAuraObjWrapper* AXTreeSourceViews::GetNull() const {
return nullptr;
}
+std::string AXTreeSourceViews::GetDebugString(AXAuraObjWrapper* node) const {
+ return node->ToString();
+}
+
void AXTreeSourceViews::SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const {
node->Serialize(out_data);
diff --git a/chromium/ui/views/accessibility/ax_tree_source_views.h b/chromium/ui/views/accessibility/ax_tree_source_views.h
index 2640ea24442..37317b530b5 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views.h
+++ b/chromium/ui/views/accessibility/ax_tree_source_views.h
@@ -54,6 +54,7 @@ class VIEWS_EXPORT AXTreeSourceViews
bool IsValid(AXAuraObjWrapper* node) const override;
bool IsEqual(AXAuraObjWrapper* node1, AXAuraObjWrapper* node2) const override;
AXAuraObjWrapper* GetNull() const override;
+ std::string GetDebugString(AXAuraObjWrapper* node) const override;
void SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const override;
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
index 64b0303bef6..53845347297 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -92,6 +92,10 @@ bool AXViewObjWrapper::HandleAccessibleAction(const ui::AXActionData& action) {
return view_ ? view_->HandleAccessibleAction(action) : false;
}
+std::string AXViewObjWrapper::ToString() const {
+ return std::string(view_ ? view_->GetClassName() : "Null view");
+}
+
void AXViewObjWrapper::OnViewIsDeleting(View* observed_view) {
observer_.RemoveAll();
view_ = nullptr;
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
index 02717a0ebc1..758381fbf49 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
@@ -35,6 +35,7 @@ class AXViewObjWrapper : public AXAuraObjWrapper, public ViewObserver {
void Serialize(ui::AXNodeData* out_node_data) override;
int32_t GetUniqueId() const final;
bool HandleAccessibleAction(const ui::AXActionData& action) override;
+ std::string ToString() const override;
// ViewObserver overrides.
void OnViewIsDeleting(View* observed_view) override;
diff --git a/chromium/ui/views/accessibility/ax_virtual_view.cc b/chromium/ui/views/accessibility/ax_virtual_view.cc
index cf273bc4d05..a222443d37e 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view.cc
+++ b/chromium/ui/views/accessibility/ax_virtual_view.cc
@@ -11,11 +11,13 @@
#include <utility>
#include "base/callback.h"
+#include "base/containers/adapters.h"
#include "base/no_destructor.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_platform_node.h"
+#include "ui/base/layout.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/views/accessibility/view_accessibility.h"
@@ -236,6 +238,15 @@ const ui::AXNodeData& AXVirtualView::GetData() const {
if (populate_data_callback_ && GetOwnerView())
populate_data_callback_.Run(&node_data);
+
+ // According to the ARIA spec, the node should not be ignored if it is
+ // focusable. This is to ensure that the focusable node is both understandable
+ // and operable.
+ if (node_data.HasState(ax::mojom::State::kIgnored) &&
+ node_data.HasState(ax::mojom::State::kFocusable)) {
+ node_data.RemoveState(ax::mojom::State::kIgnored);
+ }
+
return node_data;
}
@@ -302,12 +313,24 @@ gfx::Rect AXVirtualView::GetBoundsRect(
const ui::AXCoordinateSystem coordinate_system,
const ui::AXClippingBehavior clipping_behavior,
ui::AXOffscreenResult* offscreen_result) const {
+ // We could optionally add clipping here if ever needed.
+ // TODO(nektar): Implement bounds that are relative to the parent.
+ gfx::Rect bounds = gfx::ToEnclosingRect(GetData().relative_bounds.bounds);
+ View* owner_view = GetOwnerView();
+ if (owner_view && owner_view->GetWidget())
+ View::ConvertRectToScreen(owner_view, &bounds);
switch (coordinate_system) {
case ui::AXCoordinateSystem::kScreenDIPs:
- // We could optionally add clipping here if ever needed.
- // TODO(nektar): Implement bounds that are relative to the parent.
- return gfx::ToEnclosingRect(custom_data_.relative_bounds.bounds);
- case ui::AXCoordinateSystem::kScreenPhysicalPixels:
+ return bounds;
+ case ui::AXCoordinateSystem::kScreenPhysicalPixels: {
+ float scale_factor = 1.0;
+ if (owner_view && owner_view->GetWidget()) {
+ gfx::NativeView native_view = owner_view->GetWidget()->GetNativeView();
+ if (native_view)
+ scale_factor = ui::GetScaleFactorForNativeView(native_view);
+ }
+ return gfx::ScaleToEnclosingRect(bounds, scale_factor);
+ }
case ui::AXCoordinateSystem::kRootFrame:
case ui::AXCoordinateSystem::kFrame:
NOTIMPLEMENTED();
@@ -318,27 +341,39 @@ gfx::Rect AXVirtualView::GetBoundsRect(
gfx::NativeViewAccessible AXVirtualView::HitTestSync(
int screen_physical_pixel_x,
int screen_physical_pixel_y) const {
- if (custom_data_.relative_bounds.bounds.Contains(
- static_cast<float>(screen_physical_pixel_x),
- static_cast<float>(screen_physical_pixel_y))) {
- if (!IsIgnored())
- return GetNativeObject();
- }
+ const ui::AXNodeData& node_data = GetData();
+ if (node_data.HasState(ax::mojom::State::kInvisible))
+ return nullptr;
// Check if the point is within any of the virtual children of this view.
// AXVirtualView's HitTestSync is a recursive function that will return the
// deepest child, since it does not support relative bounds.
- for (const std::unique_ptr<AXVirtualView>& child : children_) {
+ // Search the greater indices first, since they're on top in the z-order.
+ for (const std::unique_ptr<AXVirtualView>& child :
+ base::Reversed(children_)) {
gfx::NativeViewAccessible result =
child->HitTestSync(screen_physical_pixel_x, screen_physical_pixel_y);
if (result)
return result;
}
+
+ // If it's not inside any of our virtual children, and it's inside the bounds
+ // of this virtual view, then it's inside this virtual view.
+ gfx::Rect bounds_in_screen_physical_pixels =
+ GetBoundsRect(ui::AXCoordinateSystem::kScreenPhysicalPixels,
+ ui::AXClippingBehavior::kUnclipped);
+ if (bounds_in_screen_physical_pixels.Contains(
+ static_cast<float>(screen_physical_pixel_x),
+ static_cast<float>(screen_physical_pixel_y)) &&
+ !node_data.IsIgnored()) {
+ return GetNativeObject();
+ }
+
return nullptr;
}
gfx::NativeViewAccessible AXVirtualView::GetFocus() {
- auto* owner_view = GetOwnerView();
+ View* owner_view = GetOwnerView();
if (owner_view) {
if (!(owner_view->HasFocus())) {
return nullptr;
@@ -389,15 +424,7 @@ gfx::AcceleratedWidget AXVirtualView::GetTargetForNativeAccessibilityEvent() {
}
bool AXVirtualView::IsIgnored() const {
- const ui::AXNodeData& node_data = GetData();
-
- // According to the ARIA spec, the node should not be ignored if it is
- // focusable. This is to ensure that the focusable node is both understandable
- // and operable.
- if (node_data.HasState(ax::mojom::State::kFocusable))
- return false;
-
- return node_data.IsIgnored();
+ return GetData().IsIgnored();
}
bool AXVirtualView::HandleAccessibleAction(
diff --git a/chromium/ui/views/accessibility/ax_virtual_view.h b/chromium/ui/views/accessibility/ax_virtual_view.h
index c74273c6ac8..105c961b102 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view.h
+++ b/chromium/ui/views/accessibility/ax_virtual_view.h
@@ -142,7 +142,7 @@ class VIEWS_EXPORT AXVirtualView : public ui::AXPlatformNodeDelegateBase {
gfx::Rect GetBoundsRect(
const ui::AXCoordinateSystem coordinate_system,
const ui::AXClippingBehavior clipping_behavior,
- ui::AXOffscreenResult* offscreen_result) const override;
+ ui::AXOffscreenResult* offscreen_result = nullptr) const override;
gfx::NativeViewAccessible HitTestSync(
int screen_physical_pixel_x,
int screen_physical_pixel_y) const override;
diff --git a/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc b/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc
index 3f1cb20f077..b48ada53153 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc
+++ b/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc
@@ -626,6 +626,51 @@ TEST_F(AXVirtualViewTest, Navigation) {
EXPECT_EQ(0, virtual_child_4->GetIndexInParent());
}
+TEST_F(AXVirtualViewTest, HitTesting) {
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+
+ const gfx::Vector2d offset_from_origin =
+ button_->GetBoundsInScreen().OffsetFromOrigin();
+
+ // Test that hit testing is recursive.
+ AXVirtualView* virtual_child_1 = new AXVirtualView;
+ virtual_child_1->GetCustomData().relative_bounds.bounds =
+ gfx::RectF(0, 0, 10, 10);
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
+ AXVirtualView* virtual_child_2 = new AXVirtualView;
+ virtual_child_2->GetCustomData().relative_bounds.bounds =
+ gfx::RectF(5, 5, 5, 5);
+ virtual_child_1->AddChildView(base::WrapUnique(virtual_child_2));
+ gfx::Point point_1 = gfx::Point(2, 2) + offset_from_origin;
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ virtual_child_1->HitTestSync(point_1.x(), point_1.y()));
+ gfx::Point point_2 = gfx::Point(7, 7) + offset_from_origin;
+ EXPECT_EQ(virtual_child_2->GetNativeObject(),
+ virtual_label_->HitTestSync(point_2.x(), point_2.y()));
+
+ // Test that hit testing follows the z-order.
+ AXVirtualView* virtual_child_3 = new AXVirtualView;
+ virtual_child_3->GetCustomData().relative_bounds.bounds =
+ gfx::RectF(5, 5, 10, 10);
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_3));
+ AXVirtualView* virtual_child_4 = new AXVirtualView;
+ virtual_child_4->GetCustomData().relative_bounds.bounds =
+ gfx::RectF(10, 10, 10, 10);
+ virtual_child_3->AddChildView(base::WrapUnique(virtual_child_4));
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ virtual_label_->HitTestSync(point_2.x(), point_2.y()));
+ gfx::Point point_3 = gfx::Point(12, 12) + offset_from_origin;
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_label_->HitTestSync(point_3.x(), point_3.y()));
+
+ // Test that hit testing skips ignored nodes but not their descendants.
+ virtual_child_3->GetCustomData().AddState(ax::mojom::State::kIgnored);
+ EXPECT_EQ(virtual_child_2->GetNativeObject(),
+ virtual_label_->HitTestSync(point_2.x(), point_2.y()));
+ EXPECT_EQ(virtual_child_4->GetNativeObject(),
+ virtual_label_->HitTestSync(point_3.x(), point_3.y()));
+}
+
// Test for GetTargetForNativeAccessibilityEvent().
#if defined(OS_WIN)
TEST_F(AXVirtualViewTest, GetTargetForEvents) {
diff --git a/chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc b/chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc
index 65a7b57edac..dffc373da1a 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_virtual_view_wrapper.cc
@@ -51,4 +51,9 @@ bool AXVirtualViewWrapper::HandleAccessibleAction(
return virtual_view_->HandleAccessibleAction(action);
}
+std::string AXVirtualViewWrapper::ToString() const {
+ std::string description = "Virtual view child of ";
+ return description + virtual_view_->GetOwnerView()->GetClassName();
+}
+
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_virtual_view_wrapper.h b/chromium/ui/views/accessibility/ax_virtual_view_wrapper.h
index f6121f041b3..7588a5ffbba 100644
--- a/chromium/ui/views/accessibility/ax_virtual_view_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_virtual_view_wrapper.h
@@ -31,6 +31,7 @@ class AXVirtualViewWrapper : public AXAuraObjWrapper {
void Serialize(ui::AXNodeData* out_node_data) override;
int32_t GetUniqueId() const override;
bool HandleAccessibleAction(const ui::AXActionData& action) override;
+ std::string ToString() const override;
private:
// Weak.
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
index e9a4012c6e8..9aeeb45a0bc 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -62,6 +62,10 @@ int32_t AXWidgetObjWrapper::GetUniqueId() const {
return unique_id_.Get();
}
+std::string AXWidgetObjWrapper::ToString() const {
+ return "Widget";
+}
+
void AXWidgetObjWrapper::OnWidgetDestroying(Widget* widget) {
aura_obj_cache_->Remove(widget);
}
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
index e5671607a61..2f6cc93f1ef 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
@@ -36,6 +36,7 @@ class AXWidgetObjWrapper : public AXAuraObjWrapper,
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
int32_t GetUniqueId() const final;
+ std::string ToString() const override;
// WidgetObserver overrides.
void OnWidgetDestroying(Widget* widget) override;
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
index 8a6a8c6a83d..5e79b94b22c 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -10,10 +10,10 @@
#include <vector>
#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/aura/aura_window_properties.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_id.h"
-#include "ui/accessibility/platform/aura_window_properties.h"
#include "ui/aura/client/focus_client.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/widget/widget.h"
@@ -66,6 +66,13 @@ void FireLocationChangesRecursively(aura::Window* window,
FireLocationChangesRecursively(child, cache);
}
+std::string GetWindowName(aura::Window* window) {
+ std::string class_name = window->GetName();
+ if (class_name.empty())
+ class_name = "aura::Window";
+ return class_name;
+}
+
} // namespace
AXWindowObjWrapper::AXWindowObjWrapper(AXAuraObjCache* aura_obj_cache,
@@ -136,17 +143,18 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
*child_ax_tree_id_ptr);
}
- std::string class_name = window_->GetName();
- if (class_name.empty())
- class_name = "aura::Window";
out_node_data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
- class_name);
+ GetWindowName(window_));
}
int32_t AXWindowObjWrapper::GetUniqueId() const {
return unique_id_.Get();
}
+std::string AXWindowObjWrapper::ToString() const {
+ return GetWindowName(window_);
+}
+
void AXWindowObjWrapper::OnWindowDestroyed(aura::Window* window) {
aura_obj_cache_->Remove(window, nullptr);
}
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
index 1877e2ebc86..841a3d03710 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -35,6 +35,7 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
int32_t GetUniqueId() const final;
+ std::string ToString() const override;
// WindowObserver overrides.
void OnWindowDestroyed(aura::Window* window) override;
diff --git a/chromium/ui/views/accessibility/test_list_grid_view.cc b/chromium/ui/views/accessibility/test_list_grid_view.cc
new file mode 100644
index 00000000000..031a1194dbf
--- /dev/null
+++ b/chromium/ui/views/accessibility/test_list_grid_view.cc
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/accessibility/test_list_grid_view.h"
+
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
+
+namespace views {
+namespace test {
+
+TestListGridView::TestListGridView() = default;
+TestListGridView::~TestListGridView() = default;
+
+void TestListGridView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ node_data->role = ax::mojom::Role::kListGrid;
+ if (aria_row_count) {
+ node_data->AddIntAttribute(ax::mojom::IntAttribute::kAriaRowCount,
+ *aria_row_count);
+ }
+ if (aria_column_count) {
+ node_data->AddIntAttribute(ax::mojom::IntAttribute::kAriaColumnCount,
+ *aria_column_count);
+ }
+ if (table_row_count) {
+ node_data->AddIntAttribute(ax::mojom::IntAttribute::kTableRowCount,
+ *table_row_count);
+ }
+ if (table_column_count) {
+ node_data->AddIntAttribute(ax::mojom::IntAttribute::kTableColumnCount,
+ *table_column_count);
+ }
+}
+
+void TestListGridView::SetAriaTableSize(int row_count, int column_count) {
+ aria_row_count = base::make_optional(row_count);
+ aria_column_count = base::make_optional(column_count);
+}
+
+void TestListGridView::SetTableSize(int row_count, int column_count) {
+ table_row_count = base::make_optional(row_count);
+ table_column_count = base::make_optional(column_count);
+}
+
+void TestListGridView::UnsetAriaTableSize() {
+ aria_row_count = base::nullopt;
+ aria_column_count = base::nullopt;
+}
+
+void TestListGridView::UnsetTableSize() {
+ table_row_count = base::nullopt;
+ table_column_count = base::nullopt;
+}
+
+} // namespace test
+} // namespace views
diff --git a/chromium/ui/views/accessibility/test_list_grid_view.h b/chromium/ui/views/accessibility/test_list_grid_view.h
new file mode 100644
index 00000000000..8c742ba1010
--- /dev/null
+++ b/chromium/ui/views/accessibility/test_list_grid_view.h
@@ -0,0 +1,40 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_TEST_LIST_GRID_VIEW_H_
+#define UI_VIEWS_ACCESSIBILITY_TEST_LIST_GRID_VIEW_H_
+
+#include "ui/views/view.h"
+
+namespace ui {
+struct AXNodeData;
+} // namespace ui
+
+namespace views {
+namespace test {
+
+// Class used for testing row and column count accessibility APIs.
+class TestListGridView : public View {
+ public:
+ TestListGridView();
+ ~TestListGridView() override;
+
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+
+ void SetAriaTableSize(int row_count, int column_count);
+ void SetTableSize(int row_count, int column_count);
+ void UnsetAriaTableSize();
+ void UnsetTableSize();
+
+ private:
+ base::Optional<int> aria_row_count = base::nullopt;
+ base::Optional<int> aria_column_count = base::nullopt;
+ base::Optional<int> table_row_count = base::nullopt;
+ base::Optional<int> table_column_count = base::nullopt;
+};
+
+} // namespace test
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_TEST_LIST_GRID_VIEW_H_
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
index 8061724c841..797c0eb5482 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
@@ -12,6 +12,9 @@
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.h"
#include "third_party/iaccessible2/ia2_api_all.h"
+#include "ui/accessibility/ax_constants.mojom.h"
+#include "ui/accessibility/platform/ax_platform_node_win.h"
+#include "ui/views/accessibility/test_list_grid_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/textfield/textfield.h"
@@ -407,5 +410,82 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, Overrides) {
alert_accessible->get_accChild(child_index, &child_dispatch));
ASSERT_EQ(child_dispatch.Get(), nullptr);
}
+
+TEST_F(ViewAXPlatformNodeDelegateWinTest, GridRowColumnCount) {
+ Widget widget;
+ Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget.Init(std::move(init_params));
+
+ View* content = new View;
+ widget.SetContentsView(content);
+ TestListGridView* grid = new TestListGridView();
+ content->AddChildView(grid);
+
+ Microsoft::WRL::ComPtr<IGridProvider> grid_provider;
+ EXPECT_HRESULT_SUCCEEDED(
+ grid->GetViewAccessibility().GetNativeObject()->QueryInterface(
+ __uuidof(IGridProvider), &grid_provider));
+
+ // If set, aria row/column count takes precedence over table row/column count.
+ // Expect E_UNEXPECTED if the result is kUnknownAriaColumnOrRowCount (-1) or
+ // if neither is set.
+ int row_count;
+ int column_count;
+
+ // aria row/column count = not set
+ // table row/column count = not set
+ grid->UnsetAriaTableSize();
+ grid->UnsetTableSize();
+ EXPECT_HRESULT_SUCCEEDED(grid_provider->get_RowCount(&row_count));
+ EXPECT_HRESULT_SUCCEEDED(grid_provider->get_ColumnCount(&column_count));
+ EXPECT_EQ(0, row_count);
+ EXPECT_EQ(0, column_count);
+ // To do still: When nothing is set, currently
+ // AXPlatformNodeDelegateBase::GetTable{Row/Col}Count() returns 0 Should it
+ // return base::nullopt if the attribute is not set? Like
+ // GetTableAria{Row/Col}Count()
+ // EXPECT_EQ(E_UNEXPECTED, grid_provider->get_RowCount(&row_count));
+
+ // aria row/column count = 2
+ // table row/column count = not set
+ grid->SetAriaTableSize(2, 2);
+ EXPECT_HRESULT_SUCCEEDED(grid_provider->get_RowCount(&row_count));
+ EXPECT_HRESULT_SUCCEEDED(grid_provider->get_ColumnCount(&column_count));
+ EXPECT_EQ(2, row_count);
+ EXPECT_EQ(2, column_count);
+
+ // aria row/column count = kUnknownAriaColumnOrRowCount
+ // table row/column count = not set
+ grid->SetAriaTableSize(ax::mojom::kUnknownAriaColumnOrRowCount,
+ ax::mojom::kUnknownAriaColumnOrRowCount);
+ EXPECT_EQ(E_UNEXPECTED, grid_provider->get_RowCount(&row_count));
+ EXPECT_EQ(E_UNEXPECTED, grid_provider->get_ColumnCount(&column_count));
+
+ // aria row/column count = 3
+ // table row/column count = 4
+ grid->SetAriaTableSize(3, 3);
+ grid->SetTableSize(4, 4);
+ EXPECT_HRESULT_SUCCEEDED(grid_provider->get_RowCount(&row_count));
+ EXPECT_HRESULT_SUCCEEDED(grid_provider->get_ColumnCount(&column_count));
+ EXPECT_EQ(3, row_count);
+ EXPECT_EQ(3, column_count);
+
+ // aria row/column count = not set
+ // table row/column count = 4
+ grid->UnsetAriaTableSize();
+ grid->SetTableSize(4, 4);
+ EXPECT_HRESULT_SUCCEEDED(grid_provider->get_RowCount(&row_count));
+ EXPECT_HRESULT_SUCCEEDED(grid_provider->get_ColumnCount(&column_count));
+ EXPECT_EQ(4, row_count);
+ EXPECT_EQ(4, column_count);
+
+ // aria row/column count = not set
+ // table row/column count = kUnknownAriaColumnOrRowCount
+ grid->SetTableSize(ax::mojom::kUnknownAriaColumnOrRowCount,
+ ax::mojom::kUnknownAriaColumnOrRowCount);
+ EXPECT_EQ(E_UNEXPECTED, grid_provider->get_RowCount(&row_count));
+ EXPECT_EQ(E_UNEXPECTED, grid_provider->get_ColumnCount(&column_count));
+}
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/accessibility/views_ax_tree_manager.cc b/chromium/ui/views/accessibility/views_ax_tree_manager.cc
index 15954cf453f..2b30e23ceef 100644
--- a/chromium/ui/views/accessibility/views_ax_tree_manager.cc
+++ b/chromium/ui/views/accessibility/views_ax_tree_manager.cc
@@ -8,8 +8,9 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/check.h"
#include "base/location.h"
-#include "base/logging.h"
+#include "base/notreached.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chromium/ui/views/animation/bounds_animator.cc b/chromium/ui/views/animation/bounds_animator.cc
index 64fda4d79b2..cf2598680d4 100644
--- a/chromium/ui/views/animation/bounds_animator.cc
+++ b/chromium/ui/views/animation/bounds_animator.cc
@@ -44,9 +44,21 @@ void BoundsAnimator::AnimateViewTo(
Data existing_data;
if (IsAnimating(view)) {
- // Don't immediately delete the animation, that might trigger a callback
- // from the animation container.
- existing_data = RemoveFromMaps(view);
+ DCHECK(base::Contains(data_, view));
+ const bool used_transforms = data_[view].target_transform.has_value();
+ if (used_transforms) {
+ // Using transforms means a view does not have the proper bounds until an
+ // animation is complete or canceled. So here we cancel the animation so
+ // that the bounds can be updated. Note that this means that callers who
+ // want to set bounds (i.e. View::SetBoundsRect()) directly before calling
+ // this function will have to explicitly call StopAnimatingView() before
+ // doing so.
+ StopAnimatingView(view);
+ } else {
+ // Don't immediately delete the animation, that might trigger a callback
+ // from the animation container.
+ existing_data = RemoveFromMaps(view);
+ }
}
// NOTE: we don't check if the view is already at the target location. Doing
@@ -60,12 +72,20 @@ void BoundsAnimator::AnimateViewTo(
data.animation = CreateAnimation();
data.delegate = std::move(delegate);
- if (use_transforms_ && !data.start_bounds.IsEmpty()) {
+ // If the start bounds are empty we cannot derive a transform from start to
+ // target. Views with existing transforms are not supported. Default back to
+ // using the bounds update animation in these cases.
+ if (use_transforms_ && !data.start_bounds.IsEmpty() &&
+ view->GetTransform().IsIdentity()) {
// Calculate the target transform. Note that we don't reset the transform if
// there already was one, otherwise users will end up with visual bounds
// different than what they set.
+ // Note that View::SetTransform() does not handle RTL, which is different
+ // from View::SetBounds(). So mirror the start bounds and target bounds
+ // manually if necessary.
const gfx::Transform target_transform = gfx::TransformBetweenRects(
- gfx::RectF(data.start_bounds), gfx::RectF(data.target_bounds));
+ gfx::RectF(parent_->GetMirroredRect(data.start_bounds)),
+ gfx::RectF(parent_->GetMirroredRect(data.target_bounds)));
data.target_transform = target_transform;
}
@@ -89,28 +109,6 @@ gfx::Rect BoundsAnimator::GetTargetBounds(const View* view) const {
return (i == data_.end()) ? view->bounds() : i->second.target_bounds;
}
-void BoundsAnimator::SetAnimationForView(
- View* view,
- std::unique_ptr<gfx::SlideAnimation> animation) {
- DCHECK(animation);
-
- const auto i = data_.find(view);
- if (i == data_.end())
- return;
-
- // We delay deleting the animation until the end so that we don't prematurely
- // send out notification that we're done.
- std::unique_ptr<gfx::Animation> old_animation = ResetAnimationForView(view);
-
- gfx::SlideAnimation* animation_ptr = animation.get();
- i->second.animation = std::move(animation);
- animation_to_view_[animation_ptr] = view;
-
- animation_ptr->set_delegate(this);
- animation_ptr->SetContainer(container_.get());
- animation_ptr->Show();
-}
-
const gfx::SlideAnimation* BoundsAnimator::GetAnimationForView(View* view) {
const auto i = data_.find(view);
return (i == data_.end()) ? nullptr : i->second.animation.get();
@@ -224,10 +222,20 @@ void BoundsAnimator::AnimationEndedOrCanceled(const gfx::Animation* animation,
Data data = RemoveFromMaps(view);
if (data.target_transform) {
- // Set the bounds at the end of the animation and reset the transform.
- view->SetTransform(gfx::Transform());
- if (type == AnimationEndType::kEnded)
+ if (type == AnimationEndType::kEnded) {
+ // Set the bounds at the end of the animation and reset the transform.
view->SetBoundsRect(data.target_bounds);
+ } else {
+ DCHECK_EQ(AnimationEndType::kCanceled, type);
+ // Get the existing transform and apply it to the start bounds which is
+ // the current bounds of the view. This will place the bounds at the place
+ // where the animation stopped.
+ const gfx::Transform transform = view->GetTransform();
+ gfx::RectF bounds_f(view->bounds());
+ transform.TransformRect(&bounds_f);
+ view->SetBoundsRect(gfx::ToRoundedRect(bounds_f));
+ }
+ view->SetTransform(gfx::Transform());
}
if (data.delegate) {
diff --git a/chromium/ui/views/animation/bounds_animator.h b/chromium/ui/views/animation/bounds_animator.h
index 620145bce60..dff13110422 100644
--- a/chromium/ui/views/animation/bounds_animator.h
+++ b/chromium/ui/views/animation/bounds_animator.h
@@ -67,10 +67,6 @@ class VIEWS_EXPORT BoundsAnimator : public AnimationDelegateViews {
// animating its current bounds is returned.
gfx::Rect GetTargetBounds(const View* view) const;
- // Sets the animation for the specified view.
- void SetAnimationForView(View* view,
- std::unique_ptr<gfx::SlideAnimation> animation);
-
// Returns the animation for the specified view. BoundsAnimator owns the
// returned Animation.
const gfx::SlideAnimation* GetAnimationForView(View* view);
diff --git a/chromium/ui/views/animation/bounds_animator_unittest.cc b/chromium/ui/views/animation/bounds_animator_unittest.cc
index 790c74759e7..c09736c4572 100644
--- a/chromium/ui/views/animation/bounds_animator_unittest.cc
+++ b/chromium/ui/views/animation/bounds_animator_unittest.cc
@@ -6,6 +6,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/test/icu_test_util.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/animation/slide_animation.h"
@@ -78,6 +79,56 @@ class TestView : public View {
DISALLOW_COPY_AND_ASSIGN(TestView);
};
+class RTLAnimationTestDelegate : public gfx::AnimationDelegate {
+ public:
+ RTLAnimationTestDelegate(const gfx::Rect& start,
+ const gfx::Rect& target,
+ View* view,
+ base::RepeatingClosure quit_closure)
+ : start_(start),
+ target_(target),
+ view_(view),
+ quit_closure_(std::move(quit_closure)) {}
+ ~RTLAnimationTestDelegate() override = default;
+
+ private:
+ // gfx::AnimationDelegate:
+ void AnimationProgressed(const Animation* animation) override {
+ gfx::Transform transform = view_->GetTransform();
+ ASSERT_TRUE(!transform.IsIdentity());
+
+ // In this test, assume that |parent| is root view.
+ View* parent = view_->parent();
+
+ const gfx::Rect start_rect_in_screen = parent->GetMirroredRect(start_);
+ const gfx::Rect target_rect_in_screen = parent->GetMirroredRect(target_);
+
+ gfx::RectF current_bounds_in_screen(
+ parent->GetMirroredRect(view_->bounds()));
+ transform.TransformRect(&current_bounds_in_screen);
+
+ // Verify that |view_|'s current bounds in screen are valid.
+ EXPECT_GE(current_bounds_in_screen.x(),
+ std::min(start_rect_in_screen.x(), target_rect_in_screen.x()));
+ EXPECT_LE(
+ current_bounds_in_screen.right(),
+ std::max(start_rect_in_screen.right(), target_rect_in_screen.right()));
+
+ quit_closure_.Run();
+ }
+
+ // Animation initial bounds.
+ gfx::Rect start_;
+
+ // Animation target bounds.
+ gfx::Rect target_;
+
+ // view to be animated.
+ View* view_;
+
+ base::RepeatingClosure quit_closure_;
+};
+
} // namespace
class BoundsAnimatorTest : public testing::Test {
@@ -268,4 +319,64 @@ TEST_F(BoundsAnimatorTest, UseTransformsAnimateViewToEmptySrc) {
EXPECT_EQ(target_bounds, child()->bounds());
}
+// Tests that when using the transform option on the bounds animator, cancelling
+// the animation part way results in the correct bounds applied.
+TEST_F(BoundsAnimatorTest, UseTransformsCancelAnimation) {
+ RecreateAnimator(/*use_transforms=*/true);
+
+ gfx::Rect initial_bounds(0, 0, 10, 10);
+ child()->SetBoundsRect(initial_bounds);
+ gfx::Rect target_bounds(10, 10, 20, 20);
+
+ const base::TimeDelta duration = base::TimeDelta::FromMilliseconds(200);
+ animator()->SetAnimationDuration(duration);
+ // Use a linear tween so we can estimate the expected bounds.
+ animator()->set_tween_type(gfx::Tween::LINEAR);
+ animator()->AnimateViewTo(child(), target_bounds);
+ animator()->SetAnimationDelegate(child(),
+ std::make_unique<TestAnimationDelegate>());
+ EXPECT_TRUE(animator()->IsAnimating());
+ EXPECT_TRUE(animator()->IsAnimating(child()));
+
+ // Stop halfway and cancel. The child should have its bounds updated to
+ // exactly halfway between |initial_bounds| and |target_bounds|.
+ const gfx::Rect expected_bounds(5, 5, 15, 15);
+ task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(100));
+ EXPECT_EQ(initial_bounds, child()->bounds());
+ animator()->Cancel();
+ EXPECT_EQ(expected_bounds, child()->bounds());
+}
+
+// Verify that the bounds animation which updates the transform of views work
+// as expected under RTL (https://crbug.com/1067033).
+TEST_F(BoundsAnimatorTest, VerifyBoundsAnimatorUnderRTL) {
+ // Enable RTL.
+ base::test::ScopedRestoreICUDefaultLocale scoped_locale("he");
+
+ RecreateAnimator(/*use_transform=*/true);
+ parent()->SetBounds(0, 0, 40, 40);
+
+ const gfx::Rect initial_bounds(0, 0, 10, 10);
+ child()->SetBoundsRect(initial_bounds);
+ const gfx::Rect target_bounds(10, 10, 10, 10);
+
+ const base::TimeDelta animation_duration =
+ base::TimeDelta::FromMilliseconds(10);
+ animator()->SetAnimationDuration(animation_duration);
+ child()->set_repaint_count(0);
+ animator()->AnimateViewTo(child(), target_bounds);
+ base::RunLoop run_loop;
+ animator()->SetAnimationDelegate(
+ child(),
+ std::make_unique<RTLAnimationTestDelegate>(
+ initial_bounds, target_bounds, child(), run_loop.QuitClosure()));
+
+ // The animator should be animating now.
+ EXPECT_TRUE(animator()->IsAnimating());
+ EXPECT_TRUE(animator()->IsAnimating(child()));
+
+ run_loop.Run();
+ EXPECT_FALSE(animator()->IsAnimating(child()));
+}
+
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop.h b/chromium/ui/views/animation/ink_drop.h
index e0b95f64e99..b8692ae1330 100644
--- a/chromium/ui/views/animation/ink_drop.h
+++ b/chromium/ui/views/animation/ink_drop.h
@@ -30,6 +30,9 @@ class VIEWS_EXPORT InkDrop {
// Called by ink drop hosts when their size is changed.
virtual void HostSizeChanged(const gfx::Size& new_size) = 0;
+ // Called by ink drop hosts when their transform is changed.
+ virtual void HostTransformChanged(const gfx::Transform& new_transform) = 0;
+
// Gets the target state of the ink drop.
virtual InkDropState GetTargetInkDropState() const = 0;
diff --git a/chromium/ui/views/animation/ink_drop_animation_ended_reason.cc b/chromium/ui/views/animation/ink_drop_animation_ended_reason.cc
index 8499995cd34..f1e4c5553f5 100644
--- a/chromium/ui/views/animation/ink_drop_animation_ended_reason.cc
+++ b/chromium/ui/views/animation/ink_drop_animation_ended_reason.cc
@@ -4,7 +4,9 @@
#include "ui/views/animation/ink_drop_animation_ended_reason.h"
-#include "base/logging.h"
+#include <ostream>
+
+#include "base/notreached.h"
namespace views {
diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc
index cb4df9bda33..48e61528b74 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view.cc
@@ -182,13 +182,26 @@ void InkDropHostView::ResetInkDropMask() {
}
bool InkDropHostView::AddInkDropClip(ui::Layer* ink_drop_layer) {
- base::Optional<HighlightPathGenerator::RoundRect> clipping_data =
+ base::Optional<gfx::RRectF> clipping_data =
HighlightPathGenerator::GetRoundRectForView(this);
if (!clipping_data)
return false;
- ink_drop_layer->SetClipRect(gfx::ToEnclosingRect(clipping_data->bounds));
- ink_drop_layer->SetRoundedCornerRadius(
- gfx::RoundedCornersF(clipping_data->corner_radius));
+
+ ink_drop_layer->SetClipRect(gfx::ToEnclosingRect(clipping_data->rect()));
+ auto get_corner_radii =
+ [&clipping_data](gfx::RRectF::Corner corner) -> float {
+ return clipping_data.value().GetCornerRadii(corner).x();
+ };
+ gfx::RoundedCornersF rounded_corners;
+ rounded_corners.set_upper_left(
+ get_corner_radii(gfx::RRectF::Corner::kUpperLeft));
+ rounded_corners.set_upper_right(
+ get_corner_radii(gfx::RRectF::Corner::kUpperRight));
+ rounded_corners.set_lower_right(
+ get_corner_radii(gfx::RRectF::Corner::kLowerRight));
+ rounded_corners.set_lower_left(
+ get_corner_radii(gfx::RRectF::Corner::kLowerLeft));
+ ink_drop_layer->SetRoundedCornerRadius(rounded_corners);
ink_drop_layer->SetIsFastRoundedCorner(true);
return true;
}
diff --git a/chromium/ui/views/animation/ink_drop_host_view_unittest.cc b/chromium/ui/views/animation/ink_drop_host_view_unittest.cc
index 390e1a991a9..303547f1bed 100644
--- a/chromium/ui/views/animation/ink_drop_host_view_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view_unittest.cc
@@ -220,7 +220,7 @@ TEST_F(InkDropHostViewTest, NoInkDropOnTouchOrGestureEvents) {
ui::TouchEvent touch_event(
ui::ET_TOUCH_PRESSED, gfx::Point(5, 6), ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1));
+ ui::PointerDetails(ui::EventPointerType::kTouch, 1));
test_api_.AnimateInkDrop(InkDropState::ACTION_PENDING, &touch_event);
EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
@@ -268,7 +268,7 @@ TEST_F(InkDropHostViewTest, DismissInkDropOnTouchOrGestureEvents) {
ui::TouchEvent touch_event(
ui::ET_TOUCH_PRESSED, gfx::Point(5, 6), ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1));
+ ui::PointerDetails(ui::EventPointerType::kTouch, 1));
test_api_.AnimateInkDrop(InkDropState::ACTION_TRIGGERED, &touch_event);
EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
diff --git a/chromium/ui/views/animation/ink_drop_impl.cc b/chromium/ui/views/animation/ink_drop_impl.cc
index c5d93d3d4c4..631a69e84be 100644
--- a/chromium/ui/views/animation/ink_drop_impl.cc
+++ b/chromium/ui/views/animation/ink_drop_impl.cc
@@ -628,6 +628,12 @@ void InkDropImpl::HostSizeChanged(const gfx::Size& new_size) {
}
}
+void InkDropImpl::HostTransformChanged(const gfx::Transform& new_transform) {
+ // If the host has a transform applied, the root and its children layers
+ // should be affected too.
+ root_layer_->SetTransform(new_transform);
+}
+
InkDropState InkDropImpl::GetTargetInkDropState() const {
if (!ink_drop_ripple_)
return InkDropState::HIDDEN;
diff --git a/chromium/ui/views/animation/ink_drop_impl.h b/chromium/ui/views/animation/ink_drop_impl.h
index 46b1b305456..971f3548adc 100644
--- a/chromium/ui/views/animation/ink_drop_impl.h
+++ b/chromium/ui/views/animation/ink_drop_impl.h
@@ -70,6 +70,7 @@ class VIEWS_EXPORT InkDropImpl : public InkDrop,
// InkDrop:
void HostSizeChanged(const gfx::Size& new_size) override;
+ void HostTransformChanged(const gfx::Transform& new_transform) override;
InkDropState GetTargetInkDropState() const override;
void AnimateToState(InkDropState ink_drop_state) override;
void SetHoverHighlightFadeDuration(base::TimeDelta duration) override;
diff --git a/chromium/ui/views/animation/ink_drop_state.cc b/chromium/ui/views/animation/ink_drop_state.cc
index adbefae1a22..f06a305ca59 100644
--- a/chromium/ui/views/animation/ink_drop_state.cc
+++ b/chromium/ui/views/animation/ink_drop_state.cc
@@ -4,9 +4,10 @@
#include "ui/views/animation/ink_drop_state.h"
+#include <ostream>
#include <string>
-#include "base/logging.h"
+#include "base/notreached.h"
namespace views {
diff --git a/chromium/ui/views/animation/ink_drop_stub.cc b/chromium/ui/views/animation/ink_drop_stub.cc
index 24e6245a68e..c15af9618d1 100644
--- a/chromium/ui/views/animation/ink_drop_stub.cc
+++ b/chromium/ui/views/animation/ink_drop_stub.cc
@@ -12,6 +12,8 @@ InkDropStub::~InkDropStub() = default;
void InkDropStub::HostSizeChanged(const gfx::Size& new_size) {}
+void InkDropStub::HostTransformChanged(const gfx::Transform& new_transform) {}
+
InkDropState InkDropStub::GetTargetInkDropState() const {
return InkDropState::HIDDEN;
}
diff --git a/chromium/ui/views/animation/ink_drop_stub.h b/chromium/ui/views/animation/ink_drop_stub.h
index ba8985cc5c7..849bc196e03 100644
--- a/chromium/ui/views/animation/ink_drop_stub.h
+++ b/chromium/ui/views/animation/ink_drop_stub.h
@@ -20,6 +20,7 @@ class VIEWS_EXPORT InkDropStub : public InkDrop {
// InkDrop:
void HostSizeChanged(const gfx::Size& new_size) override;
+ void HostTransformChanged(const gfx::Transform& new_transform) override;
InkDropState GetTargetInkDropState() const override;
void AnimateToState(InkDropState state) override;
void SetHoverHighlightFadeDuration(base::TimeDelta duration) override;
diff --git a/chromium/ui/views/animation/ink_drop_util.cc b/chromium/ui/views/animation/ink_drop_util.cc
index 1e5bbb18ace..72ce6649793 100644
--- a/chromium/ui/views/animation/ink_drop_util.cc
+++ b/chromium/ui/views/animation/ink_drop_util.cc
@@ -6,7 +6,7 @@
#include <math.h>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "ui/gfx/geometry/vector2d_f.h"
diff --git a/chromium/ui/views/animation/installable_ink_drop.cc b/chromium/ui/views/animation/installable_ink_drop.cc
index e0708a8ce9d..ee67a05be7f 100644
--- a/chromium/ui/views/animation/installable_ink_drop.cc
+++ b/chromium/ui/views/animation/installable_ink_drop.cc
@@ -6,8 +6,9 @@
#include <algorithm>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/memory/ptr_util.h"
+#include "base/notreached.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPath.h"
@@ -106,6 +107,9 @@ void InstallableInkDrop::HostSizeChanged(const gfx::Size& new_size) {
animator_.SetSize(layer_->size());
}
+void InstallableInkDrop::HostTransformChanged(
+ const gfx::Transform& new_transform) {}
+
InkDropState InstallableInkDrop::GetTargetInkDropState() const {
return animator_.target_state();
}
diff --git a/chromium/ui/views/animation/installable_ink_drop.h b/chromium/ui/views/animation/installable_ink_drop.h
index 65eb6489883..1fa261a776d 100644
--- a/chromium/ui/views/animation/installable_ink_drop.h
+++ b/chromium/ui/views/animation/installable_ink_drop.h
@@ -67,6 +67,7 @@ class VIEWS_EXPORT InstallableInkDrop : public InkDrop,
// InkDrop:
void HostSizeChanged(const gfx::Size& new_size) override;
+ void HostTransformChanged(const gfx::Transform& new_transform) override;
InkDropState GetTargetInkDropState() const override;
void AnimateToState(InkDropState ink_drop_state) override;
void SetHoverHighlightFadeDuration(base::TimeDelta duration) override;
diff --git a/chromium/ui/views/animation/installable_ink_drop_animator.cc b/chromium/ui/views/animation/installable_ink_drop_animator.cc
index 54c014b6508..4acf8cfcbf5 100644
--- a/chromium/ui/views/animation/installable_ink_drop_animator.cc
+++ b/chromium/ui/views/animation/installable_ink_drop_animator.cc
@@ -7,7 +7,8 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/logging.h"
+#include "base/check_op.h"
+#include "base/notreached.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/point_f.h"
diff --git a/chromium/ui/views/animation/scroll_animator.cc b/chromium/ui/views/animation/scroll_animator.cc
index 64a270d69ab..7f5a66f1e4f 100644
--- a/chromium/ui/views/animation/scroll_animator.cc
+++ b/chromium/ui/views/animation/scroll_animator.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include <cmath>
-#include "base/logging.h"
+#include "base/check.h"
#include "ui/gfx/animation/slide_animation.h"
namespace {
diff --git a/chromium/ui/views/background.cc b/chromium/ui/views/background.cc
index d8fc6304194..ed6a43ff33e 100644
--- a/chromium/ui/views/background.cc
+++ b/chromium/ui/views/background.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "base/scoped_observer.h"
#include "build/build_config.h"
diff --git a/chromium/ui/views/border.cc b/chromium/ui/views/border.cc
index e7b20c6f2e6..041214dc717 100644
--- a/chromium/ui/views/border.cc
+++ b/chromium/ui/views/border.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "cc/paint/paint_flags.h"
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index 9b278304422..22b609a91c5 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -10,8 +10,9 @@
#include <utility>
#include <vector>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/no_destructor.h"
+#include "base/notreached.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
#include "third_party/skia/include/core/SkPath.h"
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
index 308adac42ea..be71a1d4243 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -12,6 +12,7 @@
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_role_properties.h"
#include "ui/base/default_style.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_utils.h"
@@ -153,10 +154,6 @@ class BubbleDialogDelegateView::AnchorViewObserver : public ViewObserver {
parent_->OnAnchorBoundsChanged();
}
- void OnViewAddedToWidget(View* observed_view) override {
- parent_->SetAnchorWidget(observed_view->GetWidget());
- }
-
// TODO(pbos): Consider observing View visibility changes and only updating
// view bounds when the anchor is visible.
@@ -169,6 +166,8 @@ class BubbleDialogDelegateView::AnchorViewObserver : public ViewObserver {
Widget* BubbleDialogDelegateView::CreateBubble(
BubbleDialogDelegateView* bubble_delegate) {
bubble_delegate->Init();
+ // Get the latest anchor widget from the anchor view at bubble creation time.
+ bubble_delegate->SetAnchorView(bubble_delegate->GetAnchorView());
Widget* bubble_widget = CreateBubbleWidget(bubble_delegate);
#if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
@@ -189,6 +188,8 @@ BubbleDialogDelegateView::BubbleDialogDelegateView(View* anchor_view,
BubbleBorder::Arrow arrow,
BubbleBorder::Shadow shadow)
: shadow_(shadow) {
+ WidgetDelegate::SetShowCloseButton(false);
+
SetArrow(arrow);
LayoutProvider* provider = LayoutProvider::Get();
// An individual bubble should override these margins if its layout differs
@@ -210,10 +211,6 @@ BubbleDialogDelegateView* BubbleDialogDelegateView::AsBubbleDialogDelegate() {
return this;
}
-bool BubbleDialogDelegateView::ShouldShowCloseButton() const {
- return false;
-}
-
NonClientFrameView* BubbleDialogDelegateView::CreateNonClientFrameView(
Widget* widget) {
BubbleFrameView* frame = new BubbleDialogFrameView(title_margins_);
@@ -456,18 +453,49 @@ void BubbleDialogDelegateView::SetAnchorView(View* anchor_view) {
anchor_view_observer_.reset();
}
- SetAnchorWidget(anchor_view ? anchor_view->GetWidget() : nullptr);
- if (!anchor_view)
- return;
+ // When the anchor view gets set the associated anchor widget might
+ // change as well.
+ if (!anchor_view || anchor_widget() != anchor_view->GetWidget()) {
+ if (anchor_widget()) {
+ if (GetWidget() && GetWidget()->IsVisible())
+ UpdateHighlightedButton(false);
+ paint_as_active_lock_.reset();
+ anchor_widget_->RemoveObserver(this);
+ anchor_widget_ = nullptr;
+ }
+ if (anchor_view) {
+ anchor_widget_ = anchor_view->GetWidget();
+ if (anchor_widget_) {
+ anchor_widget_->AddObserver(this);
+ const bool visible = GetWidget() && GetWidget()->IsVisible();
+ UpdateHighlightedButton(visible);
+ // Have the anchor widget's paint-as-active state track this view's
+ // widget - lock is only required if the bubble widget is active.
+ if (anchor_widget_->GetTopLevelWidget() && GetWidget() &&
+ GetWidget()->ShouldPaintAsActive()) {
+ paint_as_active_lock_ =
+ anchor_widget_->GetTopLevelWidget()->LockPaintAsActive();
+ }
+ }
+ }
+ }
- anchor_view_observer_ =
- std::make_unique<AnchorViewObserver>(this, anchor_view);
- OnAnchorBoundsChanged();
+ if (anchor_view) {
+ anchor_view_observer_ =
+ std::make_unique<AnchorViewObserver>(this, anchor_view);
+ // Do not update anchoring for NULL views; this could indicate
+ // that our NativeWindow is being destroyed, so it would be
+ // dangerous for us to update our anchor bounds at that
+ // point. (It's safe to skip this, since if we were to update the
+ // bounds when |anchor_view| is NULL, the bubble won't move.)
+ OnAnchorBoundsChanged();
+ }
- // Make sure that focus can move into here from the anchor view (but not out,
- // focus will cycle inside the dialog once it gets here).
- if (focus_traversable_from_anchor_view_)
+ if (anchor_view && focus_traversable_from_anchor_view_) {
+ // Make sure that focus can move into here from the anchor view (but not
+ // out, focus will cycle inside the dialog once it gets here).
anchor_view->SetProperty(kAnchoredDialogKey, this);
+ }
}
void BubbleDialogDelegateView::SetAnchorRect(const gfx::Rect& rect) {
@@ -520,8 +548,7 @@ void BubbleDialogDelegateView::HandleVisibilityChanged(Widget* widget,
// the bubble in its entirety rather than just its title and initially focused
// view. See http://crbug.com/474622 for details.
if (widget == GetWidget() && visible) {
- if (GetAccessibleWindowRole() == ax::mojom::Role::kAlert ||
- GetAccessibleWindowRole() == ax::mojom::Role::kAlertDialog) {
+ if (ui::IsAlert(GetAccessibleWindowRole())) {
widget->GetRootView()->NotifyAccessibilityEvent(ax::mojom::Event::kAlert,
true);
}
@@ -533,28 +560,6 @@ void BubbleDialogDelegateView::OnDeactivate() {
GetWidget()->CloseWithReason(views::Widget::ClosedReason::kLostFocus);
}
-void BubbleDialogDelegateView::SetAnchorWidget(Widget* anchor_widget) {
- if (anchor_widget_ == anchor_widget)
- return;
-
- if (anchor_widget_)
- anchor_widget_->RemoveObserver(this);
-
- UpdateHighlightedButton(GetWidget() && GetWidget()->IsVisible() &&
- anchor_widget);
- // Have the anchor widget's paint-as-active state track this view's widget.
- // Lock is only required if the bubble widget is active.
- paint_as_active_lock_ =
- (GetWidget() && GetWidget()->ShouldPaintAsActive() && anchor_widget &&
- anchor_widget->GetTopLevelWidget())
- ? anchor_widget->GetTopLevelWidget()->LockPaintAsActive()
- : nullptr;
- anchor_widget_ = anchor_widget;
-
- if (anchor_widget_)
- anchor_widget_->AddObserver(this);
-}
-
void BubbleDialogDelegateView::UpdateHighlightedButton(bool highlighted) {
Button* button = Button::AsButton(highlighted_button_tracker_.view());
button = button ? button : Button::AsButton(GetAnchorView());
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
index 862b3d89dec..c56ab1fa993 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -67,7 +67,6 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
// DialogDelegateView:
BubbleDialogDelegateView* AsBubbleDialogDelegate() override;
- bool ShouldShowCloseButton() const override;
NonClientFrameView* CreateNonClientFrameView(Widget* widget) override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
@@ -213,9 +212,6 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
// Called when a deactivation is detected.
void OnDeactivate();
- // Updates the anchoring widget.
- void SetAnchorWidget(Widget* widget);
-
// Update the button highlight, which may be the anchor view or an explicit
// view set in |highlighted_button_tracker_|. This can be overridden to
// provide different highlight effects.
diff --git a/chromium/ui/views/bubble/footnote_container_view.cc b/chromium/ui/views/bubble/footnote_container_view.cc
index 68c08db02f3..1478fc8cbbb 100644
--- a/chromium/ui/views/bubble/footnote_container_view.cc
+++ b/chromium/ui/views/bubble/footnote_container_view.cc
@@ -57,7 +57,6 @@ FootnoteContainerView::FootnoteContainerView(const gfx::Insets& margins,
SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kVertical, margins, 0));
SetCornerRadius(corner_radius);
- ResetBorder();
auto* child_view_ptr = AddChildView(std::move(child_view));
SetVisible(child_view_ptr->GetVisible());
}
@@ -88,10 +87,9 @@ void FootnoteContainerView::ResetBackground() {
}
void FootnoteContainerView::ResetBorder() {
- SetBorder(CreateSolidSidedBorder(1, 0, 0, 0,
- GetNativeTheme()->ShouldUseDarkColors()
- ? gfx::kGoogleGrey900
- : gfx::kGoogleGrey200));
+ SetBorder(CreateSolidSidedBorder(
+ 1, 0, 0, 0, GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_FootnoteContainerBorder)));
}
BEGIN_METADATA(FootnoteContainerView)
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.cc b/chromium/ui/views/color_chooser/color_chooser_view.cc
index 2cd1303c808..2459d40c9e2 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.cc
+++ b/chromium/ui/views/color_chooser/color_chooser_view.cc
@@ -11,7 +11,7 @@
#include <string>
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "base/numerics/ranges.h"
#include "base/strings/string_number_conversions.h"
@@ -382,10 +382,10 @@ ColorChooserView::ColorChooserView(ColorChooserListener* listener,
container2->SetLayoutManager(std::make_unique<views::GridLayout>());
ColumnSet* columns = layout->AddColumnSet(0);
columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
columns->AddPaddingColumn(0, kMarginWidth);
columns->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(0, 0);
auto textfield = std::make_unique<Textfield>();
textfield->set_controller(this);
diff --git a/chromium/ui/views/controls/button/button_controller.cc b/chromium/ui/views/controls/button/button_controller.cc
index 3278b27d162..f639cf93c55 100644
--- a/chromium/ui/views/controls/button/button_controller.cc
+++ b/chromium/ui/views/controls/button/button_controller.cc
@@ -116,6 +116,9 @@ bool ButtonController::OnKeyReleased(const ui::KeyEvent& event) {
}
void ButtonController::OnGestureEvent(ui::GestureEvent* event) {
+ if (button_->state() == Button::STATE_DISABLED)
+ return;
+
if (event->type() == ui::ET_GESTURE_TAP &&
button_controller_delegate_->IsTriggerableEvent(*event)) {
// A GESTURE_END event is issued immediately after ET_GESTURE_TAP and will
diff --git a/chromium/ui/views/controls/button/button_unittest.cc b/chromium/ui/views/controls/button/button_unittest.cc
index 54e0cad33d1..3dfeba259fd 100644
--- a/chromium/ui/views/controls/button/button_unittest.cc
+++ b/chromium/ui/views/controls/button/button_unittest.cc
@@ -7,6 +7,8 @@
#include <memory>
#include <utility>
+#include "base/bind.h"
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
@@ -80,6 +82,9 @@ class TestButton : public Button, public ButtonListener {
void ButtonPressed(Button* sender, const ui::Event& event) override {
pressed_ = true;
+
+ if (!on_button_pressed_handler_.is_null())
+ on_button_pressed_handler_.Run();
}
void OnClickCanceled(const ui::Event& event) override { canceled_ = true; }
@@ -103,6 +108,10 @@ class TestButton : public Button, public ButtonListener {
custom_key_click_action_ = custom_key_click_action;
}
+ void set_on_button_pressed_handler(const base::RepeatingClosure& callback) {
+ on_button_pressed_handler_ = callback;
+ }
+
void Reset() {
pressed_ = false;
canceled_ = false;
@@ -120,6 +129,9 @@ class TestButton : public Button, public ButtonListener {
KeyClickAction custom_key_click_action_ = KeyClickAction::kNone;
+ // If available, will be triggered when the button is pressed.
+ base::RepeatingClosure on_button_pressed_handler_;
+
DISALLOW_COPY_AND_ASSIGN(TestButton);
};
@@ -159,6 +171,22 @@ class TestButtonObserver : public ButtonObserver {
DISALLOW_COPY_AND_ASSIGN(TestButtonObserver);
};
+TestInkDrop* AddTestInkDrop(TestButton* button) {
+ auto owned_ink_drop = std::make_unique<TestInkDrop>();
+ TestInkDrop* ink_drop = owned_ink_drop.get();
+ InkDropHostViewTestApi(button).SetInkDrop(std::move(owned_ink_drop));
+ return ink_drop;
+}
+
+// TODO(tluk): remove when the appropriate ownership APIs have been added for
+// Widget's SetContentsView().
+template <typename T>
+T* AddContentsView(Widget* widget, std::unique_ptr<T> view) {
+ T* view_ptr = view.get();
+ widget->SetContentsView(view.release());
+ return view_ptr;
+}
+
} // namespace
class ButtonTest : public ViewsTestBase {
@@ -179,8 +207,7 @@ class ButtonTest : public ViewsTestBase {
widget_->Init(std::move(params));
widget_->Show();
- button_ = std::make_unique<TestButton>(false);
- widget_->SetContentsView(button_.get());
+ button_ = AddContentsView(widget(), std::make_unique<TestButton>(false));
event_generator_ =
std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget()));
@@ -192,37 +219,35 @@ class ButtonTest : public ViewsTestBase {
button_->RemoveButtonObserver(button_observer_.get());
button_observer_.reset();
- button_.reset();
widget_.reset();
ViewsTestBase::TearDown();
}
- void CreateButtonWithInkDrop(std::unique_ptr<InkDrop> ink_drop,
- bool has_ink_drop_action_on_click) {
- button_ = std::make_unique<TestButton>(has_ink_drop_action_on_click);
- InkDropHostViewTestApi(button_.get()).SetInkDrop(std::move(ink_drop));
- widget_->SetContentsView(button_.get());
+ TestInkDrop* CreateButtonWithInkDrop(bool has_ink_drop_action_on_click) {
+ button_ = AddContentsView(
+ widget(), std::make_unique<TestButton>(has_ink_drop_action_on_click));
+ widget_->SetContentsView(button_);
+ return AddTestInkDrop(button_);
}
void CreateButtonWithRealInkDrop() {
- button_ = std::make_unique<TestButton>(false);
- InkDropHostViewTestApi(button_.get())
- .SetInkDrop(
- std::make_unique<InkDropImpl>(button_.get(), button_->size()));
- widget_->SetContentsView(button_.get());
+ button_ = AddContentsView(widget(), std::make_unique<TestButton>(false));
+ InkDropHostViewTestApi(button_).SetInkDrop(
+ std::make_unique<InkDropImpl>(button_, button_->size()));
+ widget_->SetContentsView(button_);
}
void CreateButtonWithObserver() {
- button_ = std::make_unique<TestButton>(false);
+ button_ = AddContentsView(widget(), std::make_unique<TestButton>(false));
button_observer_ = std::make_unique<TestButtonObserver>();
button_->AddButtonObserver(button_observer_.get());
- widget_->SetContentsView(button_.get());
+ widget_->SetContentsView(button_);
}
protected:
Widget* widget() { return widget_.get(); }
- TestButton* button() { return button_.get(); }
+ TestButton* button() { return button_; }
TestButtonObserver* button_observer() { return button_observer_.get(); }
ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
void SetDraggedView(View* dragged_view) {
@@ -231,7 +256,7 @@ class ButtonTest : public ViewsTestBase {
private:
std::unique_ptr<Widget> widget_;
- std::unique_ptr<TestButton> button_;
+ TestButton* button_;
std::unique_ptr<TestButtonObserver> button_observer_;
std::unique_ptr<ui::test::EventGenerator> event_generator_;
@@ -419,6 +444,18 @@ TEST_F(ButtonTest, GestureEventsSetState) {
EXPECT_EQ(Button::STATE_NORMAL, button()->state());
}
+// Tests that if the button was disabled in its button press handler, gesture
+// events will not revert the disabled state back to normal.
+// https://crbug.com/1084241.
+TEST_F(ButtonTest, GestureEventsRespectDisabledState) {
+ button()->set_on_button_pressed_handler(base::BindRepeating(
+ [](TestButton* button) { button->SetEnabled(false); }, button()));
+
+ EXPECT_EQ(Button::STATE_NORMAL, button()->state());
+ event_generator()->GestureTapAt(button()->GetBoundsInScreen().CenterPoint());
+ EXPECT_EQ(Button::STATE_DISABLED, button()->state());
+}
+
#endif // !defined(OS_MACOSX) || defined(USE_AURA)
// Ensure subclasses of Button are correctly recognized as Button.
@@ -458,8 +495,7 @@ TEST_F(ButtonTest, AsButton) {
// Note: Ink drop is not hidden upon release because Button descendants
// may enter a different ink drop state.
TEST_F(ButtonTest, ButtonClickTogglesInkDrop) {
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
event_generator()->MoveMouseTo(button()->GetBoundsInScreen().CenterPoint());
event_generator()->PressLeftButton();
@@ -472,8 +508,7 @@ TEST_F(ButtonTest, ButtonClickTogglesInkDrop) {
// Tests that pressing a button shows and releasing capture hides ink drop.
// Releasing capture should also reset PRESSED button state to NORMAL.
TEST_F(ButtonTest, CaptureLossHidesInkDrop) {
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
event_generator()->MoveMouseTo(button()->GetBoundsInScreen().CenterPoint());
event_generator()->PressLeftButton();
@@ -489,8 +524,7 @@ TEST_F(ButtonTest, CaptureLossHidesInkDrop) {
}
TEST_F(ButtonTest, HideInkDropWhenShowingContextMenu) {
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
TestContextMenuController context_menu_controller;
button()->set_context_menu_controller(&context_menu_controller);
button()->set_hide_ink_drop_when_showing_context_menu(true);
@@ -505,8 +539,7 @@ TEST_F(ButtonTest, HideInkDropWhenShowingContextMenu) {
}
TEST_F(ButtonTest, DontHideInkDropWhenShowingContextMenu) {
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
TestContextMenuController context_menu_controller;
button()->set_context_menu_controller(&context_menu_controller);
button()->set_hide_ink_drop_when_showing_context_menu(false);
@@ -523,8 +556,7 @@ TEST_F(ButtonTest, DontHideInkDropWhenShowingContextMenu) {
TEST_F(ButtonTest, HideInkDropOnBlur) {
gfx::Point center(10, 10);
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
button()->OnFocus();
@@ -543,8 +575,7 @@ TEST_F(ButtonTest, HideInkDropOnBlur) {
}
TEST_F(ButtonTest, HideInkDropHighlightOnDisable) {
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
event_generator()->MoveMouseTo(button()->GetBoundsInScreen().CenterPoint());
EXPECT_TRUE(ink_drop->is_hovered());
@@ -555,8 +586,7 @@ TEST_F(ButtonTest, HideInkDropHighlightOnDisable) {
}
TEST_F(ButtonTest, InkDropAfterTryingToShowContextMenu) {
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
button()->set_context_menu_controller(nullptr);
ink_drop->SetHovered(true);
@@ -569,34 +599,31 @@ TEST_F(ButtonTest, InkDropAfterTryingToShowContextMenu) {
}
TEST_F(ButtonTest, HideInkDropHighlightWhenRemoved) {
- views::View test_container;
- test_container.set_owned_by_client();
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
- // Mark the button as owned by client so we can remove it from widget()
- // without it being deleted.
- button()->set_owned_by_client();
+ View* contents_view = AddContentsView(widget(), std::make_unique<View>());
+
+ TestButton* button =
+ contents_view->AddChildView(std::make_unique<TestButton>(false));
+ button->SetBounds(0, 0, 200, 200);
+ TestInkDrop* ink_drop = AddTestInkDrop(button);
// Make sure that the button ink drop is hidden after the button gets removed.
- widget()->SetContentsView(&test_container);
- test_container.AddChildView(button());
- event_generator()->MoveMouseTo(button()->GetBoundsInScreen().origin());
+ event_generator()->MoveMouseTo(button->GetBoundsInScreen().origin());
event_generator()->MoveMouseBy(2, 2);
EXPECT_TRUE(ink_drop->is_hovered());
// Set ink-drop state to ACTIVATED to make sure that removing the container
// sets it back to HIDDEN.
ink_drop->AnimateToState(InkDropState::ACTIVATED);
- test_container.RemoveAllChildViews(false);
+ auto owned_button = contents_view->RemoveChildViewT(button);
+ button = nullptr;
+
EXPECT_FALSE(ink_drop->is_hovered());
EXPECT_EQ(InkDropState::HIDDEN, ink_drop->GetTargetInkDropState());
// Make sure hiding the ink drop happens even if the button is indirectly
// being removed.
- views::View parent_test_container;
- parent_test_container.set_owned_by_client();
- widget()->SetContentsView(&parent_test_container);
- parent_test_container.AddChildView(&test_container);
- test_container.AddChildView(button());
+ View* parent_view = contents_view->AddChildView(std::make_unique<View>());
+ parent_view->SetBounds(0, 0, 400, 400);
+ button = parent_view->AddChildView(std::move(owned_button));
// Trigger hovering and then remove from the indirect parent. This should
// propagate down to Button which should remove the highlight effect.
@@ -606,17 +633,9 @@ TEST_F(ButtonTest, HideInkDropHighlightWhenRemoved) {
// Set ink-drop state to ACTIVATED to make sure that removing the container
// sets it back to HIDDEN.
ink_drop->AnimateToState(InkDropState::ACTIVATED);
- parent_test_container.RemoveAllChildViews(false);
+ auto owned_parent = contents_view->RemoveChildViewT(parent_view);
EXPECT_EQ(InkDropState::HIDDEN, ink_drop->GetTargetInkDropState());
EXPECT_FALSE(ink_drop->is_hovered());
-
- // Remove references to and delete button() which cannot be removed by owned
- // containers as it's permanently set as owned by client.
- test_container.RemoveAllChildViews(false);
-
- // Set the widget contents view to a new View so widget() doesn't contain a
- // stale reference to the test containers that are about to go out of scope.
- widget()->SetContentsView(new View());
}
// Tests that when button is set to notify on release, dragging mouse out and
@@ -625,8 +644,7 @@ TEST_F(ButtonTest, InkDropShowHideOnMouseDraggedNotifyOnRelease) {
gfx::Point center(10, 10);
gfx::Point oob(-1, -1);
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
button()->button_controller()->set_notify_action(
ButtonController::NotifyAction::kOnRelease);
@@ -667,8 +685,7 @@ TEST_F(ButtonTest, InkDropShowHideOnMouseDraggedNotifyOnPress) {
gfx::Point center(10, 10);
gfx::Point oob(-1, -1);
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), true);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(true);
button()->button_controller()->set_notify_action(
ButtonController::NotifyAction::kOnPress);
@@ -708,8 +725,7 @@ TEST_F(ButtonTest, InkDropStaysHiddenWhileDragging) {
gfx::Point center(10, 10);
gfx::Point oob(-1, -1);
- TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ TestInkDrop* ink_drop = CreateButtonWithInkDrop(false);
button()->OnMousePressed(ui::MouseEvent(
ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(),
@@ -738,35 +754,51 @@ TEST_F(ButtonTest, InkDropStaysHiddenWhileDragging) {
SetDraggedView(nullptr);
}
+// VisibilityTestButton tests to see if an ink drop or a layer has been added to
+// the button at any point during the visibility state changes of its Widget.
+class VisibilityTestButton : public TestButton {
+ public:
+ VisibilityTestButton() : TestButton(false) {}
+ ~VisibilityTestButton() override {
+ if (layer())
+ ADD_FAILURE();
+ }
+
+ // TestButton:
+ void AddInkDropLayer(ui::Layer* ink_drop_layer) override {
+ ADD_FAILURE();
+ TestButton::AddInkDropLayer(ink_drop_layer);
+ }
+ void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override {
+ ADD_FAILURE();
+ TestButton::RemoveInkDropLayer(ink_drop_layer);
+ }
+};
+
// Test that hiding or closing a Widget doesn't attempt to add a layer due to
// changed visibility states.
TEST_F(ButtonTest, NoLayerAddedForWidgetVisibilityChanges) {
- CreateButtonWithRealInkDrop();
+ VisibilityTestButton* button =
+ AddContentsView(widget(), std::make_unique<VisibilityTestButton>());
- EXPECT_TRUE(button()->GetVisible());
- EXPECT_FALSE(button()->layer());
+ // Ensure no layers are created during construction.
+ EXPECT_TRUE(button->GetVisible());
+ EXPECT_FALSE(button->layer());
+ // Ensure no layers are created when hiding the widget.
widget()->Hide();
- EXPECT_FALSE(button()->layer());
- EXPECT_EQ(0, button()->ink_drop_layer_add_count());
- EXPECT_EQ(0, button()->ink_drop_layer_remove_count());
+ EXPECT_FALSE(button->layer());
+ // Ensure no layers are created when the widget is reshown.
widget()->Show();
- EXPECT_FALSE(button()->layer());
- EXPECT_EQ(0, button()->ink_drop_layer_add_count());
- EXPECT_EQ(0, button()->ink_drop_layer_remove_count());
+ EXPECT_FALSE(button->layer());
- // Allow the button to be interrogated after the view hierarchy is torn down.
- button()->set_owned_by_client();
+ // Ensure no layers are created during the closing of the Widget.
widget()->Close(); // Start an asynchronous close.
- EXPECT_FALSE(button()->layer());
- EXPECT_EQ(0, button()->ink_drop_layer_add_count());
- EXPECT_EQ(0, button()->ink_drop_layer_remove_count());
+ EXPECT_FALSE(button->layer());
+ // Ensure no layers are created following the Widget's destruction.
base::RunLoop().RunUntilIdle(); // Complete the Close().
- EXPECT_FALSE(button()->layer());
- EXPECT_EQ(0, button()->ink_drop_layer_add_count());
- EXPECT_EQ(0, button()->ink_drop_layer_remove_count());
}
// Verify that the Space key clicks the button on key-press on Mac, and
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index 8788ff2e07e..06050cc2479 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -185,7 +185,7 @@ SkPath Checkbox::GetFocusRingPath() const {
SkColor Checkbox::GetIconImageColor(int icon_state) const {
const SkColor active_color = GetNativeTheme()->GetSystemColor(
(icon_state & IconState::CHECKED)
- ? ui::NativeTheme::kColorId_ButtonEnabledColor
+ ? ui::NativeTheme::kColorId_ButtonCheckedColor
: ui::NativeTheme::kColorId_ButtonUncheckedColor);
return (icon_state & IconState::ENABLED)
? active_color
diff --git a/chromium/ui/views/controls/button/image_button_factory.cc b/chromium/ui/views/controls/button/image_button_factory.cc
index 3b492d1e9b5..5ac49262cfe 100644
--- a/chromium/ui/views/controls/button/image_button_factory.cc
+++ b/chromium/ui/views/controls/button/image_button_factory.cc
@@ -5,6 +5,7 @@
#include <memory>
+#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
diff --git a/chromium/ui/views/controls/button/image_button_factory.h b/chromium/ui/views/controls/button/image_button_factory.h
index d09ae6de08a..38d7c70ad52 100644
--- a/chromium/ui/views/controls/button/image_button_factory.h
+++ b/chromium/ui/views/controls/button/image_button_factory.h
@@ -8,7 +8,6 @@
#include <memory>
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/color_palette.h"
#include "ui/views/views_export.h"
namespace gfx {
@@ -68,14 +67,8 @@ VIEWS_EXPORT void SetImageFromVectorIconWithColor(ImageButton* button,
int dip_size,
SkColor icon_color);
-// As above, but sets the toggled images for a toggled image button.
-VIEWS_EXPORT void SetToggledImageFromVectorIcon(
- ToggleImageButton* button,
- const gfx::VectorIcon& icon,
- int dip_size,
- SkColor related_text_color = gfx::kGoogleGrey900);
-
-// As above, but with a given icon color instead of deriving from a text color.
+// As above, but sets the toggled images for a toggled image button
+// with a given icon color instead of deriving from a text color.
VIEWS_EXPORT void SetToggledImageFromVectorIconWithColor(
ToggleImageButton* button,
const gfx::VectorIcon& icon,
diff --git a/chromium/ui/views/controls/button/label_button_border.cc b/chromium/ui/views/controls/button/label_button_border.cc
index beaac0fba8d..6536bbf8eed 100644
--- a/chromium/ui/views/controls/button/label_button_border.cc
+++ b/chromium/ui/views/controls/button/label_button_border.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/logging.h"
#include "cc/paint/paint_flags.h"
#include "ui/gfx/animation/animation.h"
#include "ui/gfx/canvas.h"
diff --git a/chromium/ui/views/controls/button/md_text_button.cc b/chromium/ui/views/controls/button/md_text_button.cc
index e7ab591a2d3..b9905fc6359 100644
--- a/chromium/ui/views/controls/button/md_text_button.cc
+++ b/chromium/ui/views/controls/button/md_text_button.cc
@@ -31,30 +31,12 @@
namespace views {
// static
-std::unique_ptr<LabelButton> MdTextButton::CreateSecondaryUiButton(
- ButtonListener* listener,
- const base::string16& text) {
- return MdTextButton::Create(listener, text, style::CONTEXT_BUTTON_MD);
-}
-
-// static
-std::unique_ptr<LabelButton> MdTextButton::CreateSecondaryUiBlueButton(
- ButtonListener* listener,
- const base::string16& text) {
- auto md_button =
- MdTextButton::Create(listener, text, style::CONTEXT_BUTTON_MD);
- md_button->SetProminent(true);
- return md_button;
-}
-
-// static
std::unique_ptr<MdTextButton> MdTextButton::Create(ButtonListener* listener,
const base::string16& text,
int button_context) {
auto button = base::WrapUnique<MdTextButton>(
new MdTextButton(listener, button_context));
button->SetText(text);
- button->SetFocusForPlatform();
return button;
}
@@ -172,8 +154,7 @@ PropertyEffects MdTextButton::UpdateStyleToIndicateDefaultStatus() {
}
MdTextButton::MdTextButton(ButtonListener* listener, int button_context)
- : LabelButton(listener, base::string16(), button_context),
- is_prominent_(false) {
+ : LabelButton(listener, base::string16(), button_context) {
SetInkDropMode(InkDropMode::ON);
set_has_ink_drop_action_on_click(true);
set_show_ink_drop_when_hot_tracked(true);
@@ -259,7 +240,7 @@ void MdTextButton::UpdateColors() {
ui::NativeTheme* theme = GetNativeTheme();
SkColor bg_color =
- theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground);
+ theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonColor);
if (bg_color_override_) {
bg_color = *bg_color_override_;
@@ -274,9 +255,7 @@ void MdTextButton::UpdateColors() {
}
if (state() == STATE_PRESSED) {
- SkColor shade =
- theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonPressedShade);
- bg_color = color_utils::GetResultingPaintColor(shade, bg_color);
+ bg_color = theme->GetSystemButtonPressedColor(bg_color);
}
SkColor stroke_color;
diff --git a/chromium/ui/views/controls/button/md_text_button.h b/chromium/ui/views/controls/button/md_text_button.h
index fcd66fcd425..760ab2a80ae 100644
--- a/chromium/ui/views/controls/button/md_text_button.h
+++ b/chromium/ui/views/controls/button/md_text_button.h
@@ -19,14 +19,6 @@ class VIEWS_EXPORT MdTextButton : public LabelButton {
public:
METADATA_HEADER(MdTextButton);
- // As above, but only creates an MdTextButton if MD is enabled in the
- // secondary UI (as opposed to just "top chrome"/"primary" UI).
- static std::unique_ptr<LabelButton> CreateSecondaryUiButton(
- ButtonListener* listener,
- const base::string16& text);
- static std::unique_ptr<LabelButton> CreateSecondaryUiBlueButton(
- ButtonListener* listener,
- const base::string16& text);
static std::unique_ptr<MdTextButton> Create(
ButtonListener* listener,
const base::string16& text,
@@ -69,12 +61,12 @@ class VIEWS_EXPORT MdTextButton : public LabelButton {
void UpdateColors();
// True if this button uses prominent styling (blue fill, etc.).
- bool is_prominent_;
+ bool is_prominent_ = false;
// When set, this provides the background color.
base::Optional<SkColor> bg_color_override_;
- float corner_radius_;
+ float corner_radius_ = 0.0f;
DISALLOW_COPY_AND_ASSIGN(MdTextButton);
};
diff --git a/chromium/ui/views/controls/button/radio_button.cc b/chromium/ui/views/controls/button/radio_button.cc
index e9d8c1df6ac..7c894909eb1 100644
--- a/chromium/ui/views/controls/button/radio_button.cc
+++ b/chromium/ui/views/controls/button/radio_button.cc
@@ -4,7 +4,7 @@
#include "ui/views/controls/button/radio_button.h"
-#include "base/logging.h"
+#include "base/check.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/resource/resource_bundle.h"
diff --git a/chromium/ui/views/controls/button/toggle_button.cc b/chromium/ui/views/controls/button/toggle_button.cc
index cc6aa145aec..bf88433d005 100644
--- a/chromium/ui/views/controls/button/toggle_button.cc
+++ b/chromium/ui/views/controls/button/toggle_button.cc
@@ -96,7 +96,7 @@ class ToggleButton::ThumbView : public InkDropHostView {
const SkColor thumb_on_color = thumb_on_color_.value_or(
theme->GetSystemColor(ui::NativeTheme::kColorId_ProminentButtonColor));
const SkColor thumb_off_color = thumb_off_color_.value_or(
- theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground));
+ theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonColor));
thumb_flags.setColor(
color_utils::AlphaBlend(thumb_on_color, thumb_off_color, color_ratio_));
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc
index 1137efc406d..b0364bcdb3e 100644
--- a/chromium/ui/views/controls/combobox/combobox.cc
+++ b/chromium/ui/views/controls/combobox/combobox.cc
@@ -9,12 +9,13 @@
#include <utility>
#include "base/bind.h"
-#include "base/logging.h"
+#include "base/check_op.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/ime/input_method.h"
+#include "ui/base/models/image_model.h"
#include "ui/base/models/menu_model.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
@@ -176,7 +177,9 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel {
int GetGroupIdAt(int index) const override { return -1; }
- bool GetIconAt(int index, gfx::Image* icon) const override { return false; }
+ ui::ImageModel GetIconAt(int index) const override {
+ return ui::ImageModel();
+ }
ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override {
return nullptr;
diff --git a/chromium/ui/views/controls/editable_combobox/editable_combobox.cc b/chromium/ui/views/controls/editable_combobox/editable_combobox.cc
index 8a0fef03ad6..5f76ed0db20 100644
--- a/chromium/ui/views/controls/editable_combobox/editable_combobox.cc
+++ b/chromium/ui/views/controls/editable_combobox/editable_combobox.cc
@@ -9,8 +9,8 @@
#include <vector>
#include "base/bind.h"
+#include "base/check_op.h"
#include "base/i18n/rtl.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
@@ -226,7 +226,9 @@ class EditableCombobox::EditableComboboxMenuModel
int GetGroupIdAt(int index) const override { return -1; }
- bool GetIconAt(int index, gfx::Image* icon) const override { return false; }
+ ui::ImageModel GetIconAt(int index) const override {
+ return ui::ImageModel();
+ }
ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override {
return nullptr;
@@ -425,6 +427,14 @@ void EditableCombobox::RequestFocus() {
textfield_->RequestFocus();
}
+bool EditableCombobox::GetNeedsNotificationWhenVisibleBoundsChange() const {
+ return true;
+}
+
+void EditableCombobox::OnVisibleBoundsChanged() {
+ CloseMenu();
+}
+
////////////////////////////////////////////////////////////////////////////////
// EditableCombobox, TextfieldController overrides:
diff --git a/chromium/ui/views/controls/editable_combobox/editable_combobox.h b/chromium/ui/views/controls/editable_combobox/editable_combobox.h
index 7228d52463a..c0f6b26fad8 100644
--- a/chromium/ui/views/controls/editable_combobox/editable_combobox.h
+++ b/chromium/ui/views/controls/editable_combobox/editable_combobox.h
@@ -124,6 +124,8 @@ class VIEWS_EXPORT EditableCombobox : public View,
void OnThemeChanged() override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
void RequestFocus() override;
+ bool GetNeedsNotificationWhenVisibleBoundsChange() const override;
+ void OnVisibleBoundsChanged() override;
// Overridden from TextfieldController:
void ContentsChanged(Textfield* sender,
diff --git a/chromium/ui/views/controls/highlight_path_generator.cc b/chromium/ui/views/controls/highlight_path_generator.cc
index 206f850c916..01920dd775d 100644
--- a/chromium/ui/views/controls/highlight_path_generator.cc
+++ b/chromium/ui/views/controls/highlight_path_generator.cc
@@ -7,18 +7,13 @@
#include <algorithm>
#include "third_party/skia/include/core/SkRect.h"
+#include "ui/gfx/rrect_f.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/view.h"
#include "ui/views/view_class_properties.h"
namespace views {
-HighlightPathGenerator::RoundRect::RoundRect() = default;
-
-HighlightPathGenerator::RoundRect::RoundRect(const gfx::RectF& bounds,
- float corner_radius)
- : bounds(bounds), corner_radius(corner_radius) {}
-
HighlightPathGenerator::HighlightPathGenerator()
: HighlightPathGenerator(gfx::Insets()) {}
@@ -35,8 +30,8 @@ void HighlightPathGenerator::Install(
}
// static
-base::Optional<HighlightPathGenerator::RoundRect>
-HighlightPathGenerator::GetRoundRectForView(const View* view) {
+base::Optional<gfx::RRectF> HighlightPathGenerator::GetRoundRectForView(
+ const View* view) {
HighlightPathGenerator* path_generator =
view->GetProperty(kHighlightPathGeneratorKey);
return path_generator ? path_generator->GetRoundRect(view) : base::nullopt;
@@ -44,28 +39,26 @@ HighlightPathGenerator::GetRoundRectForView(const View* view) {
SkPath HighlightPathGenerator::GetHighlightPath(const View* view) {
// A rounded rectangle must be supplied if using this default implementation.
- base::Optional<HighlightPathGenerator::RoundRect> round_rect =
- GetRoundRect(view);
+ base::Optional<gfx::RRectF> round_rect = GetRoundRect(view);
DCHECK(round_rect);
- return SkPath().addRRect(
- SkRRect{gfx::RRectF(round_rect->bounds, round_rect->corner_radius)});
+ return SkPath().addRRect(SkRRect{*round_rect});
}
-base::Optional<HighlightPathGenerator::RoundRect>
-HighlightPathGenerator::GetRoundRect(const gfx::RectF& rect) {
+base::Optional<gfx::RRectF> HighlightPathGenerator::GetRoundRect(
+ const gfx::RectF& rect) {
return base::nullopt;
}
-base::Optional<HighlightPathGenerator::RoundRect>
-HighlightPathGenerator::GetRoundRect(const View* view) {
+base::Optional<gfx::RRectF> HighlightPathGenerator::GetRoundRect(
+ const View* view) {
gfx::Rect bounds(view->GetLocalBounds());
bounds.Inset(insets_);
return GetRoundRect(gfx::RectF(bounds));
}
-base::Optional<HighlightPathGenerator::RoundRect>
-EmptyHighlightPathGenerator::GetRoundRect(const gfx::RectF& rect) {
- return HighlightPathGenerator::RoundRect();
+base::Optional<gfx::RRectF> EmptyHighlightPathGenerator::GetRoundRect(
+ const gfx::RectF& rect) {
+ return gfx::RRectF();
}
void InstallEmptyHighlightPathGenerator(View* view) {
@@ -73,9 +66,9 @@ void InstallEmptyHighlightPathGenerator(View* view) {
view, std::make_unique<EmptyHighlightPathGenerator>());
}
-base::Optional<HighlightPathGenerator::RoundRect>
-RectHighlightPathGenerator::GetRoundRect(const gfx::RectF& rect) {
- return HighlightPathGenerator::RoundRect{rect, /*corner_radius=*/0};
+base::Optional<gfx::RRectF> RectHighlightPathGenerator::GetRoundRect(
+ const gfx::RectF& rect) {
+ return gfx::RRectF(rect);
}
void InstallRectHighlightPathGenerator(View* view) {
@@ -87,13 +80,13 @@ CircleHighlightPathGenerator::CircleHighlightPathGenerator(
const gfx::Insets& insets)
: HighlightPathGenerator(insets) {}
-base::Optional<HighlightPathGenerator::RoundRect>
-CircleHighlightPathGenerator::GetRoundRect(const gfx::RectF& rect) {
+base::Optional<gfx::RRectF> CircleHighlightPathGenerator::GetRoundRect(
+ const gfx::RectF& rect) {
gfx::RectF bounds = rect;
const float corner_radius = std::min(bounds.width(), bounds.height()) / 2.f;
bounds.ClampToCenteredSize(
gfx::SizeF(corner_radius * 2.f, corner_radius * 2.f));
- return HighlightPathGenerator::RoundRect{bounds, corner_radius};
+ return gfx::RRectF(bounds, corner_radius);
}
void InstallCircleHighlightPathGenerator(View* view) {
@@ -124,11 +117,11 @@ FixedSizeCircleHighlightPathGenerator::FixedSizeCircleHighlightPathGenerator(
int radius)
: radius_(radius) {}
-base::Optional<HighlightPathGenerator::RoundRect>
-FixedSizeCircleHighlightPathGenerator::GetRoundRect(const gfx::RectF& rect) {
+base::Optional<gfx::RRectF> FixedSizeCircleHighlightPathGenerator::GetRoundRect(
+ const gfx::RectF& rect) {
gfx::RectF bounds = rect;
bounds.ClampToCenteredSize(gfx::SizeF(radius_ * 2, radius_ * 2));
- return HighlightPathGenerator::RoundRect{bounds, radius_};
+ return gfx::RRectF(bounds, radius_);
}
void InstallFixedSizeCircleHighlightPathGenerator(View* view, int radius) {
@@ -141,9 +134,9 @@ RoundRectHighlightPathGenerator::RoundRectHighlightPathGenerator(
int corner_radius)
: HighlightPathGenerator(insets), corner_radius_(corner_radius) {}
-base::Optional<HighlightPathGenerator::RoundRect>
-RoundRectHighlightPathGenerator::GetRoundRect(const gfx::RectF& rect) {
- return HighlightPathGenerator::RoundRect{rect, corner_radius_};
+base::Optional<gfx::RRectF> RoundRectHighlightPathGenerator::GetRoundRect(
+ const gfx::RectF& rect) {
+ return gfx::RRectF(rect, corner_radius_);
}
void InstallRoundRectHighlightPathGenerator(View* view,
diff --git a/chromium/ui/views/controls/highlight_path_generator.h b/chromium/ui/views/controls/highlight_path_generator.h
index 427c5271402..e64d0d48b1b 100644
--- a/chromium/ui/views/controls/highlight_path_generator.h
+++ b/chromium/ui/views/controls/highlight_path_generator.h
@@ -11,9 +11,12 @@
#include "third_party/skia/include/core/SkPath.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/views/views_export.h"
+namespace gfx {
+class RRectF;
+}
+
namespace views {
class View;
@@ -23,17 +26,6 @@ class View;
// effects.
class VIEWS_EXPORT HighlightPathGenerator {
public:
- struct VIEWS_EXPORT RoundRect {
- // TODO(http://crbug.com/1056490): Remove these constructors and have
- // callsites create a gfx::RoundedCornersF explicitly, or replace this
- // struct with a gfx::RRectF.
- RoundRect();
- RoundRect(const gfx::RectF& bounds, float corner_radius);
-
- gfx::RectF bounds;
- gfx::RoundedCornersF corner_radius;
- };
-
// TODO(http://crbug.com/1056490): Remove this constructor in favor of the one
// that takes |insets|.
HighlightPathGenerator();
@@ -45,18 +37,18 @@ class VIEWS_EXPORT HighlightPathGenerator {
static void Install(View* host,
std::unique_ptr<HighlightPathGenerator> generator);
- static base::Optional<RoundRect> GetRoundRectForView(const View* view);
+ static base::Optional<gfx::RRectF> GetRoundRectForView(const View* view);
// TODO(http://crbug.com/1056490): Deprecate |GetHighlightPath()| in favor of
// |GetRoundRect()|.
virtual SkPath GetHighlightPath(const View* view);
- // Optionally returns a RoundRect struct which contains data for drawing a
+ // Optionally returns a gfx::RRectF which contains data for drawing a
// highlight. Note that |rect| is in the coordinate system of the view.
// TODO(http://crbug.com/1056490): Once |GetHighlightPath()| is deprecated,
// make this a pure virtual function and make the return not optional.
- virtual base::Optional<RoundRect> GetRoundRect(const gfx::RectF& rect);
- base::Optional<RoundRect> GetRoundRect(const View* view);
+ virtual base::Optional<gfx::RRectF> GetRoundRect(const gfx::RectF& rect);
+ base::Optional<gfx::RRectF> GetRoundRect(const View* view);
private:
const gfx::Insets insets_;
@@ -74,7 +66,7 @@ class VIEWS_EXPORT EmptyHighlightPathGenerator : public HighlightPathGenerator {
delete;
// HighlightPathGenerator:
- base::Optional<RoundRect> GetRoundRect(const gfx::RectF& rect) override;
+ base::Optional<gfx::RRectF> GetRoundRect(const gfx::RectF& rect) override;
};
void VIEWS_EXPORT InstallEmptyHighlightPathGenerator(View* view);
@@ -89,7 +81,7 @@ class VIEWS_EXPORT RectHighlightPathGenerator : public HighlightPathGenerator {
delete;
// HighlightPathGenerator:
- base::Optional<RoundRect> GetRoundRect(const gfx::RectF& rect) override;
+ base::Optional<gfx::RRectF> GetRoundRect(const gfx::RectF& rect) override;
};
void VIEWS_EXPORT InstallRectHighlightPathGenerator(View* view);
@@ -105,7 +97,7 @@ class VIEWS_EXPORT CircleHighlightPathGenerator
delete;
// HighlightPathGenerator:
- base::Optional<RoundRect> GetRoundRect(const gfx::RectF& rect) override;
+ base::Optional<gfx::RRectF> GetRoundRect(const gfx::RectF& rect) override;
};
void VIEWS_EXPORT InstallCircleHighlightPathGenerator(View* view);
@@ -143,7 +135,7 @@ class VIEWS_EXPORT FixedSizeCircleHighlightPathGenerator
const FixedSizeCircleHighlightPathGenerator&) = delete;
// HighlightPathGenerator:
- base::Optional<RoundRect> GetRoundRect(const gfx::RectF& rect) override;
+ base::Optional<gfx::RRectF> GetRoundRect(const gfx::RectF& rect) override;
private:
const int radius_;
@@ -164,7 +156,7 @@ class VIEWS_EXPORT RoundRectHighlightPathGenerator
const RoundRectHighlightPathGenerator&) = delete;
// HighlightPathGenerator:
- base::Optional<RoundRect> GetRoundRect(const gfx::RectF& rect) override;
+ base::Optional<gfx::RRectF> GetRoundRect(const gfx::RectF& rect) override;
private:
const int corner_radius_;
diff --git a/chromium/ui/views/controls/image_view.cc b/chromium/ui/views/controls/image_view.cc
index e430b58317f..4ca005dbdc9 100644
--- a/chromium/ui/views/controls/image_view.cc
+++ b/chromium/ui/views/controls/image_view.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "cc/paint/paint_flags.h"
#include "skia/ext/image_operations.h"
#include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc
index c15c27ae75b..ad6af149e28 100644
--- a/chromium/ui/views/controls/label.cc
+++ b/chromium/ui/views/controls/label.cc
@@ -598,10 +598,6 @@ std::unique_ptr<gfx::RenderText> Label::CreateRenderText() const {
return render_text;
}
-void Label::PaintFocusRing(gfx::Canvas* canvas) const {
- // No focus ring by default.
-}
-
gfx::Rect Label::GetTextBounds() const {
MaybeBuildDisplayText();
@@ -645,8 +641,6 @@ void Label::OnBoundsChanged(const gfx::Rect& previous_bounds) {
void Label::OnPaint(gfx::Canvas* canvas) {
View::OnPaint(canvas);
PaintText(canvas);
- if (HasFocus())
- PaintFocusRing(canvas);
}
void Label::OnThemeChanged() {
@@ -895,9 +889,9 @@ bool Label::IsCommandIdChecked(int command_id) const {
bool Label::IsCommandIdEnabled(int command_id) const {
switch (command_id) {
- case IDS_APP_COPY:
+ case MenuCommands::kCopy:
return HasSelection() && !GetObscured();
- case IDS_APP_SELECT_ALL:
+ case MenuCommands::kSelectAll:
return GetRenderTextForSelectionController() && !GetText().empty();
}
return false;
@@ -905,10 +899,10 @@ bool Label::IsCommandIdEnabled(int command_id) const {
void Label::ExecuteCommand(int command_id, int event_flags) {
switch (command_id) {
- case IDS_APP_COPY:
+ case MenuCommands::kCopy:
CopyToClipboard();
break;
- case IDS_APP_SELECT_ALL:
+ case MenuCommands::kSelectAll:
SelectAll();
DCHECK(HasSelection());
UpdateSelectionClipboard();
@@ -921,11 +915,11 @@ void Label::ExecuteCommand(int command_id, int event_flags) {
bool Label::GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) const {
switch (command_id) {
- case IDS_APP_COPY:
+ case MenuCommands::kCopy:
*accelerator = ui::Accelerator(ui::VKEY_C, ui::EF_CONTROL_DOWN);
return true;
- case IDS_APP_SELECT_ALL:
+ case MenuCommands::kSelectAll:
*accelerator = ui::Accelerator(ui::VKEY_A, ui::EF_CONTROL_DOWN);
return true;
@@ -1101,8 +1095,8 @@ void Label::CopyToClipboard() {
}
void Label::BuildContextMenuContents() {
- context_menu_contents_.AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
- context_menu_contents_.AddItemWithStringId(IDS_APP_SELECT_ALL,
+ context_menu_contents_.AddItemWithStringId(MenuCommands::kCopy, IDS_APP_COPY);
+ context_menu_contents_.AddItemWithStringId(MenuCommands::kSelectAll,
IDS_APP_SELECT_ALL);
}
diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h
index 4cb533caa9c..dc690b22dc2 100644
--- a/chromium/ui/views/controls/label.h
+++ b/chromium/ui/views/controls/label.h
@@ -35,6 +35,12 @@ class VIEWS_EXPORT Label : public View,
public:
METADATA_HEADER(Label);
+ enum MenuCommands {
+ kCopy = 1,
+ kSelectAll,
+ kLastCommandId = kSelectAll,
+ };
+
// Helper to construct a Label that doesn't use the views typography spec.
// Using this causes Label to obtain colors from ui::NativeTheme and line
// spacing from gfx::FontList::GetHeight().
@@ -261,9 +267,6 @@ class VIEWS_EXPORT Label : public View,
// Create a single RenderText instance to actually be painted.
virtual std::unique_ptr<gfx::RenderText> CreateRenderText() const;
- // Draw a focus ring. The default implementation does nothing.
- virtual void PaintFocusRing(gfx::Canvas* canvas) const;
-
// Returns the preferred size and position of the text in local coordinates,
// which may exceed the local bounds of the label.
gfx::Rect GetTextBounds() const;
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index d3f01a185fe..763a169b27e 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -1384,38 +1384,38 @@ TEST_F(LabelSelectionTest, ContextMenuContents) {
label()->SetText(ASCIIToUTF16("Label context menu"));
label()->SizeToPreferredSize();
- // A non-selectable label would not show a context menu and both COPY and
- // SELECT_ALL context menu items should be disabled for it.
- EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_COPY));
- EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL));
+ // A non-selectable label should not show a context menu and both copy and
+ // select-all context menu items should be disabled for it.
+ EXPECT_FALSE(IsMenuCommandEnabled(Label::MenuCommands::kCopy));
+ EXPECT_FALSE(IsMenuCommandEnabled(Label::MenuCommands::kSelectAll));
- // For a selectable label with no selection, only SELECT_ALL should be
+ // For a selectable label with no selection, only kSelectAll should be
// enabled.
ASSERT_TRUE(label()->SetSelectable(true));
- EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_COPY));
- EXPECT_TRUE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL));
+ EXPECT_FALSE(IsMenuCommandEnabled(Label::MenuCommands::kCopy));
+ EXPECT_TRUE(IsMenuCommandEnabled(Label::MenuCommands::kSelectAll));
- // For a selectable label with a selection, both COPY and SELECT_ALL should be
- // enabled.
+ // For a selectable label with a selection, both copy and select-all should
+ // be enabled.
label()->SelectRange(gfx::Range(0, 4));
- EXPECT_TRUE(IsMenuCommandEnabled(IDS_APP_COPY));
- EXPECT_TRUE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL));
- // Ensure unsupported commands like PASTE are not enabled.
- EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_PASTE));
+ EXPECT_TRUE(IsMenuCommandEnabled(Label::MenuCommands::kCopy));
+ EXPECT_TRUE(IsMenuCommandEnabled(Label::MenuCommands::kSelectAll));
+ // Ensure unsupported commands are not enabled.
+ EXPECT_FALSE(IsMenuCommandEnabled(Label::MenuCommands::kLastCommandId + 1));
- // An obscured label would not show a context menu and both COPY and
- // SELECT_ALL should be disabled for it.
+ // An obscured label would not show a context menu and both copy and
+ // select-all should be disabled for it.
label()->SetObscured(true);
EXPECT_FALSE(label()->GetSelectable());
- EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_COPY));
- EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL));
+ EXPECT_FALSE(IsMenuCommandEnabled(Label::MenuCommands::kCopy));
+ EXPECT_FALSE(IsMenuCommandEnabled(Label::MenuCommands::kSelectAll));
label()->SetObscured(false);
- // For an empty label, both COPY and SELECT_ALL should be disabled.
+ // For an empty label, both copy and select-all should be disabled.
label()->SetText(base::string16());
ASSERT_TRUE(label()->SetSelectable(true));
- EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_COPY));
- EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL));
+ EXPECT_FALSE(IsMenuCommandEnabled(Label::MenuCommands::kCopy));
+ EXPECT_FALSE(IsMenuCommandEnabled(Label::MenuCommands::kSelectAll));
}
} // namespace views
diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc
index 5c292fc21de..29348fd8a9d 100644
--- a/chromium/ui/views/controls/link.cc
+++ b/chromium/ui/views/controls/link.cc
@@ -6,7 +6,7 @@
#include "build/build_config.h"
-#include "base/logging.h"
+#include "base/check.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
@@ -22,9 +22,6 @@
namespace views {
-// static
-constexpr gfx::Insets Link::kFocusBorderPadding;
-
Link::Link(const base::string16& title, int text_context, int text_style)
: Label(title, text_context, text_style) {
RecalculateFont();
@@ -39,12 +36,6 @@ Link::Link(const base::string16& title, int text_context, int text_style)
Link::~Link() = default;
-Link::FocusStyle Link::GetFocusStyle() const {
- // Use an underline to indicate focus unless the link is always drawn with an
- // underline.
- return underline_ ? FocusStyle::kRing : FocusStyle::kUnderline;
-}
-
SkColor Link::GetColor() const {
// TODO(tapted): Use style::GetColor().
const ui::NativeTheme* theme = GetNativeTheme();
@@ -60,25 +51,6 @@ SkColor Link::GetColor() const {
: ui::NativeTheme::kColorId_LinkEnabled);
}
-void Link::PaintFocusRing(gfx::Canvas* canvas) const {
- if (GetFocusStyle() == FocusStyle::kRing) {
- gfx::Rect focus_ring_bounds = GetTextBounds();
- focus_ring_bounds.Inset(-kFocusBorderPadding);
- focus_ring_bounds.Intersect(GetLocalBounds());
- canvas->DrawFocusRect(focus_ring_bounds);
- }
-}
-
-gfx::Insets Link::GetInsets() const {
- gfx::Insets insets = Label::GetInsets();
- if (GetFocusStyle() == FocusStyle::kRing &&
- GetFocusBehavior() != FocusBehavior::NEVER) {
- DCHECK(!GetText().empty());
- insets += kFocusBorderPadding;
- }
- return insets;
-}
-
gfx::NativeCursor Link::GetCursor(const ui::MouseEvent& event) {
if (!GetEnabled())
return gfx::kNullCursor;
@@ -214,18 +186,6 @@ bool Link::IsSelectionSupported() const {
return false;
}
-bool Link::GetUnderline() const {
- return underline_;
-}
-
-void Link::SetUnderline(bool underline) {
- if (underline_ == underline)
- return;
- underline_ = underline;
- RecalculateFont();
- OnPropertyChanged(&underline_, kPropertyEffectsPreferredSizeChanged);
-}
-
void Link::SetPressed(bool pressed) {
if (pressed_ != pressed) {
pressed_ = pressed;
@@ -236,12 +196,8 @@ void Link::SetPressed(bool pressed) {
}
void Link::RecalculateFont() {
- // Underline the link if it is enabled and |underline_| is true. Also
- // underline to indicate focus when that's the style.
const int style = font_list().GetFontStyle();
- const bool underline =
- underline_ || (HasFocus() && GetFocusStyle() == FocusStyle::kUnderline);
- const int intended_style = (GetEnabled() && underline)
+ const int intended_style = (GetEnabled() && HasFocus())
? (style | gfx::Font::UNDERLINE)
: (style & ~gfx::Font::UNDERLINE);
@@ -262,15 +218,9 @@ void Link::ConfigureFocus() {
}
}
-DEFINE_ENUM_CONVERTERS(Link::FocusStyle,
- {Link::FocusStyle::kUnderline,
- base::ASCIIToUTF16("UNDERLINE")},
- {Link::FocusStyle::kRing, base::ASCIIToUTF16("RING")})
BEGIN_METADATA(Link)
METADATA_PARENT_CLASS(Label)
ADD_READONLY_PROPERTY_METADATA(Link, SkColor, Color)
-ADD_READONLY_PROPERTY_METADATA(Link, Link::FocusStyle, FocusStyle)
-ADD_PROPERTY_METADATA(Link, bool, Underline)
END_METADATA()
} // namespace views
diff --git a/chromium/ui/views/controls/link.h b/chromium/ui/views/controls/link.h
index 684e05d7747..51b5a2341a5 100644
--- a/chromium/ui/views/controls/link.h
+++ b/chromium/ui/views/controls/link.h
@@ -35,24 +35,11 @@ class VIEWS_EXPORT Link : public Label {
using ClickedCallback =
base::RepeatingCallback<void(Link* source, int event_flags)>;
- // The padding for the focus ring border when rendering a focused Link with
- // FocusStyle::kRing.
- static constexpr gfx::Insets kFocusBorderPadding = gfx::Insets(1);
-
- // How the Link is styled when focused.
- enum class FocusStyle {
- kUnderline, // An underline style is added to the text only when focused.
- kRing, // A focus ring is drawn around the View.
- };
-
explicit Link(const base::string16& title,
int text_context = style::CONTEXT_LABEL,
int text_style = style::STYLE_LINK);
~Link() override;
- // Returns the current FocusStyle of this Link.
- FocusStyle GetFocusStyle() const;
-
// Allow providing callbacks that expect either zero or two args, since many
// callers don't care about the arguments and can avoid adapter functions this
// way.
@@ -69,8 +56,6 @@ class VIEWS_EXPORT Link : public Label {
SkColor GetColor() const;
// Label:
- void PaintFocusRing(gfx::Canvas* canvas) const override;
- gfx::Insets GetInsets() const override;
gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
bool CanProcessEventsWithinSubtree() const override;
bool OnMousePressed(const ui::MouseEvent& event) override;
@@ -89,13 +74,6 @@ class VIEWS_EXPORT Link : public Label {
void SetEnabledColor(SkColor color) override;
bool IsSelectionSupported() const override;
- bool GetUnderline() const;
- // TODO(estade): almost all the places that call this pass false. With
- // Harmony, false is already the default so those callsites can be removed.
- // TODO(tapted): Then remove all callsites when client code sets a correct
- // typography style and derives this from style::GetFont(STYLE_LINK).
- void SetUnderline(bool underline);
-
private:
void SetPressed(bool pressed);
@@ -105,9 +83,6 @@ class VIEWS_EXPORT Link : public Label {
ClickedCallback callback_;
- // Whether the link should be underlined when enabled.
- bool underline_ = false;
-
// Whether the link is currently pressed.
bool pressed_ = false;
diff --git a/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm b/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
index eaee6349d8e..f74acc5d65d 100644
--- a/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
+++ b/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
@@ -7,7 +7,8 @@
#import <Cocoa/Cocoa.h>
#include "base/bind.h"
-#include "base/logging.h"
+#include "base/check_op.h"
+#include "base/notreached.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/views/controls/menu/menu_item_view.h"
diff --git a/chromium/ui/views/controls/menu/menu_config.h b/chromium/ui/views/controls/menu/menu_config.h
index 9d0e8aafc84..c84d1377c94 100644
--- a/chromium/ui/views/controls/menu/menu_config.h
+++ b/chromium/ui/views/controls/menu/menu_config.h
@@ -43,9 +43,6 @@ struct VIEWS_EXPORT MenuConfig {
// Font list used by menus.
gfx::FontList font_list;
- // Color for the arrow to scroll bookmarks.
- SkColor arrow_color = SK_ColorBLACK;
-
// Menu border sizes. The vertical border size does not apply to menus with
// rounded corners - those menus always use the corner radius as the vertical
// border size.
diff --git a/chromium/ui/views/controls/menu/menu_config_win.cc b/chromium/ui/views/controls/menu/menu_config_win.cc
index 02ee472e0c4..154e8cf424f 100644
--- a/chromium/ui/views/controls/menu/menu_config_win.cc
+++ b/chromium/ui/views/controls/menu/menu_config_win.cc
@@ -9,7 +9,7 @@
#include <Vssym32.h>
#include <uxtheme.h>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/win/scoped_gdi_object.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/system_fonts_win.h"
@@ -20,7 +20,6 @@ using ui::NativeTheme;
namespace views {
void MenuConfig::Init() {
- arrow_color = color_utils::GetSysSkColor(COLOR_MENUTEXT);
font_list =
gfx::FontList(gfx::win::GetSystemFont(gfx::win::SystemFont::kMenu));
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index d8c09129ad9..d9938916a53 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -61,6 +61,10 @@
#include "ui/aura/window.h"
#endif
+#if defined(USE_OZONE)
+#include "ui/ozone/public/ozone_platform.h"
+#endif
+
using base::TimeDelta;
using ui::OSExchangeData;
@@ -100,6 +104,18 @@ bool AcceleratorShouldCancelMenu(const ui::Accelerator& accelerator) {
}
#endif
+bool ShouldIgnoreScreenBoundsForMenus() {
+#if defined(USE_OZONE)
+ // Wayland requires placing menus is screen coordinates. See comment in
+ // ozone_platform_wayland.cc.
+ return ui::OzonePlatform::GetInstance()
+ ->GetPlatformProperties()
+ .ignore_screen_bounds_for_menus;
+#else
+ return false;
+#endif
+}
+
// The amount of time the mouse should be down before a mouse release is
// considered intentional. This is to prevent spurious mouse releases from
// activating controls, especially when some UI element is revealed under the
@@ -776,19 +792,15 @@ void MenuController::OnMouseReleased(SubmenuView* source,
return;
}
}
+ const int command = part.menu->GetCommand();
if (part.menu->GetDelegate()->ShouldExecuteCommandWithoutClosingMenu(
- part.menu->GetCommand(), event)) {
- part.menu->GetDelegate()->ExecuteCommand(part.menu->GetCommand(),
- event.flags());
+ command, event)) {
+ part.menu->GetDelegate()->ExecuteCommand(command, event.flags());
return;
}
if (!part.menu->NonIconChildViewsCount() &&
part.menu->GetDelegate()->IsTriggerableEvent(part.menu, event)) {
- base::TimeDelta shown_time = base::TimeTicks::Now() - menu_start_time_;
- if (!state_.context_menu || !View::ShouldShowContextMenuOnMousePress() ||
- shown_time > menu_selection_hold_time) {
- Accept(part.menu, event.flags());
- }
+ Accept(part.menu, event.flags());
return;
}
} else if (part.type == MenuPart::MENU_ITEM) {
@@ -2226,7 +2238,7 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
menu_bounds.set_x(create_on_right ? right_of_parent : left_of_parent);
// Everything after this check requires monitor bounds to be non-empty.
- if (monitor_bounds.IsEmpty())
+ if (ShouldIgnoreScreenBoundsForMenus() || monitor_bounds.IsEmpty())
return menu_bounds;
// Menu does not actually fit where it was placed, move it to the other side
@@ -2258,7 +2270,8 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
anchor_bounds.x() + (anchor_bounds.width() - menu_bounds.width()) / 2;
menu_bounds.set_x(horizontally_centered);
menu_bounds.set_y(above_anchor - kTouchYPadding);
- if (menu_bounds.y() < monitor_bounds.y())
+ if (!ShouldIgnoreScreenBoundsForMenus() &&
+ menu_bounds.y() < monitor_bounds.y())
menu_bounds.set_y(anchor_bounds.y() + kTouchYPadding);
}
@@ -2268,7 +2281,7 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
}
// Everything beyond this point requires monitor bounds to be non-empty.
- if (monitor_bounds.IsEmpty())
+ if (ShouldIgnoreScreenBoundsForMenus() || monitor_bounds.IsEmpty())
return menu_bounds;
// If the menu position is below or above the anchor bounds, force it to fit
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
index 14d45fb9dcf..3176d01e445 100644
--- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop_current.h"
#include "base/single_thread_task_runner.h"
@@ -51,18 +50,34 @@
#if defined(USE_X11)
#include "ui/events/test/events_test_utils_x11.h"
-#include "ui/gfx/x/x11.h"
+#include "ui/gfx/x/x11.h" // nogncheck
#endif
#if defined(OS_CHROMEOS)
#include "ui/base/ui_base_features.h"
#endif
+#if defined(USE_OZONE)
+#include "ui/ozone/public/ozone_platform.h"
+#endif
+
namespace views {
namespace test {
namespace {
+bool ShouldIgnoreScreenBoundsForMenus() {
+#if defined(USE_OZONE)
+ // Wayland requires placing menus is screen coordinates. See comment in
+ // ozone_platform_wayland.cc.
+ return ui::OzonePlatform::GetInstance()
+ ->GetPlatformProperties()
+ .ignore_screen_bounds_for_menus;
+#else
+ return false;
+#endif
+}
+
// Test implementation of MenuControllerDelegate that only reports the values
// called of OnMenuClosed.
class TestMenuControllerDelegate : public internal::MenuControllerDelegate {
@@ -1518,7 +1533,7 @@ TEST_F(MenuControllerTest, NoTouchCloseWhenSendingGesturesToOwner) {
location.Offset(1, 1);
ui::TouchEvent touch_event(
ui::ET_TOUCH_PRESSED, location, ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
+ ui::PointerDetails(ui::EventPointerType::kTouch, 0));
controller->OnTouchEvent(sub_menu, &touch_event);
// Menu should still be visible.
@@ -1592,9 +1607,8 @@ TEST_F(MenuControllerTest, AsynchronousTouchEventRepostEvent) {
sub_menu->ShowAt(owner(), item->bounds(), false);
gfx::Point location(sub_menu->bounds().bottom_right());
location.Offset(1, 1);
- ui::TouchEvent event(
- ui::ET_TOUCH_PRESSED, location, ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
+ ui::TouchEvent event(ui::ET_TOUCH_PRESSED, location, ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::kTouch, 0));
controller->OnTouchEvent(sub_menu, &event);
views::test::WaitForMenuClosureAnimation();
@@ -1712,6 +1726,8 @@ TEST_F(MenuControllerTest, ArrowKeysAtEnds) {
TEST_F(MenuControllerTest, CalculateMenuBoundsBestFitTest) {
MenuBoundsOptions options;
gfx::Rect expected;
+ const bool ignore_screen_bounds_for_menus =
+ ShouldIgnoreScreenBoundsForMenus();
// Fits in all locations -> placed below.
options.anchor_bounds =
@@ -1730,9 +1746,13 @@ TEST_F(MenuControllerTest, CalculateMenuBoundsBestFitTest) {
options.monitor_bounds =
gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
options.anchor_bounds.bottom());
- expected = gfx::Rect(options.anchor_bounds.x(),
- options.anchor_bounds.y() - options.menu_size.height(),
- options.menu_size.width(), options.menu_size.height());
+ if (ignore_screen_bounds_for_menus) {
+ expected = gfx::Rect(options.anchor_bounds.origin(), options.menu_size);
+ } else {
+ expected = gfx::Rect(options.anchor_bounds.x(),
+ options.anchor_bounds.y() - options.menu_size.height(),
+ options.menu_size.width(), options.menu_size.height());
+ }
EXPECT_EQ(expected, CalculateMenuBounds(options));
// Fits on both sides, prefer right -> placed right.
@@ -1741,10 +1761,15 @@ TEST_F(MenuControllerTest, CalculateMenuBoundsBestFitTest) {
options.monitor_bounds =
gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
options.menu_size.height());
- expected =
- gfx::Rect(options.anchor_bounds.right(),
- options.monitor_bounds.bottom() - options.menu_size.height(),
- options.menu_size.width(), options.menu_size.height());
+ if (ignore_screen_bounds_for_menus) {
+ expected = gfx::Rect(options.anchor_bounds.origin(), options.menu_size);
+ } else {
+ expected =
+ gfx::Rect(options.anchor_bounds.right(),
+ options.monitor_bounds.bottom() - options.menu_size.height(),
+ options.menu_size.width(), options.menu_size.height());
+ }
+
EXPECT_EQ(expected, CalculateMenuBounds(options));
// Fits only on left -> placed left.
@@ -1752,10 +1777,14 @@ TEST_F(MenuControllerTest, CalculateMenuBoundsBestFitTest) {
options.menu_size.height() / 2, 0, 0);
options.monitor_bounds = gfx::Rect(0, 0, options.anchor_bounds.right(),
options.menu_size.height());
- expected =
- gfx::Rect(options.anchor_bounds.x() - options.menu_size.width(),
- options.monitor_bounds.bottom() - options.menu_size.height(),
- options.menu_size.width(), options.menu_size.height());
+ if (ignore_screen_bounds_for_menus) {
+ expected = gfx::Rect(options.anchor_bounds.origin(), options.menu_size);
+ } else {
+ expected =
+ gfx::Rect(options.anchor_bounds.x() - options.menu_size.width(),
+ options.monitor_bounds.bottom() - options.menu_size.height(),
+ options.menu_size.width(), options.menu_size.height());
+ }
EXPECT_EQ(expected, CalculateMenuBounds(options));
// Fits on both sides, prefer left -> placed left.
@@ -1765,10 +1794,17 @@ TEST_F(MenuControllerTest, CalculateMenuBoundsBestFitTest) {
options.monitor_bounds =
gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
options.menu_size.height());
- expected =
- gfx::Rect(options.anchor_bounds.x() - options.menu_size.width(),
- options.monitor_bounds.bottom() - options.menu_size.height(),
- options.menu_size.width(), options.menu_size.height());
+ if (ignore_screen_bounds_for_menus) {
+ expected =
+ gfx::Rect({options.anchor_bounds.right() - options.menu_size.width(),
+ options.anchor_bounds.origin().y()},
+ options.menu_size);
+ } else {
+ expected =
+ gfx::Rect(options.anchor_bounds.x() - options.menu_size.width(),
+ options.monitor_bounds.bottom() - options.menu_size.height(),
+ options.menu_size.width(), options.menu_size.height());
+ }
EXPECT_EQ(expected, CalculateMenuBounds(options));
// Fits only on right -> placed right.
@@ -1776,10 +1812,17 @@ TEST_F(MenuControllerTest, CalculateMenuBoundsBestFitTest) {
options.monitor_bounds =
gfx::Rect(0, 0, options.anchor_bounds.right() + options.menu_size.width(),
options.menu_size.height());
- expected =
- gfx::Rect(options.anchor_bounds.right(),
- options.monitor_bounds.bottom() - options.menu_size.height(),
- options.menu_size.width(), options.menu_size.height());
+ if (ignore_screen_bounds_for_menus) {
+ expected =
+ gfx::Rect({options.anchor_bounds.right() - options.menu_size.width(),
+ options.anchor_bounds.origin().y()},
+ options.menu_size);
+ } else {
+ expected =
+ gfx::Rect(options.anchor_bounds.right(),
+ options.monitor_bounds.bottom() - options.menu_size.height(),
+ options.menu_size.width(), options.menu_size.height());
+ }
EXPECT_EQ(expected, CalculateMenuBounds(options));
}
@@ -1816,11 +1859,20 @@ TEST_F(MenuControllerTest, CalculateMenuBoundsAnchorTest) {
// Menu does not fit above -> placed below.
options.anchor_bounds = gfx::Rect(options.menu_size.height() / 2,
options.menu_size.width(), 0, 0);
- expected = gfx::Rect(
- options.anchor_bounds.x() +
- (options.anchor_bounds.width() - options.menu_size.width()) / 2,
- options.anchor_bounds.y() + kTouchYPadding, options.menu_size.width(),
- options.menu_size.height());
+ if (ShouldIgnoreScreenBoundsForMenus()) {
+ expected = gfx::Rect(
+ options.anchor_bounds.x() +
+ (options.anchor_bounds.width() - options.menu_size.width()) / 2,
+ options.anchor_bounds.y() - options.anchor_bounds.bottom() -
+ kTouchYPadding,
+ options.menu_size.width(), options.menu_size.height());
+ } else {
+ expected = gfx::Rect(
+ options.anchor_bounds.x() +
+ (options.anchor_bounds.width() - options.menu_size.width()) / 2,
+ options.anchor_bounds.y() + kTouchYPadding, options.menu_size.width(),
+ options.menu_size.height());
+ }
EXPECT_EQ(expected, CalculateMenuBounds(options));
}
@@ -1951,6 +2003,11 @@ TEST_P(MenuControllerTest, TestSubmenuFitsOnScreen) {
// squished or move above the anchor when it grows vertically and horizontally
// beyond the monitor bounds.
TEST_F(MenuControllerTest, GrowingMenuMovesLaterallyNotVertically) {
+ // We can't know the position of windows in Wayland. Thus, this case is not
+ // valid for Wayland.
+ if (ShouldIgnoreScreenBoundsForMenus())
+ return;
+
MenuBoundsOptions options;
options.monitor_bounds = gfx::Rect(0, 0, 100, 100);
// The anchor should be near the bottom right side of the screen.
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index 232a7de1b54..0b9230bda55 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -7,7 +7,8 @@
#include <utility>
#include "base/auto_reset.h"
-#include "base/logging.h"
+#include "base/check_op.h"
+#include "base/notreached.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "ui/aura/window_observer.h"
diff --git a/chromium/ui/views/controls/menu/menu_host_root_view.cc b/chromium/ui/views/controls/menu/menu_host_root_view.cc
index bbb1290858d..890b56554ef 100644
--- a/chromium/ui/views/controls/menu/menu_host_root_view.cc
+++ b/chromium/ui/views/controls/menu/menu_host_root_view.cc
@@ -94,4 +94,7 @@ MenuController* MenuHostRootView::GetMenuControllerForInputEvents() {
: nullptr;
}
+BEGIN_METADATA(MenuHostRootView)
+METADATA_PARENT_CLASS(RootView)
+END_METADATA()
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_host_root_view.h b/chromium/ui/views/controls/menu/menu_host_root_view.h
index e37dd792677..85548317aa2 100644
--- a/chromium/ui/views/controls/menu/menu_host_root_view.h
+++ b/chromium/ui/views/controls/menu/menu_host_root_view.h
@@ -21,6 +21,8 @@ class SubmenuView;
// such that when MenuHostRootView is deleted it doesn't delete the menu items.
class MenuHostRootView : public internal::RootView {
public:
+ METADATA_HEADER(MenuHostRootView);
+
MenuHostRootView(Widget* widget, SubmenuView* submenu);
void ClearSubmenu() { submenu_ = nullptr; }
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 6f45e5ac5d1..d00618f37c3 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -923,7 +923,7 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
const gfx::VectorIcon& radio_icon =
toggled ? kMenuRadioSelectedIcon : kMenuRadioEmptyIcon;
const SkColor radio_icon_color = GetNativeTheme()->GetSystemColor(
- toggled ? ui::NativeTheme::kColorId_ButtonEnabledColor
+ toggled ? ui::NativeTheme::kColorId_ButtonCheckedColor
: ui::NativeTheme::kColorId_ButtonUncheckedColor);
radio_check_image_view_->SetImage(
gfx::CreateVectorIcon(radio_icon, kMenuCheckSize, radio_icon_color));
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index 88a868cf6f9..79af9195b11 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -6,7 +6,8 @@
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
+#include "base/notreached.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/paint_vector_icon.h"
@@ -104,15 +105,17 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model,
model->GetSeparatorTypeAt(model_index));
}
- gfx::Image icon;
- model->GetIconAt(model_index, &icon);
+ ui::ImageModel icon = model->GetIconAt(model_index);
+ ui::ImageModel minor_icon = model->GetMinorIconAt(model_index);
return menu->AddMenuItemAt(
menu_index, item_id, model->GetLabelAt(model_index),
model->GetMinorTextAt(model_index),
- ui::ThemedVectorIcon(model->GetMinorIconAt(model_index)),
- icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(),
- icon.IsEmpty() ? ui::ThemedVectorIcon(model->GetVectorIconAt(model_index))
- : ui::ThemedVectorIcon(),
+ minor_icon.IsVectorIcon()
+ ? ui::ThemedVectorIcon(minor_icon.GetVectorIcon())
+ : ui::ThemedVectorIcon(),
+ icon.IsImage() ? *icon.GetImage().ToImageSkia() : gfx::ImageSkia(),
+ icon.IsVectorIcon() ? ui::ThemedVectorIcon(icon.GetVectorIcon())
+ : ui::ThemedVectorIcon(),
*type, ui::NORMAL_SEPARATOR);
}
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
index 7f9bb3bd850..6241a9d7916 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -66,7 +66,9 @@ class MenuModelBase : public ui::MenuModel {
int GetGroupIdAt(int index) const override { return 0; }
- bool GetIconAt(int index, gfx::Image* icon) const override { return false; }
+ ui::ImageModel GetIconAt(int index) const override {
+ return ui::ImageModel();
+ }
ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override {
return nullptr;
diff --git a/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm b/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
index 321308675f6..4f70db3ec4b 100644
--- a/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -299,7 +299,8 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
DISALLOW_COPY_AND_ASSIGN(MenuRunnerCocoaTest);
};
-TEST_P(MenuRunnerCocoaTest, RunMenuAndCancel) {
+// Crashes frequently, https://crbug.com/1073069
+TEST_P(MenuRunnerCocoaTest, DISABLED_RunMenuAndCancel) {
base::TimeTicks min_time = ui::EventTimeForNow();
RunMenu(base::BindOnce(&MenuRunnerCocoaTest::MenuCancelCallback,
diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
index 7a9d15cb206..3ba6950690e 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -22,6 +22,7 @@
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/round_rect_painter.h"
+#include "ui/views/view.h"
#include "ui/views/view_class_properties.h"
using ui::NativeTheme;
@@ -51,6 +52,12 @@ class MenuScrollButton : public View {
pref_height_);
}
+ void OnThemeChanged() override {
+ View::OnThemeChanged();
+ arrow_color_ = GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor);
+ }
+
bool CanDrop(const OSExchangeData& data) override {
DCHECK(host_->GetMenuItem()->GetMenuController());
return true; // Always return true so that drop events are targeted to us.
@@ -108,7 +115,7 @@ class MenuScrollButton : public View {
cc::PaintFlags flags;
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setAntiAlias(true);
- flags.setColor(config.arrow_color);
+ flags.setColor(arrow_color_);
canvas->DrawPath(path, flags);
}
@@ -122,6 +129,9 @@ class MenuScrollButton : public View {
// Preferred height.
int pref_height_;
+ // Color for the arrow to scroll.
+ SkColor arrow_color_;
+
DISALLOW_COPY_AND_ASSIGN(MenuScrollButton);
};
diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.h b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
index 5f87cfa5a9b..e0dc860b3a2 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
@@ -31,8 +31,6 @@ class MenuScrollViewContainer : public View {
// External function to check if the bubble border is used.
bool HasBubbleBorder() const;
- void SetFootnoteView(View* view);
-
// View overrides.
gfx::Size CalculatePreferredSize() const override;
void OnPaintBackground(gfx::Canvas* canvas) override;
diff --git a/chromium/ui/views/controls/menu/native_menu_win.cc b/chromium/ui/views/controls/menu/native_menu_win.cc
index 54de8fb75e9..042ecddda20 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.cc
+++ b/chromium/ui/views/controls/menu/native_menu_win.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/strings/string_util.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chromium/ui/views/controls/message_box_view.cc b/chromium/ui/views/controls/message_box_view.cc
index 0d522a2ed58..bbdfc07370e 100644
--- a/chromium/ui/views/controls/message_box_view.cc
+++ b/chromium/ui/views/controls/message_box_view.cc
@@ -231,7 +231,7 @@ void MessageBoxView::ResetLayoutManager() {
constexpr int kMessageViewColumnSetId = 0;
ColumnSet* column_set = layout->AddColumnSet(kMessageViewColumnSetId);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::FIXED, message_width_, 0);
+ GridLayout::ColumnSize::kFixed, message_width_, 0);
const LayoutProvider* provider = LayoutProvider::Get();
@@ -242,7 +242,7 @@ void MessageBoxView::ResetLayoutManager() {
column_set = layout->AddColumnSet(kExtraViewColumnSetId);
column_set->AddPaddingColumn(0, horizontal_insets.left());
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(0, horizontal_insets.right());
}
diff --git a/chromium/ui/views/controls/native/native_view_host.cc b/chromium/ui/views/controls/native/native_view_host.cc
index b29553ae8f7..4779e4f07d9 100644
--- a/chromium/ui/views/controls/native/native_view_host.cc
+++ b/chromium/ui/views/controls/native/native_view_host.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.cc b/chromium/ui/views/controls/native/native_view_host_aura.cc
index 26a4b5a55fa..2223f6e3b28 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/optional.h"
#include "build/build_config.h"
#include "ui/aura/client/aura_constants.h"
diff --git a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
index 973caf4a0aa..d1d03765bf3 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
@@ -15,7 +15,7 @@
#include "ui/aura/window_targeter.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/cursor/cursor.h"
-#include "ui/base/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/events/event_utils.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/controls/native/native_view_host_test_base.h"
diff --git a/chromium/ui/views/controls/progress_bar.cc b/chromium/ui/views/controls/progress_bar.cc
index 3801b433a4e..45e2f590995 100644
--- a/chromium/ui/views/controls/progress_bar.cc
+++ b/chromium/ui/views/controls/progress_bar.cc
@@ -9,7 +9,8 @@
#include <memory>
#include <string>
-#include "base/logging.h"
+#include "base/check_op.h"
+#include "base/i18n/number_formatting.h"
#include "base/macros.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkPath.h"
@@ -21,6 +22,7 @@
#include "ui/gfx/color_utils.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/metadata/metadata_impl_macros.h"
+#include "ui/views/widget/widget.h"
namespace views {
@@ -42,6 +44,10 @@ void AddPossiblyRoundRectToPath(const gfx::Rect& rectangle,
}
}
+int RoundToPercent(double fractional_value) {
+ return static_cast<int>(fractional_value * 100);
+}
+
} // namespace
ProgressBar::ProgressBar(int preferred_height, bool allow_round_corner)
@@ -54,6 +60,10 @@ ProgressBar::~ProgressBar() = default;
void ProgressBar::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kProgressIndicator;
+ if (IsIndeterminate())
+ node_data->RemoveStringAttribute(ax::mojom::StringAttribute::kValue);
+ else
+ node_data->SetValue(base::FormatPercent(RoundToPercent(current_value_)));
}
gfx::Size ProgressBar::CalculatePreferredSize() const {
@@ -64,6 +74,14 @@ gfx::Size ProgressBar::CalculatePreferredSize() const {
return pref_size;
}
+void ProgressBar::VisibilityChanged(View* starting_from, bool is_visible) {
+ MaybeNotifyAccessibilityValueChanged();
+}
+
+void ProgressBar::AddedToWidget() {
+ MaybeNotifyAccessibilityValueChanged();
+}
+
void ProgressBar::OnPaint(gfx::Canvas* canvas) {
if (IsIndeterminate())
return OnPaintIndeterminate(canvas);
@@ -117,6 +135,8 @@ void ProgressBar::SetValue(double value) {
indeterminate_bar_animation_.reset();
OnPropertyChanged(&current_value_, kPropertyEffectsPaint);
}
+
+ MaybeNotifyAccessibilityValueChanged();
}
SkColor ProgressBar::GetForegroundColor() const {
@@ -227,6 +247,15 @@ void ProgressBar::OnPaintIndeterminate(gfx::Canvas* canvas) {
canvas->DrawPath(slice_path, slice_flags);
}
+void ProgressBar::MaybeNotifyAccessibilityValueChanged() {
+ if (!GetWidget() || !GetWidget()->IsVisible() ||
+ RoundToPercent(current_value_) == last_announced_percentage_) {
+ return;
+ }
+ last_announced_percentage_ = RoundToPercent(current_value_);
+ NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
+}
+
BEGIN_METADATA(ProgressBar)
METADATA_PARENT_CLASS(View)
ADD_PROPERTY_METADATA(ProgressBar, SkColor, ForegroundColor)
diff --git a/chromium/ui/views/controls/progress_bar.h b/chromium/ui/views/controls/progress_bar.h
index 563c15cd7cd..b57af1f1355 100644
--- a/chromium/ui/views/controls/progress_bar.h
+++ b/chromium/ui/views/controls/progress_bar.h
@@ -30,9 +30,11 @@ class VIEWS_EXPORT ProgressBar : public View, public gfx::AnimationDelegate {
bool allow_round_corner = true);
~ProgressBar() override;
- // Overridden from View:
+ // View:
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
gfx::Size CalculatePreferredSize() const override;
+ void VisibilityChanged(View* starting_from, bool is_visible) override;
+ void AddedToWidget() override;
void OnPaint(gfx::Canvas* canvas) override;
double GetValue() const;
@@ -59,6 +61,9 @@ class VIEWS_EXPORT ProgressBar : public View, public gfx::AnimationDelegate {
bool IsIndeterminate();
void OnPaintIndeterminate(gfx::Canvas* canvas);
+ // Fire an accessibility event if visible and the progress has changed.
+ void MaybeNotifyAccessibilityValueChanged();
+
// Current progress to display, should be in the range 0.0 to 1.0.
double current_value_ = 0.0;
@@ -72,6 +77,8 @@ class VIEWS_EXPORT ProgressBar : public View, public gfx::AnimationDelegate {
std::unique_ptr<gfx::LinearAnimation> indeterminate_bar_animation_;
+ int last_announced_percentage_ = -1;
+
DISALLOW_COPY_AND_ASSIGN(ProgressBar);
};
diff --git a/chromium/ui/views/controls/progress_bar_unittest.cc b/chromium/ui/views/controls/progress_bar_unittest.cc
index 280637e455d..e633e419022 100644
--- a/chromium/ui/views/controls/progress_bar_unittest.cc
+++ b/chromium/ui/views/controls/progress_bar_unittest.cc
@@ -8,38 +8,122 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/events/test/event_generator.h"
#include "ui/gfx/color_utils.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/accessibility/ax_event_manager.h"
+#include "ui/views/accessibility/ax_event_observer.h"
#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget_utils.h"
namespace views {
-using ProgressBarTest = ViewsTestBase;
+namespace {
-TEST_F(ProgressBarTest, Accessibility) {
- ProgressBar bar;
- bar.SetValue(0.62);
+class TestAXEventObserver : public AXEventObserver {
+ public:
+ TestAXEventObserver() { AXEventManager::Get()->AddObserver(this); }
+
+ ~TestAXEventObserver() override {
+ AXEventManager::Get()->RemoveObserver(this);
+ }
+
+ TestAXEventObserver(const TestAXEventObserver&) = delete;
+ TestAXEventObserver& operator=(const TestAXEventObserver&) = delete;
+
+ int value_changed_count() const { return value_changed_count_; }
+
+ // AXEventObserver:
+ void OnViewEvent(View* view, ax::mojom::Event event_type) override {
+ if (event_type == ax::mojom::Event::kValueChanged)
+ value_changed_count_++;
+ }
+
+ private:
+ int value_changed_count_ = 0;
+};
+
+} // namespace
+
+class ProgressBarTest : public ViewsTestBase {
+ protected:
+ // ViewsTestBase:
+ void SetUp() override {
+ ViewsTestBase::SetUp();
+ bar_ = new ProgressBar;
+
+ widget_ = CreateTestWidget();
+ widget_->SetContentsView(bar_);
+ widget_->Show();
+
+ event_generator_ = std::make_unique<ui::test::EventGenerator>(
+ GetRootWindow(widget_.get()));
+ }
+
+ void TearDown() override {
+ widget_.reset();
+ ViewsTestBase::TearDown();
+ }
+
+ ProgressBar* bar_;
+ std::unique_ptr<Widget> widget_;
+
+ std::unique_ptr<ui::test::EventGenerator> event_generator_;
+};
+
+TEST_F(ProgressBarTest, AccessibleNodeData) {
+ bar_->SetValue(0.626);
ui::AXNodeData node_data;
- bar.GetAccessibleNodeData(&node_data);
+ bar_->GetAccessibleNodeData(&node_data);
EXPECT_EQ(ax::mojom::Role::kProgressIndicator, node_data.role);
EXPECT_EQ(base::string16(),
node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+ EXPECT_EQ(std::string("62%"),
+ node_data.GetStringAttribute(ax::mojom::StringAttribute::kValue));
EXPECT_FALSE(
node_data.HasIntAttribute(ax::mojom::IntAttribute::kRestriction));
}
+// Verifies the correct a11y events are raised for an accessible progress bar.
+TEST_F(ProgressBarTest, AccessibilityEvents) {
+ TestAXEventObserver observer;
+ EXPECT_EQ(0, observer.value_changed_count());
+
+ bar_->SetValue(0.50);
+ EXPECT_EQ(1, observer.value_changed_count());
+
+ bar_->SetValue(0.63);
+ EXPECT_EQ(2, observer.value_changed_count());
+
+ bar_->SetValue(0.636);
+ EXPECT_EQ(2, observer.value_changed_count());
+
+ bar_->SetValue(0.642);
+ EXPECT_EQ(3, observer.value_changed_count());
+
+ widget_->Hide();
+ widget_->Show();
+ EXPECT_EQ(3, observer.value_changed_count());
+
+ widget_->Hide();
+ bar_->SetValue(0.8);
+ EXPECT_EQ(3, observer.value_changed_count());
+
+ widget_->Show();
+ EXPECT_EQ(4, observer.value_changed_count());
+}
+
// Test that default colors can be overridden. Used by Chromecast.
TEST_F(ProgressBarTest, OverrideDefaultColors) {
- ProgressBar bar;
- EXPECT_NE(SK_ColorRED, bar.GetForegroundColor());
- EXPECT_NE(SK_ColorGREEN, bar.GetBackgroundColor());
- EXPECT_NE(bar.GetForegroundColor(), bar.GetBackgroundColor());
-
- bar.SetForegroundColor(SK_ColorRED);
- bar.SetBackgroundColor(SK_ColorGREEN);
- EXPECT_EQ(SK_ColorRED, bar.GetForegroundColor());
- EXPECT_EQ(SK_ColorGREEN, bar.GetBackgroundColor());
+ EXPECT_NE(SK_ColorRED, bar_->GetForegroundColor());
+ EXPECT_NE(SK_ColorGREEN, bar_->GetBackgroundColor());
+ EXPECT_NE(bar_->GetForegroundColor(), bar_->GetBackgroundColor());
+
+ bar_->SetForegroundColor(SK_ColorRED);
+ bar_->SetBackgroundColor(SK_ColorGREEN);
+ EXPECT_EQ(SK_ColorRED, bar_->GetForegroundColor());
+ EXPECT_EQ(SK_ColorGREEN, bar_->GetBackgroundColor());
}
} // namespace views
diff --git a/chromium/ui/views/controls/resize_area.cc b/chromium/ui/views/controls/resize_area.cc
index a565893fdce..a83a939e050 100644
--- a/chromium/ui/views/controls/resize_area.cc
+++ b/chromium/ui/views/controls/resize_area.cc
@@ -4,7 +4,6 @@
#include "ui/views/controls/resize_area.h"
-#include "base/logging.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/cursor/cursor.h"
diff --git a/chromium/ui/views/controls/scroll_view.cc b/chromium/ui/views/controls/scroll_view.cc
index 89e642951ea..8f1244d79c2 100644
--- a/chromium/ui/views/controls/scroll_view.cc
+++ b/chromium/ui/views/controls/scroll_view.cc
@@ -7,8 +7,8 @@
#include <algorithm>
#include "base/bind.h"
+#include "base/check_op.h"
#include "base/feature_list.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/numerics/ranges.h"
#include "build/build_config.h"
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index 3d08c952fae..0359bc89ed3 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -799,6 +799,56 @@ TEST_F(ScrollViewTest, ScrollChildToVisibleOnFocus) {
EXPECT_EQ(415 - viewport_height, offset.y());
}
+// Verifies that ScrollView scrolls into view when its contents root is focused.
+TEST_F(ScrollViewTest, ScrollViewToVisibleOnContentsRootFocus) {
+ ScrollViewTestApi outer_test_api(scroll_view_.get());
+ auto outer_contents = std::make_unique<CustomView>();
+ outer_contents->SetPreferredSize(gfx::Size(500, 1000));
+ auto* outer_contents_ptr =
+ scroll_view_->SetContents(std::move(outer_contents));
+
+ auto inner_scroll_view = std::make_unique<ScrollView>();
+ auto* inner_scroll_view_ptr =
+ outer_contents_ptr->AddChildView(std::move(inner_scroll_view));
+
+ ScrollViewTestApi inner_test_api(inner_scroll_view_ptr);
+ auto inner_contents = std::make_unique<FixedView>();
+ inner_contents->SetPreferredSize(gfx::Size(500, 1000));
+ auto* inner_contents_ptr =
+ inner_scroll_view_ptr->SetContents(std::move(inner_contents));
+
+ inner_scroll_view_ptr->SetBoundsRect(gfx::Rect(0, 510, 100, 100));
+ inner_scroll_view_ptr->Layout();
+ EXPECT_EQ(gfx::Point(), inner_test_api.IntegralViewOffset());
+
+ scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 200, 200));
+ scroll_view_->Layout();
+ EXPECT_EQ(gfx::Point(), outer_test_api.IntegralViewOffset());
+
+ // Scroll the inner scroll view to y=405 height=10. This should make the y
+ // position of the inner content at (405 + 10) - inner_viewport_height
+ // (scroll region bottom aligned). The outer scroll view should not scroll.
+ inner_contents_ptr->ScrollRectToVisible(gfx::Rect(0, 405, 10, 10));
+ const int inner_viewport_height =
+ inner_test_api.contents_viewport()->height();
+ gfx::ScrollOffset inner_offset = inner_test_api.CurrentOffset();
+ EXPECT_EQ(415 - inner_viewport_height, inner_offset.y());
+ gfx::ScrollOffset outer_offset = outer_test_api.CurrentOffset();
+ EXPECT_EQ(0, outer_offset.y());
+
+ // Set focus to the inner scroll view's contents root. This should cause the
+ // outer scroll view to scroll to y=510 height=100 so that the y position of
+ // the outer content is at (510 + 100) - outer_viewport_height (scroll region
+ // bottom aligned). The inner scroll view should not scroll.
+ inner_contents_ptr->SetFocus();
+ const int outer_viewport_height =
+ outer_test_api.contents_viewport()->height();
+ inner_offset = inner_test_api.CurrentOffset();
+ EXPECT_EQ(415 - inner_viewport_height, inner_offset.y());
+ outer_offset = outer_test_api.CurrentOffset();
+ EXPECT_EQ(610 - outer_viewport_height, outer_offset.y());
+}
+
// Verifies ClipHeightTo() uses the height of the content when it is between the
// minimum and maximum height values.
TEST_F(ScrollViewTest, ClipHeightToNormalContentHeight) {
diff --git a/chromium/ui/views/controls/scrollbar/scroll_bar_views.cc b/chromium/ui/views/controls/scrollbar/scroll_bar_views.cc
index 405168573ef..5da0afbd601 100644
--- a/chromium/ui/views/controls/scrollbar/scroll_bar_views.cc
+++ b/chromium/ui/views/controls/scrollbar/scroll_bar_views.cc
@@ -8,7 +8,8 @@
#include <memory>
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
+#include "base/notreached.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/views/controls/button/button.h"
diff --git a/chromium/ui/views/controls/slider.cc b/chromium/ui/views/controls/slider.cc
index 3e03f5379e3..0f71ce43d4a 100644
--- a/chromium/ui/views/controls/slider.cc
+++ b/chromium/ui/views/controls/slider.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include <memory>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/message_loop/message_loop_current.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc
index 9004b93f773..5c915f9d452 100644
--- a/chromium/ui/views/controls/styled_label.cc
+++ b/chromium/ui/views/controls/styled_label.cc
@@ -556,9 +556,6 @@ std::unique_ptr<Label> StyledLabel::CreateLabel(
// Note this ignores |default_text_style_|, in favor of style::STYLE_LINK.
auto link = std::make_unique<Link>(text, text_context_);
- // Links in a StyledLabel do not get underlines.
- link->SetUnderline(false);
-
layout_views_->link_targets[link.get()] = range;
result = std::move(link);
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 389092da35b..4fdef37e512 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -7,8 +7,8 @@
#include <algorithm>
#include <utility>
+#include "base/check_op.h"
#include "base/i18n/rtl.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "cc/paint/paint_flags.h"
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
index e06e0db5f2b..4c42c238ecb 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
@@ -24,7 +24,7 @@ class TabStrip;
namespace test {
class TabbedPaneAccessibilityMacTest;
-class TabbedPaneTest;
+class TabbedPaneWithWidgetTest;
} // namespace test
// TabbedPane is a view that shows tabs. When the user clicks on a tab, the
@@ -100,7 +100,7 @@ class VIEWS_EXPORT TabbedPane : public View {
friend class FocusTraversalTest;
friend class Tab;
friend class TabStrip;
- friend class test::TabbedPaneTest;
+ friend class test::TabbedPaneWithWidgetTest;
friend class test::TabbedPaneAccessibilityMacTest;
// Adds a new tab at |index| with |title|. |contents| is the view displayed
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
index 51cfc08d9ee..808afa4d777 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -43,14 +43,75 @@ ax::mojom::Role GetAccessibleRole(View* view) {
} // namespace
-class TabbedPaneTest : public ViewsTestBase {
+using TabbedPaneTest = ViewsTestBase;
+
+// Tests tab orientation.
+TEST_F(TabbedPaneTest, HorizontalOrientationDefault) {
+ auto tabbed_pane = std::make_unique<TabbedPane>();
+ EXPECT_EQ(tabbed_pane->GetOrientation(),
+ TabbedPane::Orientation::kHorizontal);
+}
+
+// Tests tab orientation.
+TEST_F(TabbedPaneTest, VerticalOrientation) {
+ auto tabbed_pane = std::make_unique<TabbedPane>(
+ TabbedPane::Orientation::kVertical, TabbedPane::TabStripStyle::kBorder);
+ EXPECT_EQ(tabbed_pane->GetOrientation(), TabbedPane::Orientation::kVertical);
+}
+
+// Tests tab strip style.
+TEST_F(TabbedPaneTest, TabStripBorderStyle) {
+ auto tabbed_pane = std::make_unique<TabbedPane>();
+ EXPECT_EQ(tabbed_pane->GetStyle(), TabbedPane::TabStripStyle::kBorder);
+}
+
+// Tests tab strip style.
+TEST_F(TabbedPaneTest, TabStripHighlightStyle) {
+ auto tabbed_pane =
+ std::make_unique<TabbedPane>(TabbedPane::Orientation::kVertical,
+ TabbedPane::TabStripStyle::kHighlight);
+ EXPECT_EQ(tabbed_pane->GetStyle(), TabbedPane::TabStripStyle::kHighlight);
+}
+
+// Tests the preferred size and layout when tabs are aligned vertically..
+TEST_F(TabbedPaneTest, SizeAndLayoutInVerticalOrientation) {
+ auto tabbed_pane = std::make_unique<TabbedPane>(
+ TabbedPane::Orientation::kVertical, TabbedPane::TabStripStyle::kBorder);
+ View* child1 =
+ tabbed_pane->AddTab(ASCIIToUTF16("tab1"),
+ std::make_unique<StaticSizedView>(gfx::Size(20, 10)));
+ View* child2 = tabbed_pane->AddTab(
+ ASCIIToUTF16("tab2"), std::make_unique<StaticSizedView>(gfx::Size(5, 5)));
+ tabbed_pane->SelectTabAt(0);
+
+ // |tabbed_pane_| reserves extra width for the tab strip in vertical mode.
+ EXPECT_GT(tabbed_pane->GetPreferredSize().width(), 20);
+ // |tabbed_pane_| height should match the largest child in vertical mode.
+ EXPECT_EQ(tabbed_pane->GetPreferredSize().height(), 10);
+
+ // The child views should resize to fit in larger tabbed panes.
+ tabbed_pane->SetBounds(0, 0, 100, 200);
+
+ EXPECT_GT(child1->bounds().width(), 0);
+ // |tabbed_pane_| reserves extra width for the tab strip. Therefore the
+ // children's width should be smaller than the |tabbed_pane_|'s width.
+ EXPECT_LT(child1->bounds().width(), 100);
+ // |tabbed_pane_| has no border. Therefore the children should be as high as
+ // the |tabbed_pane_|.
+ EXPECT_EQ(child1->bounds().height(), 200);
+
+ // If we switch to the other tab, it should get assigned the same bounds.
+ tabbed_pane->SelectTabAt(1);
+ EXPECT_EQ(child1->bounds(), child2->bounds());
+}
+
+class TabbedPaneWithWidgetTest : public ViewsTestBase {
public:
- TabbedPaneTest() = default;
+ TabbedPaneWithWidgetTest() = default;
void SetUp() override {
ViewsTestBase::SetUp();
- tabbed_pane_ = std::make_unique<TabbedPane>();
- tabbed_pane_->set_owned_by_client();
+ auto tabbed_pane = std::make_unique<TabbedPane>();
// Create a widget so that accessibility data will be returned correctly.
widget_ = std::make_unique<Widget>();
@@ -59,22 +120,17 @@ class TabbedPaneTest : public ViewsTestBase {
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(0, 0, 650, 650);
widget_->Init(std::move(params));
- widget_->SetContentsView(tabbed_pane_.get());
+ tabbed_pane_ = tabbed_pane.get();
+ widget_->SetContentsView(tabbed_pane.release());
}
void TearDown() override {
- tabbed_pane_.reset();
+ tabbed_pane_ = nullptr;
widget_.reset();
ViewsTestBase::TearDown();
}
protected:
- void MakeTabbedPane(TabbedPane::Orientation orientation,
- TabbedPane::TabStripStyle style) {
- tabbed_pane_ = std::make_unique<TabbedPane>(orientation, style);
- tabbed_pane_->set_owned_by_client();
- }
-
Tab* GetTabAt(size_t index) {
return static_cast<Tab*>(tabbed_pane_->tab_strip_->children()[index]);
}
@@ -90,41 +146,16 @@ class TabbedPaneTest : public ViewsTestBase {
}
std::unique_ptr<Widget> widget_;
- std::unique_ptr<TabbedPane> tabbed_pane_;
+ TabbedPane* tabbed_pane_;
private:
- DISALLOW_COPY_AND_ASSIGN(TabbedPaneTest);
+ DISALLOW_COPY_AND_ASSIGN(TabbedPaneWithWidgetTest);
};
-// Tests tab orientation.
-TEST_F(TabbedPaneTest, HorizontalOrientation) {
- EXPECT_EQ(tabbed_pane_->GetOrientation(),
- TabbedPane::Orientation::kHorizontal);
-}
-
-// Tests tab orientation.
-TEST_F(TabbedPaneTest, VerticalOrientation) {
- MakeTabbedPane(TabbedPane::Orientation::kVertical,
- TabbedPane::TabStripStyle::kBorder);
- EXPECT_EQ(tabbed_pane_->GetOrientation(), TabbedPane::Orientation::kVertical);
-}
-
-// Tests tab strip style.
-TEST_F(TabbedPaneTest, TabStripBorderStyle) {
- EXPECT_EQ(tabbed_pane_->GetStyle(), TabbedPane::TabStripStyle::kBorder);
-}
-
-// Tests tab strip style.
-TEST_F(TabbedPaneTest, TabStripHighlightStyle) {
- MakeTabbedPane(TabbedPane::Orientation::kVertical,
- TabbedPane::TabStripStyle::kHighlight);
- EXPECT_EQ(tabbed_pane_->GetStyle(), TabbedPane::TabStripStyle::kHighlight);
-}
-
// Tests the preferred size and layout when tabs are aligned horizontally.
// TabbedPane requests a size that fits the largest child or the minimum size
// necessary to display the tab titles, whichever is larger.
-TEST_F(TabbedPaneTest, SizeAndLayout) {
+TEST_F(TabbedPaneWithWidgetTest, SizeAndLayout) {
View* child1 = tabbed_pane_->AddTab(
ASCIIToUTF16("tab1"),
std::make_unique<StaticSizedView>(gfx::Size(20, 10)));
@@ -165,39 +196,7 @@ TEST_F(TabbedPaneTest, SizeAndLayout) {
EXPECT_EQ(child2->bounds(), child3->bounds());
}
-// Tests the preferred size and layout when tabs are aligned vertically..
-TEST_F(TabbedPaneTest, SizeAndLayoutInVerticalOrientation) {
- MakeTabbedPane(TabbedPane::Orientation::kVertical,
- TabbedPane::TabStripStyle::kBorder);
- View* child1 = tabbed_pane_->AddTab(
- ASCIIToUTF16("tab1"),
- std::make_unique<StaticSizedView>(gfx::Size(20, 10)));
- View* child2 = tabbed_pane_->AddTab(
- ASCIIToUTF16("tab2"), std::make_unique<StaticSizedView>(gfx::Size(5, 5)));
- tabbed_pane_->SelectTabAt(0);
-
- // |tabbed_pane_| reserves extra width for the tab strip in vertical mode.
- EXPECT_GT(tabbed_pane_->GetPreferredSize().width(), 20);
- // |tabbed_pane_| height should match the largest child in vertical mode.
- EXPECT_EQ(tabbed_pane_->GetPreferredSize().height(), 10);
-
- // The child views should resize to fit in larger tabbed panes.
- tabbed_pane_->SetBounds(0, 0, 100, 200);
- RunPendingMessages();
- EXPECT_GT(child1->bounds().width(), 0);
- // |tabbed_pane_| reserves extra width for the tab strip. Therefore the
- // children's width should be smaller than the |tabbed_pane_|'s width.
- EXPECT_LT(child1->bounds().width(), 100);
- // |tabbed_pane_| has no border. Therefore the children should be as high as
- // the |tabbed_pane_|.
- EXPECT_EQ(child1->bounds().height(), 200);
-
- // If we switch to the other tab, it should get assigned the same bounds.
- tabbed_pane_->SelectTabAt(1);
- EXPECT_EQ(child1->bounds(), child2->bounds());
-}
-
-TEST_F(TabbedPaneTest, AddAndSelect) {
+TEST_F(TabbedPaneWithWidgetTest, AddAndSelect) {
// Add several tabs; only the first should be selected automatically.
for (size_t i = 0; i < 3; ++i) {
tabbed_pane_->AddTab(DefaultTabTitle(), std::make_unique<View>());
@@ -218,7 +217,7 @@ TEST_F(TabbedPaneTest, AddAndSelect) {
EXPECT_NE(0u, tabbed_pane_->GetSelectedTabIndex());
}
-TEST_F(TabbedPaneTest, ArrowKeyBindings) {
+TEST_F(TabbedPaneWithWidgetTest, ArrowKeyBindings) {
// Add several tabs; only the first should be selected automatically.
for (size_t i = 0; i < 3; ++i) {
tabbed_pane_->AddTab(DefaultTabTitle(), std::make_unique<View>());
@@ -246,7 +245,7 @@ TEST_F(TabbedPaneTest, ArrowKeyBindings) {
// Use TabbedPane::HandleAccessibleAction() to select tabs and make sure their
// a11y information is correct.
-TEST_F(TabbedPaneTest, SelectTabWithAccessibleAction) {
+TEST_F(TabbedPaneWithWidgetTest, SelectTabWithAccessibleAction) {
constexpr size_t kNumTabs = 3;
for (size_t i = 0; i < kNumTabs; ++i) {
tabbed_pane_->AddTab(DefaultTabTitle(), std::make_unique<View>());
@@ -281,17 +280,17 @@ TEST_F(TabbedPaneTest, SelectTabWithAccessibleAction) {
EXPECT_EQ(1u, tabbed_pane_->GetSelectedTabIndex());
}
-TEST_F(TabbedPaneTest, AccessiblePaneTitleTracksActiveTabTitle) {
+TEST_F(TabbedPaneWithWidgetTest, AccessiblePaneTitleTracksActiveTabTitle) {
const base::string16 kFirstTitle = ASCIIToUTF16("Tab1");
const base::string16 kSecondTitle = ASCIIToUTF16("Tab2");
tabbed_pane_->AddTab(kFirstTitle, std::make_unique<View>());
tabbed_pane_->AddTab(kSecondTitle, std::make_unique<View>());
- EXPECT_EQ(kFirstTitle, GetAccessibleName(tabbed_pane_.get()));
+ EXPECT_EQ(kFirstTitle, GetAccessibleName(tabbed_pane_));
tabbed_pane_->SelectTabAt(1);
- EXPECT_EQ(kSecondTitle, GetAccessibleName(tabbed_pane_.get()));
+ EXPECT_EQ(kSecondTitle, GetAccessibleName(tabbed_pane_));
}
-TEST_F(TabbedPaneTest, AccessiblePaneContentsTitleTracksTabTitle) {
+TEST_F(TabbedPaneWithWidgetTest, AccessiblePaneContentsTitleTracksTabTitle) {
const base::string16 kFirstTitle = ASCIIToUTF16("Tab1");
const base::string16 kSecondTitle = ASCIIToUTF16("Tab2");
View* const tab1_contents =
@@ -302,7 +301,7 @@ TEST_F(TabbedPaneTest, AccessiblePaneContentsTitleTracksTabTitle) {
EXPECT_EQ(kSecondTitle, GetAccessibleName(tab2_contents));
}
-TEST_F(TabbedPaneTest, AccessiblePaneContentsRoleIsTab) {
+TEST_F(TabbedPaneWithWidgetTest, AccessiblePaneContentsRoleIsTab) {
const base::string16 kFirstTitle = ASCIIToUTF16("Tab1");
const base::string16 kSecondTitle = ASCIIToUTF16("Tab2");
View* const tab1_contents =
diff --git a/chromium/ui/views/controls/table/table_utils.cc b/chromium/ui/views/controls/table/table_utils.cc
index 36ed734a622..d6ac523212e 100644
--- a/chromium/ui/views/controls/table/table_utils.cc
+++ b/chromium/ui/views/controls/table/table_utils.cc
@@ -8,7 +8,7 @@
#include <algorithm>
-#include "base/logging.h"
+#include "base/notreached.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/text_utils.h"
diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc
index 458e2470409..94eb7a0527c 100644
--- a/chromium/ui/views/controls/table/table_view.cc
+++ b/chromium/ui/views/controls/table/table_view.cc
@@ -1422,28 +1422,33 @@ void TableView::UpdateVirtualAccessibilityChildrenBounds() {
}
gfx::Rect TableView::CalculateHeaderRowAccessibilityBounds() const {
- return AdjustRectForAXRelativeBounds(header_->GetVisibleBounds());
+ gfx::Rect header_bounds = header_->GetVisibleBounds();
+ gfx::Point header_origin = header_bounds.origin();
+ ConvertPointToTarget(header_, this, &header_origin);
+ header_bounds.set_origin(header_origin);
+ return header_bounds;
}
gfx::Rect TableView::CalculateHeaderCellAccessibilityBounds(
const int visible_column_index) const {
+ const gfx::Rect& header_bounds = CalculateHeaderRowAccessibilityBounds();
const VisibleColumn& visible_column = visible_columns_[visible_column_index];
- gfx::Rect header_cell_bounds(visible_column.x, header_->y(),
- visible_column.width, header_->height());
- return AdjustRectForAXRelativeBounds(header_cell_bounds);
+ gfx::Rect header_cell_bounds(visible_column.x, header_bounds.y(),
+ visible_column.width, header_bounds.height());
+ return header_cell_bounds;
}
gfx::Rect TableView::CalculateTableRowAccessibilityBounds(
const int row_index) const {
gfx::Rect row_bounds = GetRowBounds(row_index);
- return AdjustRectForAXRelativeBounds(row_bounds);
+ return row_bounds;
}
gfx::Rect TableView::CalculateTableCellAccessibilityBounds(
const int row_index,
const int visible_column_index) const {
gfx::Rect cell_bounds = GetCellBounds(row_index, visible_column_index);
- return AdjustRectForAXRelativeBounds(cell_bounds);
+ return cell_bounds;
}
void TableView::UpdateAccessibilityFocus() {
@@ -1510,13 +1515,6 @@ AXVirtualView* TableView::GetVirtualAccessibilityCell(
return i->get();
}
-gfx::Rect TableView::AdjustRectForAXRelativeBounds(
- const gfx::Rect& rect) const {
- gfx::Rect converted_rect = rect;
- View::ConvertRectToScreen(this, &converted_rect);
- return converted_rect;
-}
-
DEFINE_ENUM_CONVERTERS(TableTypes,
{TableTypes::TEXT_ONLY, base::ASCIIToUTF16("TEXT_ONLY")},
{TableTypes::ICON_AND_TEXT,
diff --git a/chromium/ui/views/controls/table/table_view.h b/chromium/ui/views/controls/table/table_view.h
index 6a5546c7b74..1a640fdf53e 100644
--- a/chromium/ui/views/controls/table/table_view.h
+++ b/chromium/ui/views/controls/table/table_view.h
@@ -383,11 +383,6 @@ class VIEWS_EXPORT TableView : public views::View,
// |visible_column_index| indexes into |visible_columns_|.
AXVirtualView* GetVirtualAccessibilityCell(int row, int visible_column_index);
- // Returns |rect|, adjusted for use in AXRelativeBounds by translating it into
- // screen coordinates. The result must be converted to gfx::RectF when setting
- // into AXRelativeBounds.
- gfx::Rect AdjustRectForAXRelativeBounds(const gfx::Rect& rect) const;
-
ui::TableModel* model_ = nullptr;
std::vector<ui::TableColumn> columns_;
diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc
index fb2a3ecc409..df538cc5d3c 100644
--- a/chromium/ui/views/controls/table/table_view_unittest.cc
+++ b/chromium/ui/views/controls/table/table_view_unittest.cc
@@ -80,23 +80,33 @@ class TableViewTestHelper {
// Generate the bounds for the header row and cells.
auto header_row = std::vector<gfx::Rect>();
- header_row.push_back(table_->CalculateHeaderRowAccessibilityBounds());
+ gfx::Rect header_row_bounds =
+ table_->CalculateHeaderRowAccessibilityBounds();
+ View::ConvertRectToScreen(table_, &header_row_bounds);
+ header_row.push_back(header_row_bounds);
for (size_t column_index = 0; column_index < visible_col_count();
column_index++) {
- header_row.push_back(
- table_->CalculateHeaderCellAccessibilityBounds(column_index));
+ gfx::Rect header_cell_bounds =
+ table_->CalculateHeaderCellAccessibilityBounds(column_index);
+ View::ConvertRectToScreen(table_, &header_cell_bounds);
+ header_row.push_back(header_cell_bounds);
}
expected_bounds.push_back(header_row);
// Generate the bounds for the table rows and cells.
for (int row_index = 0; row_index < table_->GetRowCount(); row_index++) {
auto table_row = std::vector<gfx::Rect>();
- table_row.push_back(
- table_->CalculateTableRowAccessibilityBounds(row_index));
+ gfx::Rect table_row_bounds =
+ table_->CalculateTableRowAccessibilityBounds(row_index);
+ View::ConvertRectToScreen(table_, &table_row_bounds);
+ table_row.push_back(table_row_bounds);
for (size_t column_index = 0; column_index < visible_col_count();
column_index++) {
- table_row.push_back(table_->CalculateTableCellAccessibilityBounds(
- row_index, column_index));
+ gfx::Rect table_cell_bounds =
+ table_->CalculateTableCellAccessibilityBounds(row_index,
+ column_index);
+ View::ConvertRectToScreen(table_, &table_cell_bounds);
+ table_row.push_back(table_cell_bounds);
}
expected_bounds.push_back(table_row);
}
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index 61b11e53fc3..d8e8fd0ace0 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -8,6 +8,7 @@
#include <set>
#include <string>
#include <utility>
+#include "ui/events/gesture_event_details.h"
#if defined(OS_WIN)
#include <vector>
@@ -55,6 +56,7 @@
#include "ui/views/painter.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/views_delegate.h"
+#include "ui/views/views_features.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/coordinate_conversion.h"
@@ -215,20 +217,20 @@ ui::TextEditCommand GetCommandForKeyEvent(const ui::KeyEvent& event) {
ui::TextEditCommand GetTextEditCommandFromMenuCommand(int command_id,
bool has_selection) {
switch (command_id) {
- case IDS_APP_UNDO:
+ case Textfield::kUndo:
return ui::TextEditCommand::UNDO;
- case IDS_APP_CUT:
+ case Textfield::kCut:
return ui::TextEditCommand::CUT;
- case IDS_APP_COPY:
+ case Textfield::kCopy:
return ui::TextEditCommand::COPY;
- case IDS_APP_PASTE:
+ case Textfield::kPaste:
return ui::TextEditCommand::PASTE;
- case IDS_APP_DELETE:
+ case Textfield::kDelete:
// The DELETE menu action only works in case of an active selection.
if (has_selection)
return ui::TextEditCommand::DELETE_FORWARD;
break;
- case IDS_APP_SELECT_ALL:
+ case Textfield::kSelectAll:
return ui::TextEditCommand::SELECT_ALL;
}
return ui::TextEditCommand::INVALID_COMMAND;
@@ -265,6 +267,11 @@ bool IsControlKeyModifier(int flags) {
#endif
}
+bool IsValidCharToInsert(const base::char16& ch) {
+ // Filter out all control characters, including tab and new line characters.
+ return (ch >= 0x20 && ch < 0x7F) || ch > 0x9F;
+}
+
} // namespace
// static
@@ -296,12 +303,11 @@ Textfield::Textfield()
selection_controller_(this) {
set_context_menu_controller(this);
set_drag_controller(this);
- cursor_view_.SetPaintToLayer(ui::LAYER_SOLID_COLOR);
- cursor_view_.layer()->SetColor(GetTextColor());
- // |cursor_view_| is owned by Textfield view.
- cursor_view_.set_owned_by_client();
- cursor_view_.GetViewAccessibility().OverrideIsIgnored(true);
- AddChildView(&cursor_view_);
+ auto cursor_view = std::make_unique<View>();
+ cursor_view->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
+ cursor_view->layer()->SetColor(GetTextColor());
+ cursor_view->GetViewAccessibility().OverrideIsIgnored(true);
+ cursor_view_ = AddChildView(std::move(cursor_view));
GetRenderText()->SetFontList(GetDefaultFontList());
UpdateBorder();
SetFocusBehavior(FocusBehavior::ALWAYS);
@@ -388,7 +394,12 @@ const base::string16& Textfield::GetText() const {
}
void Textfield::SetText(const base::string16& new_text) {
- model_->SetText(new_text);
+ SetText(new_text, new_text.length());
+}
+
+void Textfield::SetText(const base::string16& new_text,
+ size_t cursor_position) {
+ model_->SetText(new_text, cursor_position);
OnCaretBoundsChanged();
UpdateCursorViewPosition();
UpdateCursorVisibility();
@@ -434,8 +445,8 @@ void Textfield::ClearSelection() {
UpdateAfterChange(false, true);
}
-bool Textfield::HasSelection() const {
- return !GetSelectedRange().is_empty();
+bool Textfield::HasSelection(bool primary_only) const {
+ return model_->HasSelection(primary_only);
}
SkColor Textfield::GetTextColor() const {
@@ -551,8 +562,15 @@ const gfx::Range& Textfield::GetSelectedRange() const {
}
void Textfield::SetSelectedRange(const gfx::Range& range) {
- model_->SelectRange(range);
- UpdateAfterChange(false, true);
+ SetSelectedRange(range, true);
+}
+
+void Textfield::SetSelectedRange(const gfx::Range& range, bool primary) {
+ model_->SelectRange(range, primary);
+ if (primary)
+ UpdateAfterChange(false, true);
+ else
+ SchedulePaint();
OnPropertyChanged(&model_ + kTextfieldSelectedRange, kPropertyEffectsPaint);
}
@@ -571,7 +589,7 @@ size_t Textfield::GetCursorPosition() const {
void Textfield::SetColor(SkColor value) {
GetRenderText()->SetColor(value);
- cursor_view_.layer()->SetColor(value);
+ cursor_view_->layer()->SetColor(value);
OnPropertyChanged(&model_ + kTextfieldTextColor, kPropertyEffectsPaint);
}
@@ -685,7 +703,7 @@ bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
if (!handled &&
(event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton())) {
if (!had_focus)
- RequestFocusWithPointer(ui::EventPointerType::POINTER_TYPE_MOUSE);
+ RequestFocusWithPointer(ui::EventPointerType::kMouse);
#if !defined(OS_WIN)
ShowVirtualKeyboardIfEnabled();
#endif
@@ -693,7 +711,7 @@ bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
if (!handled && !had_focus && event.IsOnlyMiddleMouseButton())
- RequestFocusWithPointer(ui::EventPointerType::POINTER_TYPE_MOUSE);
+ RequestFocusWithPointer(ui::EventPointerType::kMouse);
#endif
return selection_controller_.OnMousePressed(
@@ -767,29 +785,27 @@ bool Textfield::OnKeyReleased(const ui::KeyEvent& event) {
}
void Textfield::OnGestureEvent(ui::GestureEvent* event) {
- bool show_virtual_keyboard = true;
-#if defined(OS_WIN)
- show_virtual_keyboard = event->details().primary_pointer_type() ==
- ui::EventPointerType::POINTER_TYPE_TOUCH ||
- event->details().primary_pointer_type() ==
- ui::EventPointerType::POINTER_TYPE_PEN;
-#endif
+ static const bool kTakeFocusOnTapUp =
+ base::FeatureList::IsEnabled(features::kTextfieldFocusOnTapUp);
+
switch (event->type()) {
case ui::ET_GESTURE_TAP_DOWN:
- RequestFocusWithPointer(event->details().primary_pointer_type());
- if (show_virtual_keyboard)
- ShowVirtualKeyboardIfEnabled();
- event->SetHandled();
+ if (!kTakeFocusOnTapUp) {
+ RequestFocusForGesture(event->details());
+ event->SetHandled();
+ }
break;
case ui::ET_GESTURE_TAP:
+ if (kTakeFocusOnTapUp)
+ RequestFocusForGesture(event->details());
if (controller_ && controller_->HandleGestureEvent(this, *event)) {
event->SetHandled();
return;
}
if (event->details().tap_count() == 1) {
- // If tap is on the selection and touch handles are not present, handles
- // should be shown without changing selection. Otherwise, cursor should
- // be moved to the tap location.
+ // If tap is on the selection and touch handles are not present,
+ // handles should be shown without changing selection. Otherwise,
+ // cursor should be moved to the tap location.
if (touch_selection_controller_ ||
!GetRenderText()->IsPointInSelection(event->location())) {
OnBeforeUserAction();
@@ -816,15 +832,15 @@ void Textfield::OnGestureEvent(ui::GestureEvent* event) {
SelectWordAt(event->location());
OnAfterUserAction();
CreateTouchSelectionControllerAndNotifyIt();
- // If touch selection activated successfully, mark event as handled so
- // that the regular context menu is not shown.
+ // If touch selection activated successfully, mark event as handled
+ // so that the regular context menu is not shown.
if (touch_selection_controller_)
event->SetHandled();
} else {
- // If long-press happens on the selection, deactivate touch selection
- // and try to initiate drag-drop. If drag-drop is not enabled, context
- // menu will be shown. Event is not marked as handled to let Views
- // handle drag-drop or context menu.
+ // If long-press happens on the selection, deactivate touch
+ // selection and try to initiate drag-drop. If drag-drop is not
+ // enabled, context menu will be shown. Event is not marked as
+ // handled to let Views handle drag-drop or context menu.
DestroyTouchSelection();
initiating_drag_ = switches::IsTouchDragDropEnabled();
}
@@ -837,29 +853,34 @@ void Textfield::OnGestureEvent(ui::GestureEvent* event) {
event->SetHandled();
break;
case ui::ET_GESTURE_SCROLL_BEGIN:
- touch_handles_hidden_due_to_scroll_ =
- touch_selection_controller_ != nullptr;
- DestroyTouchSelection();
- drag_start_location_ = event->location();
- drag_start_display_offset_ =
- GetRenderText()->GetUpdatedDisplayOffset().x();
- event->SetHandled();
+ if (HasFocus()) {
+ touch_handles_hidden_due_to_scroll_ =
+ touch_selection_controller_ != nullptr;
+ DestroyTouchSelection();
+ drag_start_location_ = event->location();
+ drag_start_display_offset_ =
+ GetRenderText()->GetUpdatedDisplayOffset().x();
+ event->SetHandled();
+ }
break;
- case ui::ET_GESTURE_SCROLL_UPDATE: {
- int new_offset = drag_start_display_offset_ + event->location().x() -
- drag_start_location_.x();
- GetRenderText()->SetDisplayOffset(new_offset);
- SchedulePaint();
- event->SetHandled();
+ case ui::ET_GESTURE_SCROLL_UPDATE:
+ if (HasFocus()) {
+ int new_offset = drag_start_display_offset_ + event->location().x() -
+ drag_start_location_.x();
+ GetRenderText()->SetDisplayOffset(new_offset);
+ SchedulePaint();
+ event->SetHandled();
+ }
break;
- }
case ui::ET_GESTURE_SCROLL_END:
case ui::ET_SCROLL_FLING_START:
- if (touch_handles_hidden_due_to_scroll_) {
- CreateTouchSelectionControllerAndNotifyIt();
- touch_handles_hidden_due_to_scroll_ = false;
+ if (HasFocus()) {
+ if (touch_handles_hidden_due_to_scroll_) {
+ CreateTouchSelectionControllerAndNotifyIt();
+ touch_handles_hidden_due_to_scroll_ = false;
+ }
+ event->SetHandled();
}
- event->SetHandled();
break;
default:
return;
@@ -985,7 +1006,7 @@ int Textfield::OnPerformDrop(const ui::DropTargetEvent& event) {
// Adjust the drop destination if it is on or after the current selection.
size_t pos = drop_destination_model.caret_pos();
pos -= render_text->selection().Intersect(gfx::Range(0, pos)).length();
- model_->DeleteSelectionAndInsertTextAt(new_text, pos);
+ model_->DeletePrimarySelectionAndInsertTextAt(new_text, pos);
} else {
model_->MoveCursorTo(drop_destination_model);
// Drop always inserts text even if the textfield is not in insert mode.
@@ -1106,7 +1127,7 @@ void Textfield::OnFocus() {
GetRenderText()->set_focused(true);
if (ShouldShowCursor()) {
UpdateCursorViewPosition();
- cursor_view_.SetVisible(true);
+ cursor_view_->SetVisible(true);
}
if (GetInputMethod())
GetInputMethod()->SetFocusedTextInputClient(this);
@@ -1135,7 +1156,7 @@ void Textfield::OnBlur() {
#endif // defined(OS_CHROMEOS)
}
StopBlinkingCursor();
- cursor_view_.SetVisible(false);
+ cursor_view_->SetVisible(false);
DestroyTouchSelection();
@@ -1159,7 +1180,7 @@ void Textfield::OnThemeChanged() {
render_text->set_selection_color(GetSelectionTextColor());
render_text->set_selection_background_focused_color(
GetSelectionBackgroundColor());
- cursor_view_.layer()->SetColor(GetTextColor());
+ cursor_view_->layer()->SetColor(GetTextColor());
}
////////////////////////////////////////////////////////////////////////////////
@@ -1377,23 +1398,23 @@ bool Textfield::IsCommandIdEnabled(int command_id) const {
bool Textfield::GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) const {
switch (command_id) {
- case IDS_APP_UNDO:
+ case kUndo:
*accelerator = ui::Accelerator(ui::VKEY_Z, ui::EF_PLATFORM_ACCELERATOR);
return true;
- case IDS_APP_CUT:
+ case kCut:
*accelerator = ui::Accelerator(ui::VKEY_X, ui::EF_PLATFORM_ACCELERATOR);
return true;
- case IDS_APP_COPY:
+ case kCopy:
*accelerator = ui::Accelerator(ui::VKEY_C, ui::EF_PLATFORM_ACCELERATOR);
return true;
- case IDS_APP_PASTE:
+ case kPaste:
*accelerator = ui::Accelerator(ui::VKEY_V, ui::EF_PLATFORM_ACCELERATOR);
return true;
- case IDS_APP_SELECT_ALL:
+ case kSelectAll:
*accelerator = ui::Accelerator(ui::VKEY_A, ui::EF_PLATFORM_ACCELERATOR);
return true;
@@ -1459,13 +1480,17 @@ void Textfield::ClearCompositionText() {
}
void Textfield::InsertText(const base::string16& new_text) {
- // TODO(suzhe): Filter invalid characters.
- if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || new_text.empty())
+ base::string16 filtered_new_text;
+ std::copy_if(new_text.begin(), new_text.end(),
+ std::back_inserter(filtered_new_text), IsValidCharToInsert);
+
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE ||
+ filtered_new_text.empty())
return;
OnBeforeUserAction();
skip_input_method_cancel_composition_ = true;
- model_->InsertText(new_text);
+ model_->InsertText(filtered_new_text);
skip_input_method_cancel_composition_ = false;
UpdateAfterChange(true, true);
OnAfterUserAction();
@@ -1477,13 +1502,12 @@ void Textfield::InsertChar(const ui::KeyEvent& event) {
return;
}
- // Filter out all control characters, including tab and new line characters,
- // and all characters with Alt modifier (and Search on ChromeOS, Ctrl on
- // Linux). But allow characters with the AltGr modifier. On Windows AltGr is
- // represented by Alt+Ctrl or Right Alt, and on Linux it's a different flag
- // that we don't care about.
+ // Filter all invalid chars and all characters with Alt modifier (and Search
+ // on ChromeOS, Ctrl on Linux). But allow characters with the AltGr modifier.
+ // On Windows AltGr is represented by Alt+Ctrl or Right Alt, and on Linux it's
+ // a different flag that we don't care about.
const base::char16 ch = event.GetCharacter();
- const bool should_insert_char = ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
+ const bool should_insert_char = IsValidCharToInsert(ch) &&
!ui::IsSystemKeyModifier(event.flags()) &&
!IsControlKeyModifier(event.flags());
if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || !should_insert_char)
@@ -1711,9 +1735,9 @@ bool Textfield::IsTextEditCommandEnabled(ui::TextEditCommand command) const {
case ui::TextEditCommand::REDO:
return editable && model_->CanRedo();
case ui::TextEditCommand::CUT:
- return editable && readable && model_->HasSelection();
+ return editable && readable && HasSelection();
case ui::TextEditCommand::COPY:
- return readable && model_->HasSelection();
+ return readable && HasSelection();
case ui::TextEditCommand::PASTE:
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, &result);
@@ -1722,8 +1746,7 @@ bool Textfield::IsTextEditCommandEnabled(ui::TextEditCommand command) const {
return !GetText().empty() &&
GetSelectedRange().length() != GetText().length();
case ui::TextEditCommand::TRANSPOSE:
- return editable && !model_->HasSelection() &&
- !model_->HasCompositionText();
+ return editable && !HasSelection() && !model_->HasCompositionText();
case ui::TextEditCommand::YANK:
return editable;
case ui::TextEditCommand::MOVE_DOWN:
@@ -2053,13 +2076,13 @@ void Textfield::RequestFocusWithPointer(ui::EventPointerType pointer_type) {
return;
switch (pointer_type) {
- case ui::EventPointerType::POINTER_TYPE_MOUSE:
+ case ui::EventPointerType::kMouse:
focus_reason_ = ui::TextInputClient::FOCUS_REASON_MOUSE;
break;
- case ui::EventPointerType::POINTER_TYPE_PEN:
+ case ui::EventPointerType::kPen:
focus_reason_ = ui::TextInputClient::FOCUS_REASON_PEN;
break;
- case ui::EventPointerType::POINTER_TYPE_TOUCH:
+ case ui::EventPointerType::kTouch:
focus_reason_ = ui::TextInputClient::FOCUS_REASON_TOUCH;
break;
default:
@@ -2070,6 +2093,19 @@ void Textfield::RequestFocusWithPointer(ui::EventPointerType pointer_type) {
View::RequestFocus();
}
+void Textfield::RequestFocusForGesture(const ui::GestureEventDetails& details) {
+ bool show_virtual_keyboard = true;
+#if defined(OS_WIN)
+ show_virtual_keyboard =
+ details.primary_pointer_type() == ui::EventPointerType::kTouch ||
+ details.primary_pointer_type() == ui::EventPointerType::kPen;
+#endif
+
+ RequestFocusWithPointer(details.primary_pointer_type());
+ if (show_virtual_keyboard)
+ ShowVirtualKeyboardIfEnabled();
+}
+
views::PropertyChangedSubscription Textfield::AddTextChangedCallback(
views::PropertyChangedCallback callback) {
return AddPropertyChangedCallback(&model_ + kTextfieldText,
@@ -2216,7 +2252,7 @@ void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) {
}
void Textfield::UpdateCursorVisibility() {
- cursor_view_.SetVisible(ShouldShowCursor());
+ cursor_view_->SetVisible(ShouldShowCursor());
if (ShouldBlinkCursor())
StartBlinkingCursor();
else
@@ -2229,7 +2265,7 @@ void Textfield::UpdateCursorViewPosition() {
location.set_height(
std::min(location.height(),
GetLocalBounds().height() - location.y() - location.y()));
- cursor_view_.SetBoundsRect(location);
+ cursor_view_->SetBoundsRect(location);
}
int Textfield::GetTextStyle() const {
@@ -2339,15 +2375,14 @@ void Textfield::UpdateContextMenu() {
context_menu_contents_.reset();
context_menu_contents_ = std::make_unique<ui::SimpleMenuModel>(this);
- context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
+ context_menu_contents_->AddItemWithStringId(kUndo, IDS_APP_UNDO);
context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
- context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
- context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
- context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
- context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
+ context_menu_contents_->AddItemWithStringId(kCut, IDS_APP_CUT);
+ context_menu_contents_->AddItemWithStringId(kCopy, IDS_APP_COPY);
+ context_menu_contents_->AddItemWithStringId(kPaste, IDS_APP_PASTE);
+ context_menu_contents_->AddItemWithStringId(kDelete, IDS_APP_DELETE);
context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
- context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
- IDS_APP_SELECT_ALL);
+ context_menu_contents_->AddItemWithStringId(kSelectAll, IDS_APP_SELECT_ALL);
// If the controller adds menu commands, also override ExecuteCommand() and
// IsCommandIdEnabled() as appropriate, for the commands added.
@@ -2398,7 +2433,9 @@ void Textfield::OnEditFailed() {
}
bool Textfield::ShouldShowCursor() const {
- return HasFocus() && !HasSelection() && GetEnabled() && !GetReadOnly() &&
+ // Show the cursor when the primary selected range is empty; secondary
+ // selections do not affect cursor visibility.
+ return HasFocus() && !HasSelection(true) && GetEnabled() && !GetReadOnly() &&
!drop_cursor_visible_ && GetRenderText()->cursor_enabled();
}
@@ -2419,7 +2456,7 @@ void Textfield::StopBlinkingCursor() {
void Textfield::OnCursorBlinkTimerFired() {
DCHECK(ShouldBlinkCursor());
UpdateCursorViewPosition();
- cursor_view_.SetVisible(!cursor_view_.GetVisible());
+ cursor_view_->SetVisible(!cursor_view_->GetVisible());
}
void Textfield::OnEnabledChanged() {
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index 21bafd3fe89..825c45513cf 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -31,6 +31,7 @@
#include "ui/base/ime/text_input_type.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/pointer/touch_editing_controller.h"
+#include "ui/events/gesture_event_details.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/geometry/insets.h"
@@ -75,6 +76,13 @@ class VIEWS_EXPORT Textfield : public View,
public:
METADATA_HEADER(Textfield);
+ enum MenuCommands {
+ kUndo = kLastTouchEditableCommandId + 1,
+ kDelete,
+ kSelectAll,
+ kLastCommandId = kSelectAll,
+ };
+
// Returns the text cursor blink time, or 0 for no blinking.
static base::TimeDelta GetCaretBlinkInterval();
@@ -105,11 +113,14 @@ class VIEWS_EXPORT Textfield : public View,
// textfield.
const base::string16& GetText() const;
- // Sets the text currently displayed in the Textfield. This doesn't
- // change the cursor position if the current cursor is within the
- // new text's range, or moves the cursor to the end if the cursor is
- // out of the new text's range.
+ // Sets the text currently displayed in the Textfield and the cursor position.
+ // Calls to |SetText| are often followed by updating the selection or cursor,
+ // which does not update the edit history. I.e. the cursor position after
+ // redoing this change will be determined by |cursor_position| here and not by
+ // any subsequent calls to e.g. |SetSelectedRange|. Selections are not
+ // explicitly set here since redo's clear the selection anyways.
void SetText(const base::string16& new_text);
+ void SetText(const base::string16& new_text, size_t cursor_position);
// Appends the given string to the previously-existing text in the field.
void AppendText(const base::string16& new_text);
@@ -136,8 +147,9 @@ class VIEWS_EXPORT Textfield : public View,
// Clears the selection within the edit field and sets the caret to the end.
void ClearSelection();
- // Checks if there is any selected text.
- bool HasSelection() const;
+ // Checks if there is any selected text. |primary_only| indicates whether
+ // secondary selections should also be considered.
+ bool HasSelection(bool primary_only = false) const;
// Gets/sets the text color to be used when painting the Textfield.
SkColor GetTextColor() const;
@@ -206,6 +218,7 @@ class VIEWS_EXPORT Textfield : public View,
// Selects the specified logical text range.
void SetSelectedRange(const gfx::Range& range);
+ void SetSelectedRange(const gfx::Range& range, bool primary);
// Gets the text selection model.
const gfx::SelectionModel& GetSelectionModel() const;
@@ -413,11 +426,14 @@ class VIEWS_EXPORT Textfield : public View,
// override this to customize when the placeholder text is shown.
virtual bool ShouldShowPlaceholderText() const;
- protected:
// Like RequestFocus, but explicitly states that the focus is triggered by
// a pointer event.
void RequestFocusWithPointer(ui::EventPointerType pointer_type);
+ // Like RequestFocus, but explicitly states that the focus is triggered by a
+ // gesture event.
+ void RequestFocusForGesture(const ui::GestureEventDetails& details);
+
private:
friend class TextfieldTestApi;
@@ -641,7 +657,7 @@ class VIEWS_EXPORT Textfield : public View,
std::unique_ptr<views::MenuRunner> context_menu_runner_;
// View containing the text cursor.
- View cursor_view_;
+ View* cursor_view_ = nullptr;
#if defined(OS_MACOSX)
// Used to track active password input sessions.
diff --git a/chromium/ui/views/controls/textfield/textfield_model.cc b/chromium/ui/views/controls/textfield/textfield_model.cc
index 9e4896bf28d..d3df8334a98 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include <utility>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/macros.h"
#include "base/message_loop/message_loop_current.h"
#include "base/no_destructor.h"
@@ -19,6 +19,30 @@
#include "ui/gfx/utf16_indexing.h"
#include "ui/views/style/platform_style.h"
+namespace {
+
+// Orders ranges decreasing with respect to their min index. This is useful for
+// applying text edits such that an edit doesn't offset the positions of later
+// edits. It should be reversed when undoing edits.
+void order_ranges(std::vector<gfx::Range>* ranges) {
+ std::sort(ranges->begin(), ranges->end(), [](const auto& r1, const auto& r2) {
+ return r1.GetMin() > r2.GetMin();
+ });
+}
+
+// Adjusts |position| for the deletion of |ranges|. E.g., if |position| is 10,
+// and |ranges| is {{1, 3}, {15, 18}, and {6, 13}}, this will return 4,
+// subtracting 2 (3-1), 0 (15>10), and 4 (10-6) for each range respectively.
+size_t adjust_position_for_removals(size_t position,
+ std::vector<gfx::Range> ranges) {
+ size_t adjustment = 0;
+ for (auto range : ranges)
+ adjustment += range.Intersect(gfx::Range(0, position)).length();
+ return position - adjustment;
+}
+
+} // namespace
+
namespace views {
namespace internal {
@@ -38,15 +62,26 @@ class Edit {
// Revert the change made by this edit in |model|.
void Undo(TextfieldModel* model) {
- model->ModifyText(new_text_start_, new_text_end(), old_text_,
- old_text_start_, old_selection_);
+ // Insertions must be applied in order of increasing indices since |Redo|
+ // applies them in decreasing order.
+ auto insertion_texts = old_texts_;
+ std::reverse(insertion_texts.begin(), insertion_texts.end());
+ auto insertion_text_starts = old_text_starts_;
+ std::reverse(insertion_text_starts.begin(), insertion_text_starts.end());
+ model->ModifyText({{new_text_start_, new_text_end()}}, insertion_texts,
+ insertion_text_starts, old_primary_selection_,
+ old_secondary_selections_);
}
// Apply the change of this edit to the |model|.
void Redo(TextfieldModel* model) {
- model->ModifyText(old_text_start_, old_text_end(), new_text_,
- new_text_start_,
- gfx::Range(new_cursor_pos_, new_cursor_pos_));
+ std::vector<gfx::Range> deletions;
+ for (size_t i = 0; i < old_texts_.size(); ++i) {
+ deletions.emplace_back(old_text_starts_[i],
+ old_text_starts_[i] + old_texts_[i].length());
+ }
+ model->ModifyText(deletions, {new_text_}, {new_text_start_},
+ {new_cursor_pos_, new_cursor_pos_}, {});
}
// Try to merge the |edit| into this edit and returns true on success. The
@@ -73,24 +108,27 @@ class Edit {
Edit(Type type,
MergeType merge_type,
- const base::string16& old_text,
- size_t old_text_start,
- gfx::Range old_selection,
+ std::vector<base::string16> old_texts,
+ std::vector<size_t> old_text_starts,
+ gfx::Range old_primary_selection,
+ std::vector<gfx::Range> old_secondary_selections,
bool delete_backward,
size_t new_cursor_pos,
const base::string16& new_text,
size_t new_text_start)
: type_(type),
merge_type_(merge_type),
- old_text_(old_text),
- old_text_start_(old_text_start),
- old_selection_(old_selection),
+ old_texts_(old_texts),
+ old_text_starts_(old_text_starts),
+ old_primary_selection_(old_primary_selection),
+ old_secondary_selections_(old_secondary_selections),
delete_backward_(delete_backward),
new_cursor_pos_(new_cursor_pos),
new_text_(new_text),
new_text_start_(new_text_start) {}
- // Each type of edit provides its own specific merge implementation.
+ // Each type of edit provides its own specific merge implementation. Assumes
+ // |edit| occurs after |this|.
virtual bool DoMerge(const Edit* edit) = 0;
Type type() const { return type_; }
@@ -101,9 +139,6 @@ class Edit {
// Should this edit be forcibly merged with the previous edit?
bool force_merge() const { return merge_type_ == MergeType::kForceMerge; }
- // Returns the end index of the |old_text_|.
- size_t old_text_end() const { return old_text_start_ + old_text_.length(); }
-
// Returns the end index of the |new_text_|.
size_t new_text_end() const { return new_text_start_ + new_text_.length(); }
@@ -111,32 +146,43 @@ class Edit {
// where an omnibox autocomplete string is set after a new character is typed.
void MergeReplace(const Edit* edit) {
CHECK_EQ(Type::kReplace, edit->type_);
- CHECK_EQ(0U, edit->old_text_start_);
+ CHECK_EQ(1U, edit->old_text_starts_.size());
+ CHECK_EQ(0U, edit->old_text_starts_[0]);
CHECK_EQ(0U, edit->new_text_start_);
- base::string16 old_text = edit->old_text_;
- old_text.erase(new_text_start_, new_text_.length());
- old_text.insert(old_text_start_, old_text_);
- // SetText() replaces entire text. Set |old_text_| to the entire
- // replaced text with |this| edit undone.
- old_text_ = old_text;
- old_text_start_ = edit->old_text_start_;
- delete_backward_ = false;
- new_text_ = edit->new_text_;
- new_text_start_ = edit->new_text_start_;
+ // We need to compute the merged edit's |old_texts_| by undoing this edit.
+ // Otherwise, |old_texts_| would be the autocompleted text following the
+ // user input. E.g., given goo|[gle.com], when the user types 'g', the text
+ // updates to goog|[le.com]. If we leave old_texts_ unchanged as 'gle.com',
+ // then undoing will result in 'gle.com' instead of 'goo|[gle.com]'
+ base::string16 old_texts = edit->old_texts_[0];
+ // Remove |new_text_|.
+ old_texts.erase(new_text_start_, new_text_.length());
+ // Add |old_texts_| in reverse order since we're undoing an edit.
+ for (size_t i = old_texts_.size(); i != 0; i--)
+ old_texts.insert(old_text_starts_[i - 1], old_texts_[i - 1]);
+
merge_type_ = MergeType::kDoNotMerge;
+ old_texts_ = {old_texts};
+ old_text_starts_ = {0};
+ delete_backward_ = false;
+ new_cursor_pos_ = edit->new_cursor_pos_;
+ new_text_ = edit->new_text_;
+ new_text_start_ = 0;
}
Type type_;
// The type of merging allowed.
MergeType merge_type_;
- // Deleted text by this edit.
- base::string16 old_text_;
- // The index of |old_text_|.
- size_t old_text_start_;
- // The range of the text selection prior to the edit.
- gfx::Range old_selection_;
+ // Deleted texts ordered with decreasing indices.
+ std::vector<base::string16> old_texts_;
+ // The indices of |old_texts_|.
+ std::vector<size_t> old_text_starts_;
+ // The text selection ranges prior to the edit. |old_primary_selection_|
+ // represents the selection associated with the cursor.
+ gfx::Range old_primary_selection_;
+ std::vector<gfx::Range> old_secondary_selections_;
// True if the deletion is made backward.
bool delete_backward_;
// New cursor position.
@@ -149,100 +195,128 @@ class Edit {
DISALLOW_COPY_AND_ASSIGN(Edit);
};
+// Insert text at a given position. Assumes 1) no previous selection and 2) the
+// insertion is at the cursor, which will advance by the insertion length.
class InsertEdit : public Edit {
public:
InsertEdit(bool mergeable, const base::string16& new_text, size_t at)
: Edit(Type::kInsert,
mergeable ? MergeType::kMergeable : MergeType::kDoNotMerge,
- base::string16(),
- at,
- gfx::Range(at, at),
- false /* N/A */,
- at + new_text.length() /* new cursor */,
- new_text,
- at) {}
-
- // Edit implementation.
+ {} /* old_texts */,
+ {} /* old_text_starts */,
+ {gfx::Range(at, at)} /* old_primary_selection */,
+ {} /* old_secondary_selections */,
+ false /* delete_backward */,
+ at + new_text.length() /* new_cursor_pos */,
+ new_text /* new_text */,
+ at /* new_text_start */) {}
+
+ // Merge if |edit| is an insertion continuing forward where |this| ended. E.g.
+ // If |this| changed "ab|c" to "abX|c", an edit to "abXY|c" can be merged.
bool DoMerge(const Edit* edit) override {
+ // Reject other edit types, and inserts starting somewhere other than where
+ // this insert ended.
if (edit->type() != Type::kInsert ||
new_text_end() != edit->new_text_start_)
return false;
- // If continuous edit, merge it.
- // TODO(oshima): gtk splits edits between whitespace. Find out what
- // we want to here and implement if necessary.
new_text_ += edit->new_text_;
new_cursor_pos_ = edit->new_cursor_pos_;
return true;
}
};
+// Delete one or more ranges and do a single insertion. The insertion need not
+// be adjacent to the deletions (e.g. drag & drop).
class ReplaceEdit : public Edit {
public:
ReplaceEdit(MergeType merge_type,
- const base::string16& old_text,
- size_t old_text_start,
- gfx::Range old_selection,
+ std::vector<base::string16> old_texts,
+ std::vector<size_t> old_text_starts,
+ gfx::Range old_primary_selection,
+ std::vector<gfx::Range> old_secondary_selections,
bool backward,
size_t new_cursor_pos,
const base::string16& new_text,
size_t new_text_start)
: Edit(Type::kReplace,
merge_type,
- old_text,
- old_text_start,
- old_selection,
+ old_texts,
+ old_text_starts,
+ old_primary_selection,
+ old_secondary_selections,
backward,
new_cursor_pos,
new_text,
new_text_start) {}
- // Edit implementation.
+ // Merge if |edit| is an insertion or replacement continuing forward where
+ // |this| ended. E.g. If |this| changed "a|bc" to "aX|c", edits to "aXY|" or
+ // "aXYc" can be merged. Drag and drops are marked kDoNotMerge and should not
+ // get here.
bool DoMerge(const Edit* edit) override {
- if (edit->type() == Type::kDelete ||
- new_text_end() != edit->old_text_start_ ||
- edit->old_text_start_ != edit->new_text_start_)
+ // Reject deletions, replacements deleting multiple ranges, and edits
+ // inserting or deleting text somewhere other than where this edit ended.
+ if (edit->type() == Type::kDelete || edit->old_texts_.size() > 1 ||
+ new_text_end() != edit->new_text_start_ ||
+ (!edit->old_text_starts_.empty() &&
+ new_text_end() != edit->old_text_starts_[0]))
return false;
- old_text_ += edit->old_text_;
+ if (edit->old_texts_.size() == 1)
+ old_texts_[0] += edit->old_texts_[0];
new_text_ += edit->new_text_;
new_cursor_pos_ = edit->new_cursor_pos_;
return true;
}
};
+// Delete possibly multiple texts.
class DeleteEdit : public Edit {
public:
DeleteEdit(bool mergeable,
- const base::string16& text,
- size_t text_start,
+ std::vector<base::string16> texts,
+ std::vector<size_t> text_starts,
+ gfx::Range old_primary_selection,
+ std::vector<gfx::Range> old_secondary_selections,
bool backward,
- gfx::Range old_selection)
+ size_t new_cursor_pos)
: Edit(Type::kDelete,
mergeable ? MergeType::kMergeable : MergeType::kDoNotMerge,
- text,
- text_start,
- old_selection,
+ texts,
+ text_starts,
+ old_primary_selection,
+ old_secondary_selections,
backward,
- text_start,
- base::string16(),
- text_start) {}
+ new_cursor_pos,
+ base::string16() /* new_text */,
+ 0 /* new_text_start */) {}
- // Edit implementation.
+ // Merge if |edit| is a deletion continuing in the same direction and position
+ // where |this| ended. E.g. If |this| changed "ab|c" to "a|c" an edit to "|c"
+ // can be merged.
bool DoMerge(const Edit* edit) override {
if (edit->type() != Type::kDelete)
return false;
+ // Deletions with selections are marked kDoNotMerge and should not get here.
+ DCHECK(old_secondary_selections_.empty());
+ DCHECK(old_primary_selection_.is_empty());
+ DCHECK(edit->old_secondary_selections_.empty());
+ DCHECK(edit->old_primary_selection_.is_empty());
if (delete_backward_) {
- // backspace can be merged only with backspace at the same position.
- if (!edit->delete_backward_ || old_text_start_ != edit->old_text_end())
+ // Backspace can be merged only with backspace at the same position.
+ if (!edit->delete_backward_ ||
+ old_text_starts_[0] !=
+ edit->old_text_starts_[0] + edit->old_texts_[0].length())
return false;
- old_text_start_ = edit->old_text_start_;
- old_text_ = edit->old_text_ + old_text_;
+ old_text_starts_[0] = edit->old_text_starts_[0];
+ old_texts_[0] = edit->old_texts_[0] + old_texts_[0];
new_cursor_pos_ = edit->new_cursor_pos_;
} else {
- // delete can be merged only with delete at the same position.
- if (edit->delete_backward_ || old_text_start_ != edit->old_text_start_)
+ // Delete can be merged only with delete at the same position.
+ if (edit->delete_backward_ ||
+ old_text_starts_[0] != edit->old_text_starts_[0])
return false;
- old_text_ += edit->old_text_;
+ old_texts_[0] += edit->old_texts_[0];
}
return true;
}
@@ -315,7 +389,8 @@ TextfieldModel::~TextfieldModel() {
ClearComposition();
}
-bool TextfieldModel::SetText(const base::string16& new_text) {
+bool TextfieldModel::SetText(const base::string16& new_text,
+ size_t cursor_position) {
using MergeType = internal::MergeType;
bool changed = false;
if (HasCompositionText()) {
@@ -325,14 +400,11 @@ bool TextfieldModel::SetText(const base::string16& new_text) {
if (text() != new_text) {
if (changed) // No need to remember composition.
Undo();
- // SetText moves the cursor to the end.
- size_t new_cursor = new_text.length();
// If there is a composition text, don't merge with previous edit.
// Otherwise, force merge the edits.
ExecuteAndRecordReplace(
changed ? MergeType::kDoNotMerge : MergeType::kForceMerge,
- gfx::Range(0, text().length()), new_cursor, new_text, 0U);
- render_text_->SetCursorPosition(new_cursor);
+ {gfx::Range(0, text().length())}, cursor_position, new_text, 0U);
}
ClearSelection();
return changed;
@@ -372,7 +444,7 @@ bool TextfieldModel::Delete(bool add_to_kill_buffer) {
gfx::Range range_to_delete(cursor_position, next_grapheme_index);
if (add_to_kill_buffer)
SetKillBuffer(GetTextFromRange(range_to_delete));
- ExecuteAndRecordDelete(range_to_delete, true);
+ ExecuteAndRecordDelete({range_to_delete}, true);
return true;
}
return false;
@@ -400,7 +472,7 @@ bool TextfieldModel::Backspace(bool add_to_kill_buffer) {
PlatformStyle::RangeToDeleteBackwards(text(), cursor_position));
if (add_to_kill_buffer)
SetKillBuffer(GetTextFromRange(range_to_delete));
- ExecuteAndRecordDelete(range_to_delete, true);
+ ExecuteAndRecordDelete({range_to_delete}, true);
return true;
}
return false;
@@ -446,10 +518,10 @@ base::string16 TextfieldModel::GetSelectedText() const {
return GetTextFromRange(render_text_->selection());
}
-void TextfieldModel::SelectRange(const gfx::Range& range) {
+void TextfieldModel::SelectRange(const gfx::Range& range, bool primary) {
if (HasCompositionText())
ConfirmCompositionText();
- render_text_->SelectRange(range);
+ render_text_->SelectRange(range, primary);
}
void TextfieldModel::SelectSelectionModel(const gfx::SelectionModel& sel) {
@@ -526,7 +598,8 @@ bool TextfieldModel::Redo() {
}
bool TextfieldModel::Cut() {
- if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
+ if (!HasCompositionText() && HasSelection(true) &&
+ !render_text_->obscured()) {
ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
.WriteText(GetSelectedText());
DeleteSelection();
@@ -536,7 +609,8 @@ bool TextfieldModel::Cut() {
}
bool TextfieldModel::Copy() {
- if (!HasCompositionText() && HasSelection() && !render_text_->obscured()) {
+ if (!HasCompositionText() && HasSelection(true) &&
+ !render_text_->obscured()) {
ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
.WriteText(GetSelectedText());
return true;
@@ -605,23 +679,30 @@ bool TextfieldModel::Yank() {
return false;
}
-bool TextfieldModel::HasSelection() const {
- return !render_text_->selection().is_empty();
+bool TextfieldModel::HasSelection(bool primary_only) const {
+ if (primary_only)
+ return !render_text_->selection().is_empty();
+ auto selections = render_text_->GetAllSelections();
+ return std::any_of(
+ selections.begin(), selections.end(),
+ [](const auto& selection) { return !selection.is_empty(); });
}
void TextfieldModel::DeleteSelection() {
DCHECK(!HasCompositionText());
DCHECK(HasSelection());
- ExecuteAndRecordDelete(render_text_->selection(), false);
+ ExecuteAndRecordDelete(render_text_->GetAllSelections(), false);
}
-void TextfieldModel::DeleteSelectionAndInsertTextAt(
+void TextfieldModel::DeletePrimarySelectionAndInsertTextAt(
const base::string16& new_text,
size_t position) {
using MergeType = internal::MergeType;
if (HasCompositionText())
CancelCompositionText();
- ExecuteAndRecordReplace(MergeType::kDoNotMerge, render_text_->selection(),
+ // We don't use |ExecuteAndRecordReplaceSelection| because that assumes the
+ // insertion occurs at the cursor.
+ ExecuteAndRecordReplace(MergeType::kDoNotMerge, {render_text_->selection()},
position + new_text.length(), new_text, position);
}
@@ -774,13 +855,25 @@ void TextfieldModel::ClearRedoHistory() {
edit_history_.erase(delete_start, edit_history_.end());
}
-void TextfieldModel::ExecuteAndRecordDelete(gfx::Range range, bool mergeable) {
- size_t old_text_start = range.GetMin();
- const base::string16 old_text = text().substr(old_text_start, range.length());
- bool backward = range.is_reversed();
- gfx::Range curr_selection = render_text_->selection();
+void TextfieldModel::ExecuteAndRecordDelete(std::vector<gfx::Range> ranges,
+ bool mergeable) {
+ // We need only check replacement_ranges[0] as |delete_backwards_| is
+ // irrelevant for multi-range deletions which can't be merged anyways.
+ const bool backward = ranges[0].is_reversed();
+ order_ranges(&ranges);
+
+ std::vector<base::string16> old_texts;
+ std::vector<size_t> old_text_starts;
+ for (const auto& range : ranges) {
+ old_texts.push_back(GetTextFromRange(range));
+ old_text_starts.push_back(range.GetMin());
+ }
+
+ size_t cursor_pos = adjust_position_for_removals(GetCursorPosition(), ranges);
+
auto edit = std::make_unique<internal::DeleteEdit>(
- mergeable, old_text, old_text_start, backward, curr_selection);
+ mergeable, old_texts, old_text_starts, render_text_->selection(),
+ render_text_->secondary_selections(), backward, cursor_pos);
edit->Redo(this);
AddOrMergeEditHistory(std::move(edit));
}
@@ -788,22 +881,36 @@ void TextfieldModel::ExecuteAndRecordDelete(gfx::Range range, bool mergeable) {
void TextfieldModel::ExecuteAndRecordReplaceSelection(
internal::MergeType merge_type,
const base::string16& new_text) {
- size_t new_text_start = render_text_->selection().GetMin();
+ auto replacement_ranges = render_text_->GetAllSelections();
+ size_t new_text_start =
+ adjust_position_for_removals(GetCursorPosition(), replacement_ranges);
size_t new_cursor_pos = new_text_start + new_text.length();
- ExecuteAndRecordReplace(merge_type, render_text_->selection(), new_cursor_pos,
+
+ ExecuteAndRecordReplace(merge_type, replacement_ranges, new_cursor_pos,
new_text, new_text_start);
}
-void TextfieldModel::ExecuteAndRecordReplace(internal::MergeType merge_type,
- gfx::Range replacement_range,
- size_t new_cursor_pos,
- const base::string16& new_text,
- size_t new_text_start) {
- size_t old_text_start = replacement_range.GetMin();
- bool backward = replacement_range.is_reversed();
+void TextfieldModel::ExecuteAndRecordReplace(
+ internal::MergeType merge_type,
+ std::vector<gfx::Range> replacement_ranges,
+ size_t new_cursor_pos,
+ const base::string16& new_text,
+ size_t new_text_start) {
+ // We need only check replacement_ranges[0] as |delete_backwards_| is
+ // irrelevant for multi-range deletions which can't be merged anyways.
+ const bool backward = replacement_ranges[0].is_reversed();
+ order_ranges(&replacement_ranges);
+
+ std::vector<base::string16> old_texts;
+ std::vector<size_t> old_text_starts;
+ for (const auto& range : replacement_ranges) {
+ old_texts.push_back(GetTextFromRange(range));
+ old_text_starts.push_back(range.GetMin());
+ }
+
auto edit = std::make_unique<internal::ReplaceEdit>(
- merge_type, GetTextFromRange(replacement_range), old_text_start,
- render_text_->selection(), backward, new_cursor_pos, new_text,
+ merge_type, old_texts, old_text_starts, render_text_->selection(),
+ render_text_->secondary_selections(), backward, new_cursor_pos, new_text,
new_text_start);
edit->Redo(this);
AddOrMergeEditHistory(std::move(edit));
@@ -838,23 +945,28 @@ void TextfieldModel::AddOrMergeEditHistory(
}
}
-void TextfieldModel::ModifyText(size_t delete_from,
- size_t delete_to,
- const base::string16& new_text,
- size_t new_text_insert_at,
- gfx::Range selection) {
- DCHECK_LE(delete_from, delete_to);
+void TextfieldModel::ModifyText(
+ const std::vector<gfx::Range>& deletions,
+ const std::vector<base::string16>& insertion_texts,
+ const std::vector<size_t>& insertion_positions,
+ const gfx::Range& primary_selection,
+ const std::vector<gfx::Range>& secondary_selections) {
+ DCHECK_EQ(insertion_texts.size(), insertion_positions.size());
base::string16 old_text = text();
ClearComposition();
- if (delete_from != delete_to)
- SetRenderTextText(old_text.erase(delete_from, delete_to - delete_from));
- if (!new_text.empty())
- SetRenderTextText(old_text.insert(new_text_insert_at, new_text));
- if (selection.start() == selection.end()) {
- render_text_->SetCursorPosition(selection.start());
- } else {
- render_text_->SelectRange(selection);
- }
+
+ for (auto deletion : deletions)
+ old_text.erase(deletion.start(), deletion.length());
+ for (size_t i = 0; i < insertion_texts.size(); ++i)
+ old_text.insert(insertion_positions[i], insertion_texts[i]);
+ SetRenderTextText(old_text);
+
+ if (primary_selection.start() == primary_selection.end())
+ render_text_->SetCursorPosition(primary_selection.start());
+ else
+ render_text_->SelectRange(primary_selection);
+ for (auto secondary_selection : secondary_selections)
+ render_text_->SelectRange(secondary_selection, false);
}
void TextfieldModel::SetRenderTextText(const base::string16& text) {
diff --git a/chromium/ui/views/controls/textfield/textfield_model.h b/chromium/ui/views/controls/textfield/textfield_model.h
index 0cc866ce613..9873bc160e9 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.h
+++ b/chromium/ui/views/controls/textfield/textfield_model.h
@@ -65,12 +65,17 @@ class VIEWS_EXPORT TextfieldModel {
// Edit related methods.
const base::string16& text() const { return render_text_->text(); }
- // Sets the text. Returns true if the text has been modified. The current
- // composition text will be confirmed first. Setting the same text will not
- // add edit history because it's not user visible change nor user-initiated
- // change. This allow a client code to set the same text multiple times
- // without worrying about messing edit history.
- bool SetText(const base::string16& new_text);
+ // Sets the text. Returns true if the text was modified. The current
+ // composition text will be confirmed first. Setting the same text, even with
+ // an updated |cursor_position|, will neither add edit history nor change the
+ // cursor because it's neither a user visible change nor user-initiated
+ // change. This allows clients to set the same text multiple times without
+ // messing up edit history. The resulting history edit will have
+ // |new_cursor_pos| set to |cursor_position|. This is important even if
+ // subsequent calls will override the cursor position because updating the
+ // cursor alone won't update the edit history. I.e. the cursor position after
+ // applying or redoing the edit will be determined by |cursor_position|.
+ bool SetText(const base::string16& new_text, size_t cursor_position);
gfx::RenderText* render_text() { return render_text_.get(); }
@@ -138,13 +143,15 @@ class VIEWS_EXPORT TextfieldModel {
// Selection related methods.
- // Returns the selected text.
+ // Returns the primary selected text associated with the cursor. Does not
+ // return secondary selections.
base::string16 GetSelectedText() const;
- // The current composition text will be confirmed. The selection starts with
- // the range's start position, and ends with the range's end position,
- // therefore the cursor position becomes the end position.
- void SelectRange(const gfx::Range& range);
+ // The current composition text will be confirmed. If |primary| is true, the
+ // selection starts with the range's start position and ends with the range's
+ // end position; therefore the cursor position becomes the end position. If
+ // |primary| is false, then the selection is not associated with the cursor.
+ void SelectRange(const gfx::Range& range, bool primary = true);
// The current composition text will be confirmed.
// render_text_'s selection model is set to |sel|.
@@ -200,16 +207,17 @@ class VIEWS_EXPORT TextfieldModel {
bool Yank();
// Tells if any text is selected, even if the selection is in composition
- // text.
- bool HasSelection() const;
+ // text. |primary_only| indicates whether secondary selections should also be
+ // considered.
+ bool HasSelection(bool primary_only = false) const;
// Deletes the selected text. This method shouldn't be called with
// composition text.
void DeleteSelection();
// Deletes the selected text (if any) and insert text at given position.
- void DeleteSelectionAndInsertTextAt(const base::string16& new_text,
- size_t position);
+ void DeletePrimarySelectionAndInsertTextAt(const base::string16& new_text,
+ size_t position);
// Retrieves the text content in a given range.
base::string16 GetTextFromRange(const gfx::Range& range) const;
@@ -256,23 +264,25 @@ class VIEWS_EXPORT TextfieldModel {
FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_CutCopyPasteTest);
FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_ReplaceTest);
- // Insert the given |new_text|. |mergeable| indicates if this insert operation
- // can be merged with previous edits in the history.
+ // Insert the given |new_text| at the cursor. |mergeable| indicates if this
+ // operation can be merged with previous edits in the history. Will delete any
+ // selected text.
void InsertTextInternal(const base::string16& new_text, bool mergeable);
- // Replace the current text with the given |new_text|. |mergeable| indicates
- // if this replace operation can be merged with previous edits in the history.
+ // Replace the current selected text with the given |new_text|. |mergeable|
+ // indicates if this operation can be merged with previous edits in the
+ // history.
void ReplaceTextInternal(const base::string16& new_text, bool mergeable);
// Clears redo history.
void ClearRedoHistory();
// Executes and records edit operations.
- void ExecuteAndRecordDelete(gfx::Range range, bool mergeable);
+ void ExecuteAndRecordDelete(std::vector<gfx::Range> ranges, bool mergeable);
void ExecuteAndRecordReplaceSelection(internal::MergeType merge_type,
const base::string16& new_text);
void ExecuteAndRecordReplace(internal::MergeType merge_type,
- gfx::Range replacement_range,
+ std::vector<gfx::Range> replacement_range,
size_t new_cursor_pos,
const base::string16& new_text,
size_t new_text_start);
@@ -282,15 +292,20 @@ class VIEWS_EXPORT TextfieldModel {
void AddOrMergeEditHistory(std::unique_ptr<internal::Edit> edit);
// Modify the text buffer in following way:
- // 1) Delete the string from |delete_from| to |delete_to|.
- // 2) Insert the |new_text| at the index |new_text_insert_at|.
- // Note that the index is after deletion.
- // 3) Select |selection|.
- void ModifyText(size_t delete_from,
- size_t delete_to,
- const base::string16& new_text,
- size_t new_text_insert_at,
- gfx::Range selection);
+ // 1) Delete the |deletions|.
+ // 2) Insert the |insertion_texts| at the |insertion_positions|.
+ // 3) Select |primary_selection| and |secondary_selections|.
+ // Deletions and insertions are applied in order and affect later edit
+ // indices. E.g., given 'xyz', inserting 'A' at 1 and 'B' at 2 will result in
+ // 'xAByz', not 'xAyBz'. On the other hand, inserting 'B' at 2 then 'A' at 1
+ // will result in 'xAyBz'. Thus, for applying or redoing edits, they should be
+ // ordered with increasing indices; while for undoing edits, they should be
+ // ordered decreasing.
+ void ModifyText(const std::vector<gfx::Range>& deletions,
+ const std::vector<base::string16>& insertion_texts,
+ const std::vector<size_t>& insertion_positions,
+ const gfx::Range& primary_selection,
+ const std::vector<gfx::Range>& secondary_selections);
// Calls render_text->SetText() and delegate's callback.
void SetRenderTextText(const base::string16& text);
diff --git a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
index 91d5f62a0c7..d9b29c3f0fb 100644
--- a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
@@ -57,10 +57,27 @@ class TextfieldModelTest : public ViewsTestBase,
protected:
void ResetModel(TextfieldModel* model) const {
- model->SetText(base::string16());
+ model->SetText(base::string16(), 0);
model->ClearEditHistory();
}
+ const std::vector<base::string16> GetAllSelectionTexts(
+ TextfieldModel* model) const {
+ std::vector<base::string16> selected_texts;
+ for (auto range : model->render_text()->GetAllSelections())
+ selected_texts.push_back(model->GetTextFromRange(range));
+ return selected_texts;
+ }
+
+ void VerifyAllSelectionTexts(
+ TextfieldModel* model,
+ std::vector<std::string> expected_selected_texts) const {
+ std::vector<base::string16> selected_texts = GetAllSelectionTexts(model);
+ EXPECT_EQ(expected_selected_texts.size(), selected_texts.size());
+ for (size_t i = 0; i < selected_texts.size(); ++i)
+ EXPECT_STR_EQ(expected_selected_texts[i], selected_texts[i]);
+ }
+
bool composition_text_confirmed_or_cleared_ = false;
private:
@@ -191,7 +208,7 @@ TEST_F(TextfieldModelTest, EditString_ComplexScript) {
#endif
// Test cursor position and deletion for Hindi Virama.
- model.SetText(base::WideToUTF16(L"\x0D38\x0D4D\x0D15\x0D16\x0D2E"));
+ model.SetText(base::WideToUTF16(L"\x0D38\x0D4D\x0D15\x0D16\x0D2E"), 0);
model.MoveCursorTo(0);
EXPECT_EQ(0U, model.GetCursorPosition());
@@ -210,7 +227,7 @@ TEST_F(TextfieldModelTest, EditString_ComplexScript) {
#endif
model.SetText(
- base::WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9"));
+ base::WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9"), 0);
model.MoveCursorTo(0);
EXPECT_TRUE(model.Delete());
EXPECT_TRUE(model.Delete());
@@ -220,7 +237,7 @@ TEST_F(TextfieldModelTest, EditString_ComplexScript) {
// The first 2 characters are not strong directionality characters.
model.SetText(
- base::WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC"));
+ base::WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC"), 0);
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
EXPECT_TRUE(model.Backspace());
EXPECT_EQ(base::WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"),
@@ -229,7 +246,7 @@ TEST_F(TextfieldModelTest, EditString_ComplexScript) {
// Halfwidth katakana ダ:
// "HALFWIDTH KATAKANA LETTER TA" + "HALFWIDTH KATAKANA VOICED SOUND MARK"
// ("ABC" prefix as sanity check that the entire string isn't deleted).
- model.SetText(base::WideToUTF16(L"ABC\xFF80\xFF9E"));
+ model.SetText(base::WideToUTF16(L"ABC\xFF80\xFF9E"), 0);
model.MoveCursorTo(model.text().length());
model.Backspace();
#if defined(OS_MACOSX)
@@ -244,7 +261,7 @@ TEST_F(TextfieldModelTest, EditString_ComplexScript) {
// Emoji with Fitzpatrick modifier:
// 'BOY' + 'EMOJI MODIFIER FITZPATRICK TYPE-5'
- model.SetText(base::WideToUTF16(L"\U0001F466\U0001F3FE"));
+ model.SetText(base::WideToUTF16(L"\U0001F466\U0001F3FE"), 0);
model.MoveCursorTo(model.text().length());
model.Backspace();
#if defined(OS_MACOSX)
@@ -316,6 +333,23 @@ TEST_F(TextfieldModelTest, Selection) {
gfx::SELECTION_NONE);
EXPECT_EQ(3U, model.GetCursorPosition());
+ // Select multiple ranges and move cursor.
+ model.SelectRange(gfx::Range(1U, 3U));
+ model.SelectRange(gfx::Range(5U, 4U), false);
+ EXPECT_STR_EQ("EL", model.GetSelectedText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
+ EXPECT_TRUE(model.GetSelectedText().empty());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+ model.SelectRange(gfx::Range(1U, 3U));
+ model.SelectRange(gfx::Range(4U, 5U), false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
+ EXPECT_TRUE(model.GetSelectedText().empty());
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+
// Select all and move cursor.
model.SelectAll(false);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
@@ -378,9 +412,9 @@ TEST_F(TextfieldModelTest, Selection_BidiWithNonSpacingMarks) {
// In case of "aBc", this test shows how to select "aB" or "Bc", assume 'B' is
// an RTL character.
- model.SetText(
- base::WideToUTF16(L"a\x05E9"
- L"b"));
+ model.SetText(base::WideToUTF16(L"a\x05E9"
+ L"b"),
+ 0);
model.MoveCursorTo(0);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
gfx::SELECTION_RETAIN);
@@ -479,6 +513,56 @@ TEST_F(TextfieldModelTest, SelectionAndEdit) {
EXPECT_STR_EQ("BEE", model.text());
}
+TEST_F(TextfieldModelTest, SelectionAndEdit_WithSecondarySelection) {
+ // Backspace
+ TextfieldModel model(nullptr);
+ model.Append(base::ASCIIToUTF16("asynchronous promises make the moon spin?"));
+ model.SelectRange(gfx::Range(0U, 4U));
+ model.SelectRange(gfx::Range(17U, 19U), false);
+ model.SelectRange(gfx::Range(15U, 7U), false);
+ model.SelectRange(gfx::Range(41U, 20U), false);
+ EXPECT_TRUE(model.Backspace());
+ EXPECT_STR_EQ("chrome", model.text());
+ EXPECT_TRUE(model.GetSelectedText().empty());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+
+ // Delete with an empty primary selection
+ model.Append(base::ASCIIToUTF16(" is constructor overloading bad?"));
+ model.SelectRange(gfx::Range(1U, 1U));
+ model.SelectRange(gfx::Range(22U, 12U), false);
+ model.SelectRange(gfx::Range(26U, 23U), false);
+ model.SelectRange(gfx::Range(27U, 38U), false);
+ EXPECT_TRUE(model.Delete());
+ EXPECT_STR_EQ("chrome is cool", model.text());
+ EXPECT_TRUE(model.GetSelectedText().empty());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+
+ // Insert
+ model.Append(base::ASCIIToUTF16(" are inherited classes heavy?"));
+ model.SelectRange(gfx::Range(27U, 16U));
+ model.SelectRange(gfx::Range(41U, 34U), false);
+ model.SelectRange(gfx::Range(42U, 43U), false);
+ model.InsertChar('n');
+ EXPECT_STR_EQ("chrome is cool and classy", model.text());
+ EXPECT_TRUE(model.GetSelectedText().empty());
+ EXPECT_EQ(17U, model.GetCursorPosition());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+
+ // Replace
+ model.Append(
+ base::ASCIIToUTF16("help! why can't i instantiate an abstract sun!?"));
+ model.SelectRange(gfx::Range(71U, 72U));
+ model.SelectRange(gfx::Range(30U, 70U), false);
+ model.SelectRange(gfx::Range(29U, 25U), false);
+ model.ReplaceChar('!');
+ EXPECT_STR_EQ("chrome is cool and classy!!!", model.text());
+ EXPECT_TRUE(model.GetSelectedText().empty());
+ EXPECT_EQ(28U, model.GetCursorPosition());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+}
+
TEST_F(TextfieldModelTest, Word) {
TextfieldModel model(nullptr);
model.Append(
@@ -577,21 +661,33 @@ TEST_F(TextfieldModelTest, Word) {
TEST_F(TextfieldModelTest, SetText) {
TextfieldModel model(nullptr);
model.Append(base::ASCIIToUTF16("HELLO"));
+
+ // SetText moves cursor to the indicated position.
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
- model.SetText(base::ASCIIToUTF16("GOODBYE"));
+ model.SetText(base::ASCIIToUTF16("GOODBYE"), 6);
EXPECT_STR_EQ("GOODBYE", model.text());
- // SetText move the cursor to the end of the new text.
- EXPECT_EQ(7U, model.GetCursorPosition());
+ EXPECT_EQ(6U, model.GetCursorPosition());
+ model.SetText(base::ASCIIToUTF16("SUNSET"), 6);
+ EXPECT_STR_EQ("SUNSET", model.text());
+ EXPECT_EQ(6U, model.GetCursorPosition());
model.SelectAll(false);
- EXPECT_STR_EQ("GOODBYE", model.GetSelectedText());
+ EXPECT_STR_EQ("SUNSET", model.GetSelectedText());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
- EXPECT_EQ(7U, model.GetCursorPosition());
+ EXPECT_EQ(6U, model.GetCursorPosition());
- model.SetText(base::ASCIIToUTF16("BYE"));
- // Setting shorter string moves the cursor to the end of the new string.
+ // Setting text to the current text should not modify the cursor position.
+ model.SetText(base::ASCIIToUTF16("SUNSET"), 3);
+ EXPECT_STR_EQ("SUNSET", model.text());
+ EXPECT_EQ(6U, model.GetCursorPosition());
+
+ // Setting text that's shorter than the indicated cursor moves the cursor to
+ // the text end.
+ model.SetText(base::ASCIIToUTF16("BYE"), 5);
EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_EQ(base::string16(), model.GetSelectedText());
- model.SetText(base::string16());
+
+ // SetText with empty string.
+ model.SetText(base::string16(), 0);
EXPECT_EQ(0U, model.GetCursorPosition());
}
@@ -615,7 +711,7 @@ TEST_F(TextfieldModelTest, Clipboard) {
EXPECT_EQ(11U, model.GetCursorPosition());
// Copy with an empty selection should do nothing.
- model.Copy();
+ EXPECT_FALSE(model.Copy());
clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
EXPECT_EQ(initial_clipboard_text, clipboard_text);
EXPECT_STR_EQ("HELLO WORLD", model.text());
@@ -666,6 +762,132 @@ TEST_F(TextfieldModelTest, Clipboard) {
EXPECT_TRUE(model.Paste());
EXPECT_STR_EQ("HELLO HELLOHELLO", model.text());
EXPECT_EQ(16U, model.GetCursorPosition());
+
+ // Paste should replace the selection.
+ model.render_text()->SetObscured(false);
+ model.SetText(base::ASCIIToUTF16("It's time to say goodbye."), 0);
+ model.SelectRange({17, 24});
+ EXPECT_TRUE(model.Paste());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_STR_EQ("HELLO ", clipboard_text);
+ EXPECT_STR_EQ("It's time to say HELLO.", model.text());
+ EXPECT_EQ(22U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+
+ // Paste with an empty clipboard should not replace the selection.
+ ui::Clipboard::GetForCurrentThread()->Clear(ui::ClipboardBuffer::kCopyPaste);
+ model.SelectRange({5, 8});
+ EXPECT_FALSE(model.Paste());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_TRUE(clipboard_text.empty());
+ EXPECT_STR_EQ("It's time to say HELLO.", model.text());
+ EXPECT_EQ(8U, model.GetCursorPosition());
+ EXPECT_STR_EQ("tim", model.GetSelectedText());
+}
+
+TEST_F(TextfieldModelTest, Clipboard_WithSecondarySelections) {
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ const base::string16 initial_clipboard_text =
+ base::ASCIIToUTF16("initial text");
+ ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
+ .WriteText(initial_clipboard_text);
+
+ base::string16 clipboard_text;
+ TextfieldModel model(nullptr);
+ model.Append(base::ASCIIToUTF16("It's time to say HELLO."));
+
+ // Cut with multiple selections should copy only the primary selection but
+ // delete all selections.
+ model.SelectRange({0, 5});
+ model.SelectRange({13, 17}, false);
+ EXPECT_TRUE(model.Cut());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_STR_EQ("It's ", clipboard_text);
+ EXPECT_STR_EQ("time to HELLO.", model.text());
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+
+ // Copy with multiple selections should copy only the primary selection and
+ // retain multiple selections.
+ model.SelectRange({13, 8});
+ model.SelectRange({0, 4}, false);
+ EXPECT_TRUE(model.Copy());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_STR_EQ("HELLO", clipboard_text);
+ EXPECT_STR_EQ("time to HELLO.", model.text());
+ EXPECT_EQ(8U, model.GetCursorPosition());
+ EXPECT_TRUE(model.HasSelection());
+ VerifyAllSelectionTexts(&model, {"HELLO", "time"});
+
+ // Paste with multiple selections should paste at the primary selection and
+ // delete all selections.
+ model.SelectRange({0, 1});
+ model.SelectRange({5, 8}, false);
+ model.SelectRange({14, 14}, false);
+ EXPECT_TRUE(model.Paste());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_STR_EQ("HELLO", clipboard_text);
+ EXPECT_STR_EQ("HELLOime HELLO.", model.text());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.render_text()->secondary_selections().empty());
+
+ // Paste with multiple selections and an empty clipboard should not change the
+ // text or selections.
+ ui::Clipboard::GetForCurrentThread()->Clear(ui::ClipboardBuffer::kCopyPaste);
+ model.SelectRange({1, 2});
+ model.SelectRange({4, 5}, false);
+ EXPECT_FALSE(model.Paste());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_TRUE(clipboard_text.empty());
+ EXPECT_STR_EQ("HELLOime HELLO.", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"E", "O"});
+
+ // Cut with an empty primary selection and nonempty secondary selections
+ // should neither delete the secondary selection nor replace the clipboard.
+ ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
+ .WriteText(initial_clipboard_text);
+ model.SelectRange({2, 2});
+ model.SelectRange({4, 5}, false);
+ EXPECT_FALSE(model.Cut());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_STR_EQ("initial text", clipboard_text);
+ EXPECT_STR_EQ("HELLOime HELLO.", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"", "O"});
+
+ // Copy with an empty primary selection and nonempty secondary selections
+ // should not replace the clipboard.
+ EXPECT_FALSE(model.Copy());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_STR_EQ("initial text", clipboard_text);
+ EXPECT_STR_EQ("HELLOime HELLO.", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"", "O"});
+
+ // Paste with an empty primary selection, nonempty secondary selection, and
+ // empty clipboard should change neither the text nor the selections.
+ ui::Clipboard::GetForCurrentThread()->Clear(ui::ClipboardBuffer::kCopyPaste);
+ EXPECT_FALSE(model.Paste());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_TRUE(clipboard_text.empty());
+ EXPECT_STR_EQ("HELLOime HELLO.", model.text());
+ EXPECT_EQ(2U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"", "O"});
+
+ // Paste with an empty primary selection and nonempty secondary selections
+ // should paste at the primary selection and delete the secondary selections.
+ ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
+ .WriteText(initial_clipboard_text);
+ EXPECT_TRUE(model.Paste());
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &clipboard_text);
+ EXPECT_STR_EQ("initial text", clipboard_text);
+ EXPECT_STR_EQ("HEinitial textLLime HELLO.", model.text());
+ EXPECT_EQ(14U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
}
static void SelectWordTestVerifier(
@@ -734,9 +956,9 @@ TEST_F(TextfieldModelTest, SelectWordTest_MixScripts) {
word_and_cursor.emplace_back(L"\x5929", 14);
// The text consists of Ascii, Hebrew, Hindi with Virama sign, and Chinese.
- model.SetText(
- base::WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 "
- L"\x4E2D\x56FD\x82B1\x5929"));
+ model.SetText(base::WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 "
+ L"\x4E2D\x56FD\x82B1\x5929"),
+ 0);
for (size_t i = 0; i < word_and_cursor.size(); ++i) {
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
for (size_t j = 0; j < i; ++j)
@@ -871,42 +1093,57 @@ TEST_F(TextfieldModelTest, SelectRangeTest) {
gfx::Range range(0, 6);
EXPECT_FALSE(range.is_reversed());
model.SelectRange(range);
+ EXPECT_TRUE(model.HasSelection());
EXPECT_STR_EQ("HELLO ", model.GetSelectedText());
range = gfx::Range(6, 1);
EXPECT_TRUE(range.is_reversed());
model.SelectRange(range);
+ EXPECT_TRUE(model.HasSelection());
EXPECT_STR_EQ("ELLO ", model.GetSelectedText());
range = gfx::Range(2, 1000);
EXPECT_FALSE(range.is_reversed());
model.SelectRange(range);
+ EXPECT_TRUE(model.HasSelection());
EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText());
range = gfx::Range(1000, 3);
EXPECT_TRUE(range.is_reversed());
model.SelectRange(range);
+ EXPECT_TRUE(model.HasSelection());
EXPECT_STR_EQ("LO WORLD", model.GetSelectedText());
range = gfx::Range(0, 0);
EXPECT_TRUE(range.is_empty());
model.SelectRange(range);
+ EXPECT_FALSE(model.HasSelection());
EXPECT_TRUE(model.GetSelectedText().empty());
range = gfx::Range(3, 3);
EXPECT_TRUE(range.is_empty());
model.SelectRange(range);
+ EXPECT_FALSE(model.HasSelection());
EXPECT_TRUE(model.GetSelectedText().empty());
range = gfx::Range(1000, 100);
EXPECT_FALSE(range.is_empty());
model.SelectRange(range);
+ EXPECT_FALSE(model.HasSelection());
EXPECT_TRUE(model.GetSelectedText().empty());
range = gfx::Range(1000, 1000);
EXPECT_TRUE(range.is_empty());
model.SelectRange(range);
+ EXPECT_FALSE(model.HasSelection());
EXPECT_TRUE(model.GetSelectedText().empty());
+
+ EXPECT_TRUE(range.is_empty());
+ model.SelectRange({1, 5});
+ model.SelectRange({100, 7}, false);
+ EXPECT_TRUE(model.HasSelection());
+ EXPECT_STR_EQ("ELLO", model.GetSelectedText());
+ VerifyAllSelectionTexts(&model, {"ELLO", "ORLD"});
}
TEST_F(TextfieldModelTest, SelectionTest) {
@@ -994,6 +1231,16 @@ TEST_F(TextfieldModelTest, SelectSelectionModelTest) {
model.SelectSelectionModel(gfx::SelectionModel(1000, gfx::CURSOR_BACKWARD));
EXPECT_TRUE(model.GetSelectedText().empty());
+
+ gfx::SelectionModel mutliselection_selection_model{{2, 3},
+ gfx::CURSOR_BACKWARD};
+ mutliselection_selection_model.AddSecondarySelection({5, 4});
+ mutliselection_selection_model.AddSecondarySelection({1, 0});
+ mutliselection_selection_model.AddSecondarySelection({20, 9});
+ mutliselection_selection_model.AddSecondarySelection({6, 6});
+ model.SelectSelectionModel(mutliselection_selection_model);
+ EXPECT_STR_EQ("L", model.GetSelectedText());
+ VerifyAllSelectionTexts(&model, {"L", "O", "H", "LD", ""});
}
TEST_F(TextfieldModelTest, CompositionTextTest) {
@@ -1065,7 +1312,7 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
model.SetCompositionText(composition);
EXPECT_STR_EQ("1234567890", model.text());
- EXPECT_TRUE(model.SetText(base::ASCIIToUTF16("1234567890")));
+ EXPECT_TRUE(model.SetText(base::ASCIIToUTF16("1234567890"), 0));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
@@ -1123,7 +1370,7 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
composition_text_confirmed_or_cleared_ = false;
EXPECT_STR_EQ("1234567890-678-", model.text());
- model.SetText(base::string16());
+ model.SetText(base::string16(), 0);
model.SetCompositionText(composition);
model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
@@ -1145,7 +1392,7 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
composition_text_confirmed_or_cleared_ = false;
EXPECT_STR_EQ("676788678", model.text());
- model.SetText(base::string16());
+ model.SetText(base::string16(), 0);
model.SetCompositionText(composition);
model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
@@ -1268,7 +1515,7 @@ TEST_F(TextfieldModelTest, UndoRedo_BasicTest) {
EXPECT_EQ(1U, model.GetCursorPosition());
// Delete ===============================
- model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"), 0);
model.ClearEditHistory();
model.MoveCursorTo(2);
EXPECT_TRUE(model.Delete());
@@ -1300,31 +1547,34 @@ TEST_F(TextfieldModelTest, UndoRedo_BasicTest) {
TEST_F(TextfieldModelTest, UndoRedo_SetText) {
// This is to test the undo/redo behavior of omnibox.
TextfieldModel model(nullptr);
- model.InsertChar('w');
+ // Simulate typing www.y while www.google.com and www.youtube.com are
+ // autocompleted.
+ model.InsertChar('w'); // w|
EXPECT_STR_EQ("w", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
- model.SetText(base::ASCIIToUTF16("www.google.com"));
- EXPECT_EQ(14U, model.GetCursorPosition());
+ model.SetText(base::ASCIIToUTF16("www.google.com"), 1); // w|ww.google.com
+ model.SelectRange(gfx::Range(14, 1)); // w[ww.google.com]
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_STR_EQ("www.google.com", model.text());
- model.SelectRange(gfx::Range(14, 1));
- model.InsertChar('w');
+ model.InsertChar('w'); // ww|
EXPECT_STR_EQ("ww", model.text());
- model.SetText(base::ASCIIToUTF16("www.google.com"));
- model.SelectRange(gfx::Range(14, 2));
- model.InsertChar('w');
+ model.SetText(base::ASCIIToUTF16("www.google.com"), 2); // ww|w.google.com
+ model.SelectRange(gfx::Range(14, 2)); // ww[w.google.com]
+ model.InsertChar('w'); // www|
EXPECT_STR_EQ("www", model.text());
- model.SetText(base::ASCIIToUTF16("www.google.com"));
- model.SelectRange(gfx::Range(14, 3));
- model.InsertChar('.');
+ model.SetText(base::ASCIIToUTF16("www.google.com"), 3); // www|.google.com
+ model.SelectRange(gfx::Range(14, 3)); // www[.google.com]
+ model.InsertChar('.'); // www.|
EXPECT_STR_EQ("www.", model.text());
- model.SetText(base::ASCIIToUTF16("www.google.com"));
- model.SelectRange(gfx::Range(14, 4));
- model.InsertChar('y');
+ model.SetText(base::ASCIIToUTF16("www.google.com"), 4); // www.|google.com
+ model.SelectRange(gfx::Range(14, 4)); // www.[google.com]
+ model.InsertChar('y'); // www.y|
EXPECT_STR_EQ("www.y", model.text());
- model.SetText(base::ASCIIToUTF16("www.youtube.com"));
+ model.SetText(base::ASCIIToUTF16("www.youtube.com"), 5); // www.y|outube.com
EXPECT_STR_EQ("www.youtube.com", model.text());
- EXPECT_EQ(15U, model.GetCursorPosition());
+ EXPECT_EQ(5U, model.GetCursorPosition());
+ // Undo until the initial edit.
EXPECT_TRUE(model.Undo());
EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(4U, model.GetCursorPosition());
@@ -1341,6 +1591,8 @@ TEST_F(TextfieldModelTest, UndoRedo_SetText) {
EXPECT_STR_EQ("", model.text());
EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
+
+ // Redo until the last edit.
EXPECT_TRUE(model.Redo());
EXPECT_STR_EQ("www.google.com", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
@@ -1365,27 +1617,29 @@ TEST_F(TextfieldModelTest, UndoRedo_BackspaceThenSetText) {
model.InsertChar('w');
EXPECT_STR_EQ("w", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
- model.SetText(base::ASCIIToUTF16("www.google.com"));
- EXPECT_EQ(14U, model.GetCursorPosition());
+ model.SetText(base::ASCIIToUTF16("www.google.com"), 1);
EXPECT_STR_EQ("www.google.com", model.text());
- model.SetText(base::ASCIIToUTF16("www.google.com")); // Confirm the text.
+ EXPECT_EQ(1U, model.GetCursorPosition());
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(14U, model.GetCursorPosition());
EXPECT_TRUE(model.Backspace());
EXPECT_TRUE(model.Backspace());
EXPECT_STR_EQ("www.google.c", model.text());
// Autocomplete sets the text.
- model.SetText(base::ASCIIToUTF16("www.google.com/search=www.google.c"));
+ model.SetText(base::ASCIIToUTF16("www.google.com/search=www.google.c"), 12);
EXPECT_STR_EQ("www.google.com/search=www.google.c", model.text());
+ EXPECT_EQ(12U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
EXPECT_STR_EQ("www.google.c", model.text());
+ EXPECT_EQ(12U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(14U, model.GetCursorPosition());
}
TEST_F(TextfieldModelTest, UndoRedo_CutCopyPasteTest) {
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"), 5);
EXPECT_FALSE(model.Redo()); // There is nothing to redo.
// Test Cut.
model.SelectRange(gfx::Range(1, 3)); // A[BC]DE
@@ -1478,7 +1732,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CutCopyPasteTest) {
gfx::Range(1, 3)));
// Test Copy.
ResetModel(&model);
- model.SetText(base::ASCIIToUTF16("12345")); // 12345|
+ model.SetText(base::ASCIIToUTF16("12345"), 5); // 12345|
EXPECT_STR_EQ("12345", model.text());
EXPECT_EQ(5U, model.GetCursorPosition());
model.SelectRange(gfx::Range(1, 3)); // 1[23]45
@@ -1553,7 +1807,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CursorTest) {
TEST_F(TextfieldModelTest, Undo_SelectionTest) {
gfx::Range range = gfx::Range(2, 4);
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("abcdef"));
+ model.SetText(base::ASCIIToUTF16("abcdef"), 0);
model.SelectRange(range);
EXPECT_EQ(model.render_text()->selection(), range);
@@ -1585,7 +1839,7 @@ TEST_F(TextfieldModelTest, Undo_SelectionTest) {
model.MoveCursorTo(model.text().length());
EXPECT_TRUE(model.Backspace());
model.SelectRange(gfx::Range(1, 3));
- model.SetText(base::ASCIIToUTF16("[set]"));
+ model.SetText(base::ASCIIToUTF16("[set]"), 0);
EXPECT_TRUE(model.Undo());
EXPECT_STR_EQ("abcde", model.text());
EXPECT_EQ(model.render_text()->selection(), gfx::Range(1, 3));
@@ -1642,28 +1896,28 @@ TEST_F(TextfieldModelTest, UndoRedo_ReplaceTest) {
{
SCOPED_TRACE("Select forwards and insert.");
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("abcd"));
+ model.SetText(base::ASCIIToUTF16("abcd"), 4);
model.SelectRange(gfx::Range(1, 3));
RunInsertReplaceTest(&model);
}
{
SCOPED_TRACE("Select reversed and insert.");
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("abcd"));
+ model.SetText(base::ASCIIToUTF16("abcd"), 4);
model.SelectRange(gfx::Range(3, 1));
RunInsertReplaceTest(&model);
}
{
SCOPED_TRACE("Select forwards and overwrite.");
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("abcd"));
+ model.SetText(base::ASCIIToUTF16("abcd"), 4);
model.SelectRange(gfx::Range(1, 3));
RunOverwriteReplaceTest(&model);
}
{
SCOPED_TRACE("Select reversed and overwrite.");
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("abcd"));
+ model.SetText(base::ASCIIToUTF16("abcd"), 4);
model.SelectRange(gfx::Range(3, 1));
RunOverwriteReplaceTest(&model);
}
@@ -1679,7 +1933,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
ui::ImeTextSpan::Thickness::kThin));
composition.selection = gfx::Range(2, 3);
- model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"), 0);
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
model.InsertChar('x');
EXPECT_STR_EQ("ABCDEx", model.text());
@@ -1718,11 +1972,11 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
// Call SetText with the same text as the result.
ResetModel(&model);
- model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"), 0);
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
model.SetCompositionText(composition);
EXPECT_STR_EQ("ABCDEabc", model.text());
- model.SetText(base::ASCIIToUTF16("ABCDEabc"));
+ model.SetText(base::ASCIIToUTF16("ABCDEabc"), 0);
EXPECT_STR_EQ("ABCDEabc", model.text());
EXPECT_TRUE(model.Undo());
EXPECT_STR_EQ("ABCDE", model.text());
@@ -1732,11 +1986,11 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
// Call SetText with a different result; the composition should be forgotten.
ResetModel(&model);
- model.SetText(base::ASCIIToUTF16("ABCDE"));
+ model.SetText(base::ASCIIToUTF16("ABCDE"), 0);
model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
model.SetCompositionText(composition);
EXPECT_STR_EQ("ABCDEabc", model.text());
- model.SetText(base::ASCIIToUTF16("1234"));
+ model.SetText(base::ASCIIToUTF16("1234"), 0);
EXPECT_STR_EQ("1234", model.text());
EXPECT_TRUE(model.Undo());
EXPECT_STR_EQ("ABCDE", model.text());
@@ -1747,6 +2001,298 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
// TODO(oshima): Test the behavior with an IME.
}
+TEST_F(TextfieldModelTest, UndoRedo_TypingWithSecondarySelections) {
+ TextfieldModel model(nullptr);
+
+ // Type 'ab cd' as 'prefix ab xy suffix' and 'prefix ab cd suffix' are
+ // autocompleted.
+ // Type 'a', autocomplete [prefix ]a[b xy suffix]
+ model.InsertChar('a');
+ model.SetText(base::ASCIIToUTF16("prefix ab xy suffix"), 8);
+ model.SelectRange({19, 8});
+ model.SelectRange({0, 7}, false);
+
+ // Type 'ab', autocomplete [prefix ]ab[ xy suffix]
+ model.InsertChar('b');
+ model.SetText(base::ASCIIToUTF16("prefix ab xy suffix"), 9);
+ model.SelectRange({19, 9});
+ model.SelectRange({0, 7}, false);
+
+ // Type 'ab ', autocomplete [prefix ]ab [xy suffix]
+ model.InsertChar(' ');
+ model.SetText(base::ASCIIToUTF16("prefix ab xy suffix"), 10);
+ model.SelectRange({19, 10});
+ model.SelectRange({0, 7}, false);
+
+ // Type 'ab c', autocomplete changed to [prefix ]ab c[d suffix]
+ model.InsertChar('c');
+ model.SetText(base::ASCIIToUTF16("prefix ab cd suffix"), 11);
+ model.SelectRange({19, 11});
+ model.SelectRange({0, 7}, false);
+
+ // Type 'ab cd', autocomplete [prefix ]ab cd[ suffix]
+ model.InsertChar('d');
+ model.SetText(base::ASCIIToUTF16("prefix ab cd suffix"), 12);
+ model.SelectRange({19, 12});
+ model.SelectRange({0, 7}, false);
+
+ // Undo 3 times
+ EXPECT_TRUE(model.Undo()); // [prefix ]ab c[d suffix]
+ EXPECT_STR_EQ("prefix ab cd suffix", model.text());
+ EXPECT_EQ(11U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"d suffix", "prefix "});
+
+ EXPECT_TRUE(model.Undo()); // [prefix ]ab [xy suffix]
+ EXPECT_STR_EQ("prefix ab xy suffix", model.text());
+ EXPECT_EQ(10U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"xy suffix", "prefix "});
+
+ EXPECT_TRUE(model.Undo()); // [prefix ]ab[ xy suffix]
+ EXPECT_STR_EQ("prefix ab xy suffix", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {" xy suffix", "prefix "});
+
+ // Redo 3 times
+ EXPECT_TRUE(model.Redo()); // [prefix ]ab [xy suffix]
+ EXPECT_STR_EQ("prefix ab xy suffix", model.text());
+ EXPECT_EQ(10U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+
+ EXPECT_TRUE(model.Redo()); // [prefix ]ab c[d suffix]
+ EXPECT_STR_EQ("prefix ab cd suffix", model.text());
+ EXPECT_EQ(11U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+
+ EXPECT_TRUE(model.Redo()); // [prefix ]ab cd[ suffix]
+ EXPECT_STR_EQ("prefix ab cd suffix", model.text());
+ EXPECT_EQ(12U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+}
+
+TEST_F(TextfieldModelTest, UndoRedo_MergingEditsWithSecondarySelections) {
+ TextfieldModel model(nullptr);
+
+ // Test all possible merge combinations involving secondary selections.
+ // I.e. an initial [replace or delete] edit with secondary selections,
+ // followed by a second and third [insert, replace, or delete] edits, which
+ // are [continuous and discontinuous] respectively. Some cases of the third,
+ // discontinuous edit have been omitted when the the second edit would not
+ // been merged anyways.
+
+ // Note, the cursor and selections depend on whether we're traversing forward
+ // or backwards through edit history. I.e., `undo(); redo();` can result in a
+ // different outcome than `redo(); undo();`. In general, if our edit history
+ // consists of 3 edits: A->B, C->D, & E->F, then undo will traverse
+ // F->E->C->A, while redo will traverse A->B->D->F. Though, B & C and D & E
+ // will have the same text, they can have different cursors and selections.
+
+ // Replacement with secondary selections followed by insertions
+ model.SetText(base::ASCIIToUTF16("prefix infix suffix"), 13);
+ model.SelectRange({18, 13});
+ model.SelectRange({1, 6}, false); // p[refix] infix [suffi]x
+ // Replace
+ model.InsertChar('1'); // p infix 1|x
+ // Continuous insert (should merge)
+ model.InsertChar('3'); // p infix 13|x
+ // Discontinuous insert (should not merge)
+ model.SelectRange({9, 9}); // p infix 1|3x
+ model.InsertChar('2'); // p infix 12|3x
+ EXPECT_STR_EQ("p infix 123x", model.text());
+ EXPECT_FALSE(model.HasSelection());
+ // Edit history should be
+ // p[refix] infix [suffi]x -> p infix 13|x
+ // p infix 1|3x -> p infix 12|3x
+ // Undo 2 times
+ EXPECT_TRUE(model.Undo()); // p infix 1|3x
+ EXPECT_STR_EQ("p infix 13x", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Undo()); // p[refix] infix [suffi]x
+ EXPECT_STR_EQ("prefix infix suffix", model.text());
+ EXPECT_EQ(13U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"suffi", "refix"});
+ // Redo 2 times
+ EXPECT_TRUE(model.Redo()); // p infix 13|x
+ EXPECT_STR_EQ("p infix 13x", model.text());
+ EXPECT_EQ(10U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Redo()); // p infix 12|3x
+ EXPECT_STR_EQ("p infix 123x", model.text());
+ EXPECT_EQ(10U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_FALSE(model.Redo());
+
+ // Replacement with secondary selections followed by replacements
+ model.SetText(base::ASCIIToUTF16("prefix infix suffix"), 13);
+ model.SelectRange({15, 13});
+ model.SelectRange({1, 6}, false); // p[refix] infix [su]ffix
+ // Replace
+ model.InsertChar('1'); // p infix 1|ffix
+ // Continuous multiple characters, and backwards replace (should merge)
+ model.SelectRange({11, 9}); // p infix 1[ff]ix
+ model.InsertChar('3'); // p infix 13|ix
+ // Discontinuous but adjacent replace (should not merge)
+ model.SelectRange({10, 9}); // p infix 1[3]ix
+ model.InsertChar('2'); // p infix 12|ix
+ EXPECT_STR_EQ("p infix 12ix", model.text());
+ EXPECT_FALSE(model.HasSelection());
+ // Edit history should be
+ // p[refix] infix [su]ffix -> p infix 13|ix
+ // p infix 1[3]ix -> p infix 12|ix
+ // Undo 2 times
+ EXPECT_TRUE(model.Undo()); // p infix 1[3]ix
+ EXPECT_STR_EQ("p infix 13ix", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"3"});
+ EXPECT_TRUE(model.Undo()); // p[refix] infix [su]ffix
+ EXPECT_STR_EQ("prefix infix suffix", model.text());
+ EXPECT_EQ(13U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"su", "refix"});
+ // Redo 2 times
+ EXPECT_TRUE(model.Redo()); // p infix 13|ix
+ EXPECT_STR_EQ("p infix 13ix", model.text());
+ EXPECT_EQ(10U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Redo()); // p infix 12|ix
+ EXPECT_STR_EQ("p infix 12ix", model.text());
+ EXPECT_EQ(10U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_FALSE(model.Redo());
+
+ // Replacement with secondary selections followed by deletion
+ model.SetText(base::ASCIIToUTF16("prefix infix suffix"), 13);
+ model.SelectRange({15, 13});
+ model.SelectRange({1, 6}, false); // p[refix] infix [su]ffix
+ // Replace
+ model.InsertChar('1'); // p infix 1|ffix
+ // Continuous delete (should not merge)
+ model.Delete(false); // p infix 1|fix
+ EXPECT_STR_EQ("p infix 1fix", model.text());
+ EXPECT_FALSE(model.HasSelection());
+ // Edit history should be
+ // p[refix] infix [su]ffix -> p infix 1|ffix
+ // p infix 1|ffix -> p infix 1|fix
+ // Undo 2 times
+ EXPECT_TRUE(model.Undo()); // p infix 1|ffix
+ EXPECT_STR_EQ("p infix 1ffix", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Undo()); // p[refix] infix [su]ffix
+ EXPECT_STR_EQ("prefix infix suffix", model.text());
+ EXPECT_EQ(13U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"su", "refix"});
+ // Redo 2 times
+ EXPECT_TRUE(model.Redo()); // p infix 1|ffix
+ EXPECT_STR_EQ("p infix 1ffix", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Redo()); // p infix 1|fix
+ EXPECT_STR_EQ("p infix 1fix", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_FALSE(model.Redo());
+
+ // Deletion with secondary selections followed by insertion
+ model.SetText(base::ASCIIToUTF16("prefix infix suffix"), 13);
+ model.SelectRange({15, 13});
+ model.SelectRange({1, 6}, false); // p[refix] infix [su]ffix
+ // Delete
+ model.Delete(false); // p infix |ffix
+ // Continuous insert (should not merge)
+ model.InsertChar('1'); // p infix 1|ffix
+ EXPECT_STR_EQ("p infix 1ffix", model.text());
+ EXPECT_FALSE(model.HasSelection());
+ // Edit history should be
+ // p[refix] infix [su]ffix -> p infix |ffix
+ // p infix |ffix -> p infix 1|ffix
+ // Undo 2 times
+ EXPECT_TRUE(model.Undo()); // p infix |ffix
+ EXPECT_STR_EQ("p infix ffix", model.text());
+ EXPECT_EQ(8U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Undo()); // p[refix] infix [su]ffix
+ EXPECT_STR_EQ("prefix infix suffix", model.text());
+ EXPECT_EQ(13U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"su", "refix"});
+ // Redo 2 times
+ EXPECT_TRUE(model.Redo()); // p infix |ffix
+ EXPECT_STR_EQ("p infix ffix", model.text());
+ EXPECT_EQ(8U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Redo()); // p infix 1|ffix
+ EXPECT_STR_EQ("p infix 1ffix", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_FALSE(model.Redo());
+
+ // Deletion with secondary selections followed by replacement
+ model.SetText(base::ASCIIToUTF16("prefix infix suffix"), 13);
+ model.SelectRange({15, 13});
+ model.SelectRange({1, 6}, false); // p[refix] infix [su]ffix
+ // Delete
+ model.Delete(false); // p infix |ffix
+ // Continuous replacement (should not merge)
+ model.SelectRange({8, 9}); // p infix [f]fix
+ model.InsertChar('1'); // p infix 1|fix
+ EXPECT_STR_EQ("p infix 1fix", model.text());
+ EXPECT_FALSE(model.HasSelection());
+ // Edit history should be
+ // p[refix] infix [su]ffix -> p infix |ffix
+ // p infix [f]fix -> p infix 1|fix
+ // Undo 2 times
+ EXPECT_TRUE(model.Undo()); // p infix [f]fix
+ EXPECT_STR_EQ("p infix ffix", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"f"});
+ EXPECT_TRUE(model.Undo()); // p[refix] infix [su]ffix
+ EXPECT_STR_EQ("prefix infix suffix", model.text());
+ EXPECT_EQ(13U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"su", "refix"});
+ // Redo 2 times
+ EXPECT_TRUE(model.Redo()); // p infix |ffix
+ EXPECT_STR_EQ("p infix ffix", model.text());
+ EXPECT_EQ(8U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Redo()); // p infix 1|fix
+ EXPECT_STR_EQ("p infix 1fix", model.text());
+ EXPECT_EQ(9U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_FALSE(model.Redo());
+
+ // Deletion with secondary selections followed by deletion
+ model.SetText(base::ASCIIToUTF16("prefix infix suffix"), 13);
+ model.SelectRange({15, 13});
+ model.SelectRange({1, 6}, false); // p[refix] infix [su]ffix
+ // Delete
+ model.Delete(false); // p infix |ffix
+ // Continuous delete (should not merge)
+ model.Delete(false); // p infix |fix
+ EXPECT_STR_EQ("p infix fix", model.text());
+ EXPECT_FALSE(model.HasSelection());
+ // Edit history should be
+ // p[refix] infix [su]ffix -> p infix |ffix
+ // p infix |ffix -> p infix |fix
+ // Undo 2 times
+ EXPECT_TRUE(model.Undo()); // p infix |ffix
+ EXPECT_STR_EQ("p infix ffix", model.text());
+ EXPECT_EQ(8U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Undo()); // p[refix] infix [su]ffix
+ EXPECT_STR_EQ("prefix infix suffix", model.text());
+ EXPECT_EQ(13U, model.GetCursorPosition());
+ VerifyAllSelectionTexts(&model, {"su", "refix"});
+ // Redo 2 times
+ EXPECT_TRUE(model.Redo()); // p infix |ffix
+ EXPECT_STR_EQ("p infix ffix", model.text());
+ EXPECT_EQ(8U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_TRUE(model.Redo()); // p infix |fix
+ EXPECT_STR_EQ("p infix fix", model.text());
+ EXPECT_EQ(8U, model.GetCursorPosition());
+ EXPECT_FALSE(model.HasSelection());
+ EXPECT_FALSE(model.Redo());
+}
+
// Tests that clipboard text with leading, trailing and interspersed tabs
// spaces etc is pasted correctly. Leading and trailing tabs should be
// stripped. Text separated by multiple tabs/spaces should be left alone.
@@ -1902,7 +2448,7 @@ TEST_F(TextfieldModelTest, Transpose) {
const TestCase& test_case = all_tests[i][j];
- model.SetText(test_strings[i]);
+ model.SetText(test_strings[i], 0);
model.SelectRange(test_case.range);
EXPECT_EQ(test_case.range, model.render_text()->selection());
model.Transpose();
@@ -1915,32 +2461,49 @@ TEST_F(TextfieldModelTest, Transpose) {
TEST_F(TextfieldModelTest, Yank) {
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("abcde"));
+ model.SetText(base::ASCIIToUTF16("abcdefgh"), 0);
model.SelectRange(gfx::Range(1, 3));
// Delete selection but don't add to kill buffer.
model.Delete(false);
- EXPECT_STR_EQ("ade", model.text());
+ EXPECT_STR_EQ("adefgh", model.text());
// Since the kill buffer is empty, yank should cause no change.
- model.Yank();
- EXPECT_STR_EQ("ade", model.text());
+ EXPECT_FALSE(model.Yank());
+ EXPECT_STR_EQ("adefgh", model.text());
+
+ // With a nonempty selection and an empty kill buffer, yank should delete the
+ // selection.
+ model.SelectRange(gfx::Range(4, 5));
+ EXPECT_TRUE(model.Yank());
+ EXPECT_STR_EQ("adefh", model.text());
+
+ // With multiple selections and an empty kill buffer, yank should delete the
+ // selections.
+ model.SelectRange(gfx::Range(2, 3));
+ model.SelectRange(gfx::Range(4, 5), false);
+ EXPECT_TRUE(model.Yank());
+ EXPECT_STR_EQ("adf", model.text());
+
+ // The kill buffer should remain empty after yanking without a kill buffer.
+ EXPECT_FALSE(model.Yank());
+ EXPECT_STR_EQ("adf", model.text());
// Delete selection and add to kill buffer.
model.SelectRange(gfx::Range(0, 1));
model.Delete(true);
- EXPECT_STR_EQ("de", model.text());
+ EXPECT_STR_EQ("df", model.text());
// Yank twice.
- model.Yank();
- model.Yank();
- EXPECT_STR_EQ("aade", model.text());
+ EXPECT_TRUE(model.Yank());
+ EXPECT_TRUE(model.Yank());
+ EXPECT_STR_EQ("aadf", model.text());
// Ensure an empty deletion does not modify the kill buffer.
model.SelectRange(gfx::Range(4));
model.Delete(true);
- model.Yank();
- EXPECT_STR_EQ("aadea", model.text());
+ EXPECT_TRUE(model.Yank());
+ EXPECT_STR_EQ("aadfa", model.text());
// Backspace twice but don't add to kill buffer.
model.Backspace(false);
@@ -1948,7 +2511,7 @@ TEST_F(TextfieldModelTest, Yank) {
EXPECT_STR_EQ("aad", model.text());
// Ensure kill buffer is not modified.
- model.Yank();
+ EXPECT_TRUE(model.Yank());
EXPECT_STR_EQ("aada", model.text());
// Backspace twice, each time modifying the kill buffer.
@@ -1957,13 +2520,13 @@ TEST_F(TextfieldModelTest, Yank) {
EXPECT_STR_EQ("aa", model.text());
// Ensure yanking inserts the modified kill buffer text.
- model.Yank();
+ EXPECT_TRUE(model.Yank());
EXPECT_STR_EQ("aad", model.text());
}
TEST_F(TextfieldModelTest, SetCompositionFromExistingText) {
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("abcde"));
+ model.SetText(base::ASCIIToUTF16("abcde"), 0);
model.SetCompositionFromExistingText(gfx::Range(0, 1));
EXPECT_TRUE(model.HasCompositionText());
@@ -1979,7 +2542,7 @@ TEST_F(TextfieldModelTest, SetCompositionFromExistingText) {
TEST_F(TextfieldModelTest, SetCompositionFromExistingText_Empty) {
TextfieldModel model(nullptr);
- model.SetText(base::ASCIIToUTF16("abc"));
+ model.SetText(base::ASCIIToUTF16("abc"), 0);
model.SetCompositionFromExistingText(gfx::Range(0, 2));
EXPECT_TRUE(model.HasCompositionText());
@@ -1991,12 +2554,12 @@ TEST_F(TextfieldModelTest, SetCompositionFromExistingText_Empty) {
TEST_F(TextfieldModelTest, SetCompositionFromExistingText_OutOfBounds) {
TextfieldModel model(nullptr);
- model.SetText(base::string16());
+ model.SetText(base::string16(), 0);
model.SetCompositionFromExistingText(gfx::Range(0, 2));
EXPECT_FALSE(model.HasCompositionText());
- model.SetText(base::ASCIIToUTF16("abc"));
+ model.SetText(base::ASCIIToUTF16("abc"), 0);
model.SetCompositionFromExistingText(gfx::Range(1, 4));
EXPECT_FALSE(model.HasCompositionText());
}
diff --git a/chromium/ui/views/controls/textfield/textfield_test_api.cc b/chromium/ui/views/controls/textfield/textfield_test_api.cc
index 3f756dfaad7..099f22e9bcf 100644
--- a/chromium/ui/views/controls/textfield/textfield_test_api.cc
+++ b/chromium/ui/views/controls/textfield/textfield_test_api.cc
@@ -31,7 +31,7 @@ void TextfieldTestApi::ResetTouchSelectionController() {
}
void TextfieldTestApi::SetCursorViewRect(gfx::Rect bounds) {
- textfield_->cursor_view_.SetBoundsRect(bounds);
+ textfield_->cursor_view_->SetBoundsRect(bounds);
}
bool TextfieldTestApi::IsTextDirectionCheckedInContextMenu(
@@ -40,4 +40,8 @@ bool TextfieldTestApi::IsTextDirectionCheckedInContextMenu(
textfield_->text_services_context_menu_.get(), direction);
}
+bool TextfieldTestApi::ShouldShowCursor() const {
+ return textfield_->ShouldShowCursor();
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_test_api.h b/chromium/ui/views/controls/textfield/textfield_test_api.h
index 6f0496c5771..3f346da6059 100644
--- a/chromium/ui/views/controls/textfield/textfield_test_api.h
+++ b/chromium/ui/views/controls/textfield/textfield_test_api.h
@@ -46,14 +46,18 @@ class TextfieldTestApi {
return textfield_->cursor_blink_timer_.IsRunning();
}
- gfx::Rect GetCursorViewRect() { return textfield_->cursor_view_.bounds(); }
+ gfx::Rect GetCursorViewRect() { return textfield_->cursor_view_->bounds(); }
void SetCursorViewRect(gfx::Rect bounds);
- bool IsCursorVisible() const { return textfield_->cursor_view_.GetVisible(); }
+ bool IsCursorVisible() const {
+ return textfield_->cursor_view_->GetVisible();
+ }
bool IsTextDirectionCheckedInContextMenu(
base::i18n::TextDirection direction) const;
+ bool ShouldShowCursor() const;
+
private:
Textfield* textfield_;
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index 4a7a614b9d9..456cecaba14 100644
--- a/chromium/ui/views/controls/textfield/textfield_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -13,6 +13,7 @@
#include <vector>
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/format_macros.h"
#include "base/i18n/rtl.h"
#include "base/pickle.h"
@@ -53,6 +54,7 @@
#include "ui/views/test/test_views_delegate.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
+#include "ui/views/views_features.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_utils.h"
#include "url/gurl.h"
@@ -779,6 +781,19 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
// an event when it updates the cursor position.
void MoveMouseTo(const gfx::Point& where) { mouse_position_ = where; }
+ // Tap on the textfield.
+ void TapAtCursor(ui::EventPointerType pointer_type) {
+ ui::GestureEventDetails tap_down_details(ui::ET_GESTURE_TAP_DOWN);
+ tap_down_details.set_primary_pointer_type(pointer_type);
+ GestureEventForTest tap_down(GetCursorPositionX(0), 0, tap_down_details);
+ textfield_->OnGestureEvent(&tap_down);
+
+ ui::GestureEventDetails tap_up_details(ui::ET_GESTURE_TAP);
+ tap_up_details.set_primary_pointer_type(pointer_type);
+ GestureEventForTest tap_up(GetCursorPositionX(0), 0, tap_up_details);
+ textfield_->OnGestureEvent(&tap_up);
+ }
+
// We need widget to populate wrapper class.
Widget* widget_ = nullptr;
@@ -1155,6 +1170,19 @@ TEST_F(TextfieldTest, MoveParagraphForwardBackwardAndModifySelection) {
#endif
}
+TEST_F(TextfieldTest, ModifySelectionWithMultipleSelections) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("0123456 89"));
+ textfield_->SetSelectedRange(gfx::Range(3, 5));
+ textfield_->SetSelectedRange(gfx::Range(8, 9), false);
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_RIGHT_AND_MODIFY_SELECTION);
+ EXPECT_EQ(gfx::Range(3, 6), textfield_->GetSelectedRange());
+ EXPECT_EQ(6U, textfield_->GetCursorPosition());
+ EXPECT_EQ(0U, textfield_->GetSelectionModel().secondary_selections().size());
+}
+
TEST_F(TextfieldTest, InsertionDeletionTest) {
// Insert a test string in a textfield.
InitTextfield();
@@ -1245,6 +1273,36 @@ TEST_F(TextfieldTest, DeletionWithSelection) {
}
}
+// Test that deletion operations behave correctly with multiple selections.
+TEST_F(TextfieldTest, DeletionWithMultipleSelections) {
+ struct {
+ ui::KeyboardCode key;
+ bool shift;
+ } cases[] = {
+ {ui::VKEY_BACK, false},
+ {ui::VKEY_BACK, true},
+ {ui::VKEY_DELETE, false},
+ {ui::VKEY_DELETE, true},
+ };
+
+ InitTextfield();
+ // [Ctrl] ([Alt] on Mac) + [Delete]/[Backspace] should delete the active
+ // selection, regardless of [Shift].
+ for (size_t i = 0; i < base::size(cases); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
+ textfield_->SetText(ASCIIToUTF16("one two three"));
+ // Select: o[ne] [two] th[re]e
+ textfield_->SetSelectedRange(gfx::Range(4, 7));
+ textfield_->SetSelectedRange(gfx::Range(10, 12), false);
+ textfield_->SetSelectedRange(gfx::Range(1, 3), false);
+ SendWordEvent(cases[i].key, cases[i].shift);
+ EXPECT_STR_EQ("o the", textfield_->GetText());
+ EXPECT_EQ(gfx::Range(2), textfield_->GetSelectedRange());
+ EXPECT_EQ(0U,
+ textfield_->GetSelectionModel().secondary_selections().size());
+ }
+}
+
// Test deletions not covered by other tests with key events.
TEST_F(TextfieldTest, DeletionWithEditCommands) {
struct {
@@ -1283,11 +1341,11 @@ TEST_F(TextfieldTest, PasswordTest) {
SetClipboardText(ui::ClipboardBuffer::kCopyPaste, "foo");
// Cut and copy should be disabled.
- EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_->ExecuteCommand(IDS_APP_CUT, 0);
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(Textfield::kCut));
+ textfield_->ExecuteCommand(Textfield::kCut, 0);
SendKeyEvent(ui::VKEY_X, false, true);
- EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_->ExecuteCommand(IDS_APP_COPY, 0);
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(Textfield::kCopy));
+ textfield_->ExecuteCommand(Textfield::kCopy, 0);
SendKeyEvent(ui::VKEY_C, false, true);
SendAlternateCopy();
EXPECT_STR_EQ("foo", GetClipboardText(ui::ClipboardBuffer::kCopyPaste));
@@ -1297,8 +1355,8 @@ TEST_F(TextfieldTest, PasswordTest) {
SendKeyEvent(ui::VKEY_DELETE, true, false);
// Paste should work normally.
- EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(Textfield::kPaste));
+ textfield_->ExecuteCommand(Textfield::kPaste, 0);
SendKeyEvent(ui::VKEY_V, false, true);
SendAlternatePaste();
EXPECT_STR_EQ("foo", GetClipboardText(ui::ClipboardBuffer::kCopyPaste));
@@ -1517,6 +1575,42 @@ TEST_F(TextfieldTest, CursorMovement) {
EXPECT_STR_EQ("one two", last_contents_);
}
+TEST_F(TextfieldTest, CursorMovementWithMultipleSelections) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("012 456 890 234 678"));
+ // [p] [s]
+ textfield_->SetSelectedRange({4, 7});
+ textfield_->SetSelectedRange({12, 15}, false);
+
+ test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_LEFT);
+ EXPECT_EQ(gfx::Range(4, 4), textfield_->GetSelectedRange());
+ EXPECT_EQ(0U, textfield_->GetSelectionModel().secondary_selections().size());
+
+ textfield_->SetSelectedRange({4, 7});
+ textfield_->SetSelectedRange({12, 15}, false);
+
+ test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_RIGHT);
+ EXPECT_EQ(gfx::Range(7, 7), textfield_->GetSelectedRange());
+ EXPECT_EQ(0U, textfield_->GetSelectionModel().secondary_selections().size());
+}
+
+TEST_F(TextfieldTest, ShouldShowCursor) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("word1 word2"));
+
+ // should show cursor when there's no primary selection
+ textfield_->SetSelectedRange({4, 4});
+ EXPECT_TRUE(test_api_->ShouldShowCursor());
+ textfield_->SetSelectedRange({1, 3}, false);
+ EXPECT_TRUE(test_api_->ShouldShowCursor());
+
+ // should not show cursor when there's a primary selection
+ textfield_->SetSelectedRange({4, 7});
+ EXPECT_FALSE(test_api_->ShouldShowCursor());
+ textfield_->SetSelectedRange({1, 3}, false);
+ EXPECT_FALSE(test_api_->ShouldShowCursor());
+}
+
TEST_F(TextfieldTest, FocusTraversalTest) {
InitTextfields(3);
textfield_->RequestFocus();
@@ -1760,7 +1854,7 @@ TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) {
bad_data.SetPickledData(fmt, base::Pickle());
bad_data.SetFileContents(base::FilePath(L"x"), "x");
bad_data.SetHtml(base::string16(ASCIIToUTF16("x")), GURL("x.org"));
- ui::OSExchangeData::DownloadFileInfo download(base::FilePath(), nullptr);
+ ui::DownloadFileInfo download(base::FilePath(), nullptr);
bad_data.SetDownloadFileInfo(&download);
EXPECT_FALSE(textfield_->CanDrop(bad_data));
}
@@ -1964,24 +2058,24 @@ TEST_F(TextfieldTest, ReadOnlyTest) {
// Cut should be disabled.
SetClipboardText(ui::ClipboardBuffer::kCopyPaste, "Test");
- EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_->ExecuteCommand(IDS_APP_CUT, 0);
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(Textfield::kCut));
+ textfield_->ExecuteCommand(Textfield::kCut, 0);
SendKeyEvent(ui::VKEY_X, false, true);
SendAlternateCut();
EXPECT_STR_EQ("Test", GetClipboardText(ui::ClipboardBuffer::kCopyPaste));
EXPECT_STR_EQ("read only", textfield_->GetText());
// Paste should be disabled.
- EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
+ EXPECT_FALSE(textfield_->IsCommandIdEnabled(Textfield::kPaste));
+ textfield_->ExecuteCommand(Textfield::kPaste, 0);
SendKeyEvent(ui::VKEY_V, false, true);
SendAlternatePaste();
EXPECT_STR_EQ("read only", textfield_->GetText());
// Copy should work normally.
SetClipboardText(ui::ClipboardBuffer::kCopyPaste, "Test");
- EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_->ExecuteCommand(IDS_APP_COPY, 0);
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(Textfield::kCopy));
+ textfield_->ExecuteCommand(Textfield::kCopy, 0);
EXPECT_STR_EQ("read only", GetClipboardText(ui::ClipboardBuffer::kCopyPaste));
SetClipboardText(ui::ClipboardBuffer::kCopyPaste, "Test");
SendKeyEvent(ui::VKEY_C, false, true);
@@ -2297,11 +2391,11 @@ TEST_F(TextfieldTest, Yank) {
TEST_F(TextfieldTest, CutCopyPaste) {
InitTextfield();
- // Ensure IDS_APP_CUT cuts.
+ // Ensure kCut cuts.
textfield_->SetText(ASCIIToUTF16("123"));
textfield_->SelectAll(false);
- EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_CUT));
- textfield_->ExecuteCommand(IDS_APP_CUT, 0);
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(Textfield::kCut));
+ textfield_->ExecuteCommand(Textfield::kCut, 0);
EXPECT_STR_EQ("123", GetClipboardText(ui::ClipboardBuffer::kCopyPaste));
EXPECT_STR_EQ("", textfield_->GetText());
EXPECT_EQ(ui::ClipboardBuffer::kCopyPaste, GetAndResetCopiedToClipboard());
@@ -2337,11 +2431,11 @@ TEST_F(TextfieldTest, CutCopyPaste) {
EXPECT_STR_EQ("123", textfield_->GetText());
EXPECT_EQ(ui::ClipboardBuffer::kMaxValue, GetAndResetCopiedToClipboard());
- // Ensure IDS_APP_COPY copies.
+ // Ensure kCopy copies.
textfield_->SetText(ASCIIToUTF16("789"));
textfield_->SelectAll(false);
- EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY));
- textfield_->ExecuteCommand(IDS_APP_COPY, 0);
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(Textfield::kCopy));
+ textfield_->ExecuteCommand(Textfield::kCopy, 0);
EXPECT_STR_EQ("789", GetClipboardText(ui::ClipboardBuffer::kCopyPaste));
EXPECT_EQ(ui::ClipboardBuffer::kCopyPaste, GetAndResetCopiedToClipboard());
@@ -2363,12 +2457,12 @@ TEST_F(TextfieldTest, CutCopyPaste) {
EXPECT_STR_EQ("345", textfield_->GetText());
EXPECT_EQ(ui::ClipboardBuffer::kCopyPaste, GetAndResetCopiedToClipboard());
- // Ensure IDS_APP_PASTE, [Ctrl]+[V], and [Shift]+[Insert] pastes;
+ // Ensure kPaste, [Ctrl]+[V], and [Shift]+[Insert] pastes;
// also ensure that [Ctrl]+[Alt]+[V] does nothing.
SetClipboardText(ui::ClipboardBuffer::kCopyPaste, "abc");
textfield_->SetText(base::string16());
- EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE));
- textfield_->ExecuteCommand(IDS_APP_PASTE, 0);
+ EXPECT_TRUE(textfield_->IsCommandIdEnabled(Textfield::kPaste));
+ textfield_->ExecuteCommand(Textfield::kPaste, 0);
EXPECT_STR_EQ("abc", textfield_->GetText());
SendKeyEvent(ui::VKEY_V, false, true);
EXPECT_STR_EQ("abcabc", textfield_->GetText());
@@ -3662,12 +3756,7 @@ TEST_F(TextfieldTest, FocusReasonTouchTap) {
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_NONE,
textfield_->GetFocusReason());
- ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP_DOWN);
- tap_details.set_primary_pointer_type(
- ui::EventPointerType::POINTER_TYPE_TOUCH);
- GestureEventForTest tap(GetCursorPositionX(0), 0, tap_details);
- textfield_->OnGestureEvent(&tap);
-
+ TapAtCursor(ui::EventPointerType::kTouch);
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_TOUCH,
textfield_->GetFocusReason());
}
@@ -3678,11 +3767,7 @@ TEST_F(TextfieldTest, FocusReasonPenTap) {
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_NONE,
textfield_->GetFocusReason());
- ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP_DOWN);
- tap_details.set_primary_pointer_type(ui::EventPointerType::POINTER_TYPE_PEN);
- GestureEventForTest tap(GetCursorPositionX(0), 0, tap_details);
- textfield_->OnGestureEvent(&tap);
-
+ TapAtCursor(ui::EventPointerType::kPen);
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_PEN,
textfield_->GetFocusReason());
}
@@ -3693,23 +3778,8 @@ TEST_F(TextfieldTest, FocusReasonMultipleEvents) {
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_NONE,
textfield_->GetFocusReason());
- // Pen tap, followed by a touch tap
- {
- ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP_DOWN);
- tap_details.set_primary_pointer_type(
- ui::EventPointerType::POINTER_TYPE_PEN);
- GestureEventForTest tap(GetCursorPositionX(0), 0, tap_details);
- textfield_->OnGestureEvent(&tap);
- }
-
- {
- ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP_DOWN);
- tap_details.set_primary_pointer_type(
- ui::EventPointerType::POINTER_TYPE_TOUCH);
- GestureEventForTest tap(GetCursorPositionX(0), 0, tap_details);
- textfield_->OnGestureEvent(&tap);
- }
-
+ TapAtCursor(ui::EventPointerType::kPen);
+ TapAtCursor(ui::EventPointerType::kTouch);
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_PEN,
textfield_->GetFocusReason());
}
@@ -3721,13 +3791,8 @@ TEST_F(TextfieldTest, FocusReasonFocusBlurFocus) {
textfield_->GetFocusReason());
// Pen tap, blur, then programmatic focus.
- ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP_DOWN);
- tap_details.set_primary_pointer_type(ui::EventPointerType::POINTER_TYPE_PEN);
- GestureEventForTest tap(GetCursorPositionX(0), 0, tap_details);
- textfield_->OnGestureEvent(&tap);
-
+ TapAtCursor(ui::EventPointerType::kPen);
widget_->GetFocusManager()->ClearFocus();
-
textfield_->RequestFocus();
EXPECT_EQ(ui::TextInputClient::FOCUS_REASON_OTHER,
@@ -3737,11 +3802,7 @@ TEST_F(TextfieldTest, FocusReasonFocusBlurFocus) {
TEST_F(TextfieldTest, KeyboardObserverForPenInput) {
InitTextfield();
- ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP_DOWN);
- tap_details.set_primary_pointer_type(ui::EventPointerType::POINTER_TYPE_PEN);
- GestureEventForTest tap(GetCursorPositionX(0), 0, tap_details);
- textfield_->OnGestureEvent(&tap);
-
+ TapAtCursor(ui::EventPointerType::kPen);
EXPECT_EQ(1, input_method_->count_show_virtual_keyboard());
}
@@ -3796,4 +3857,14 @@ TEST_F(TextfieldTest, TextChangedCallbackTest) {
EXPECT_TRUE(text_changed);
}
+// Tests that invalid characters like non-displayable characters are filtered
+// out when inserted into the text field.
+TEST_F(TextfieldTest, InsertInvalidCharsTest) {
+ InitTextfield();
+
+ textfield_->InsertText(ASCIIToUTF16("\babc\ndef\t"));
+
+ EXPECT_EQ(textfield_->GetText(), ASCIIToUTF16("abcdef"));
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/tree/tree_view.cc b/chromium/ui/views/controls/tree/tree_view.cc
index 7d26bdf9f58..bd84a3f38d7 100644
--- a/chromium/ui/views/controls/tree/tree_view.cc
+++ b/chromium/ui/views/controls/tree/tree_view.cc
@@ -41,7 +41,6 @@
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/tree/tree_view_controller.h"
-#include "ui/views/layout/layout_provider.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/vector_icons.h"
@@ -193,14 +192,7 @@ void TreeView::StartEditing(TreeModelNode* node) {
DCHECK(!editing_);
editing_ = true;
if (!editor_) {
- LayoutProvider* provider = LayoutProvider::Get();
- gfx::Insets text_insets(
- provider->GetDistanceMetric(DISTANCE_CONTROL_VERTICAL_TEXT_PADDING),
- provider->GetDistanceMetric(
- DISTANCE_TEXTFIELD_HORIZONTAL_TEXT_PADDING));
editor_ = new Textfield;
- editor_->SetBorder(views::CreatePaddedBorder(
- views::CreateSolidBorder(1, gfx::kGoogleBlue700), text_insets));
// Add the editor immediately as GetPreferredSize returns the wrong thing if
// not parented.
AddChildView(editor_);
@@ -895,7 +887,7 @@ void TreeView::PopulateAccessibilityData(InternalNode* node,
} else {
// !IsRoot(node)) && node->parent() != nullptr.
- if (node->parent()->is_expanded()) {
+ if (IsExpanded(node->parent()->model_node())) {
int depth = 0;
row = GetRowForInternalNode(node, &depth);
if (depth >= 0) {
@@ -922,7 +914,6 @@ void TreeView::PopulateAccessibilityData(InternalNode* node,
data->AddAction(ax::mojom::Action::kFocus);
data->AddAction(ax::mojom::Action::kScrollToMakeVisible);
gfx::Rect node_bounds = GetBackgroundBoundsForNode(node);
- View::ConvertRectToScreen(this, &node_bounds);
data->relative_bounds.bounds = gfx::RectF(node_bounds);
} else {
data->AddState(ax::mojom::State::kInvisible);
diff --git a/chromium/ui/views/controls/tree/tree_view.h b/chromium/ui/views/controls/tree/tree_view.h
index 89c559a3bfb..b03b860f7b2 100644
--- a/chromium/ui/views/controls/tree/tree_view.h
+++ b/chromium/ui/views/controls/tree/tree_view.h
@@ -134,7 +134,7 @@ class VIEWS_EXPORT TreeView : public View,
// Maps a node to a row, returns -1 if node is not valid.
int GetRowForNode(ui::TreeModelNode* node);
- views::Textfield* editor() { return editor_; }
+ Textfield* editor() { return editor_; }
// Replaces this TreeView's TreeViewDrawingProvider with |provider|.
void SetDrawingProvider(std::unique_ptr<TreeViewDrawingProvider> provider);
diff --git a/chromium/ui/views/controls/views_text_services_context_menu.cc b/chromium/ui/views/controls/views_text_services_context_menu.cc
index 5e1559e61bc..0cebc532c69 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu.cc
+++ b/chromium/ui/views/controls/views_text_services_context_menu.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/logging.h"
+#include "base/notreached.h"
#include "ui/views/controls/views_text_services_context_menu_base.h"
namespace views {
diff --git a/chromium/ui/views/controls/webview/BUILD.gn b/chromium/ui/views/controls/webview/BUILD.gn
index b52fdbf769a..66ba75adfcc 100644
--- a/chromium/ui/views/controls/webview/BUILD.gn
+++ b/chromium/ui/views/controls/webview/BUILD.gn
@@ -59,7 +59,7 @@ jumbo_component("webview") {
"//ui/views",
]
- if (is_linux || is_android) {
+ if (is_linux || is_android || is_fuchsia) {
sources += [ "unhandled_keyboard_event_handler_default.cc" ]
}
}
diff --git a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
index 85a1cc6e07a..cff5956b04a 100644
--- a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
+++ b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
@@ -23,7 +23,7 @@ bool UnhandledKeyboardEventHandler::HandleKeyboardEvent(
// Previous calls to TranslateMessage can generate Char events as well as
// RawKeyDown events, even if the latter triggered an accelerator. In these
// cases, we discard the Char events.
- if (event.GetType() == blink::WebInputEvent::kChar &&
+ if (event.GetType() == blink::WebInputEvent::Type::kChar &&
ignore_next_char_event_) {
ignore_next_char_event_ = false;
return false;
@@ -32,7 +32,7 @@ bool UnhandledKeyboardEventHandler::HandleKeyboardEvent(
// always generate a Char event.
ignore_next_char_event_ = false;
- if (event.GetType() == blink::WebInputEvent::kRawKeyDown) {
+ if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown) {
ui::Accelerator accelerator =
ui::GetAcceleratorFromNativeWebKeyboardEvent(event);
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.cc b/chromium/ui/views/controls/webview/web_dialog_view.cc
index a8dab41a057..f8c7d7670ef 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view.cc
@@ -387,13 +387,14 @@ content::WebContents* WebDialogView::OpenURLFromTab(
void WebDialogView::AddNewContents(
content::WebContents* source,
std::unique_ptr<content::WebContents> new_contents,
+ const GURL& target_url,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) {
- WebDialogWebContentsDelegate::AddNewContents(source, std::move(new_contents),
- disposition, initial_rect,
- user_gesture, was_blocked);
+ WebDialogWebContentsDelegate::AddNewContents(
+ source, std::move(new_contents), target_url, disposition, initial_rect,
+ user_gesture, was_blocked);
}
void WebDialogView::LoadingStateChanged(content::WebContents* source,
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.h b/chromium/ui/views/controls/webview/web_dialog_view.h
index b2c7fed8463..5b04647c4a3 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.h
+++ b/chromium/ui/views/controls/webview/web_dialog_view.h
@@ -140,6 +140,7 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView,
const content::OpenURLParams& params) override;
void AddNewContents(content::WebContents* source,
std::unique_ptr<content::WebContents> new_contents,
+ const GURL& target_url,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
diff --git a/chromium/ui/views/controls/webview/web_dialog_view_unittest.cc b/chromium/ui/views/controls/webview/web_dialog_view_unittest.cc
index ceb97226b3d..cb149be77fa 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view_unittest.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view_unittest.cc
@@ -14,6 +14,7 @@
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_renderer_host.h"
#include "content/test/test_content_browser_client.h"
#include "content/test/test_web_contents.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -127,6 +128,7 @@ class WebDialogViewUnitTest : public views::test::WidgetTest {
}
private:
+ content::RenderViewHostTestEnabler test_render_host_factories_;
content::TestContentBrowserClient test_browser_client_;
std::unique_ptr<content::TestBrowserContext> browser_context_;
// These are raw pointers (vs unique pointers) because the views
diff --git a/chromium/ui/views/corewm/DEPS b/chromium/ui/views/corewm/DEPS
index 1ce5357a428..059e550da2c 100644
--- a/chromium/ui/views/corewm/DEPS
+++ b/chromium/ui/views/corewm/DEPS
@@ -23,7 +23,7 @@ specific_include_rules = {
"desktop_capture_controller_unittest.cc": [
"+ui/views/test/native_widget_factory.h",
- "+ui/views/test/views_interactive_ui_test_base.h",
+ "+ui/views/test/widget_test.h",
"+ui/views/view.h",
"+ui/views/widget/desktop_aura/desktop_native_widget_aura.h",
"+ui/views/widget/desktop_aura/desktop_screen_position_client.h",
diff --git a/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc b/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
index 2e4d5119392..d04c5baca0b 100644
--- a/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
+++ b/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc
@@ -4,7 +4,6 @@
#include <memory>
-#include "base/logging.h"
#include "base/macros.h"
#include "ui/aura/env.h"
#include "ui/aura/test/test_window_delegate.h"
@@ -13,7 +12,7 @@
#include "ui/events/event.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/test/native_widget_factory.h"
-#include "ui/views/test/views_interactive_ui_test_base.h"
+#include "ui/views/test/widget_test.h"
#include "ui/views/view.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
@@ -26,7 +25,7 @@
namespace views {
-using DesktopCaptureControllerTest = ViewsInteractiveUITestBase;
+using DesktopCaptureControllerTest = test::DesktopWidgetTestInteractive;
// This class provides functionality to verify whether the View instance
// received the gesture event.
@@ -103,7 +102,7 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(50, 50, 650, 650);
params.native_widget = test::CreatePlatformNativeWidgetImpl(
- params, widget1.get(), test::kStubCapture, nullptr);
+ widget1.get(), test::kStubCapture, nullptr);
widget1->Init(std::move(params));
internal::RootView* root1 =
static_cast<internal::RootView*>(widget1->GetRootView());
@@ -125,7 +124,7 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(50, 50, 650, 650);
params.native_widget = test::CreatePlatformNativeWidgetImpl(
- params, widget2.get(), test::kStubCapture, nullptr);
+ widget2.get(), test::kStubCapture, nullptr);
widget2->Init(std::move(params));
internal::RootView* root2 =
diff --git a/chromium/ui/views/corewm/tooltip_aura.cc b/chromium/ui/views/corewm/tooltip_aura.cc
index c115ea2bf2d..2ae616b9896 100644
--- a/chromium/ui/views/corewm/tooltip_aura.cc
+++ b/chromium/ui/views/corewm/tooltip_aura.cc
@@ -54,8 +54,7 @@ bool CanUseTranslucentTooltipWidget() {
}
// Creates a widget of type TYPE_TOOLTIP
-views::Widget* CreateTooltipWidget(aura::Window* tooltip_window,
- const gfx::Rect& bounds) {
+views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params;
// For aura, since we set the type to TYPE_TOOLTIP, the widget will get
@@ -65,7 +64,6 @@ views::Widget* CreateTooltipWidget(aura::Window* tooltip_window,
DCHECK(params.context);
params.z_order = ui::ZOrderLevel::kFloatingUIElement;
params.accept_events = false;
- params.bounds = bounds;
if (CanUseTranslucentTooltipWidget())
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
@@ -237,15 +235,10 @@ void TooltipAura::SetText(aura::Window* window,
tooltip_view_->SetMaxWidth(GetMaxWidth(location));
tooltip_view_->SetText(tooltip_text);
- const gfx::Rect adjusted_bounds =
- GetTooltipBounds(location, tooltip_view_->GetPreferredSize());
-
if (!widget_) {
- widget_ = CreateTooltipWidget(tooltip_window_, adjusted_bounds);
+ widget_ = CreateTooltipWidget(tooltip_window_);
widget_->SetContentsView(tooltip_view_.get());
widget_->AddObserver(this);
- } else {
- widget_->SetBounds(adjusted_bounds);
}
ui::NativeTheme* native_theme = widget_->GetNativeTheme();
@@ -263,6 +256,17 @@ void TooltipAura::SetText(aura::Window* window,
color_utils::GetResultingPaintColor(foreground_color, background_color);
tooltip_view_->SetBackgroundColor(background_color, foreground_color);
tooltip_view_->SetForegroundColor(foreground_color);
+
+ // Calculate the tooltip preferred size after all tooltip attributes are
+ // updated - tooltip updates (for example setting text color) may invalidate
+ // the tooltip render text layout, which would make layout run just done to
+ // calculate the tooltip string size get immendiately disregarded.
+ // This also addresses https://crbug.com/2181825 (after color update,
+ // GetPreferredSize() will generate fresh render text layout, even if the
+ // actual tooltip text hasn't changed).
+ const gfx::Rect adjusted_bounds =
+ GetTooltipBounds(location, tooltip_view_->GetPreferredSize());
+ widget_->SetBounds(adjusted_bounds);
}
void TooltipAura::Show() {
diff --git a/chromium/ui/views/corewm/tooltip_controller.cc b/chromium/ui/views/corewm/tooltip_controller.cc
index 5b911f138a5..c19d2296ff9 100644
--- a/chromium/ui/views/corewm/tooltip_controller.cc
+++ b/chromium/ui/views/corewm/tooltip_controller.cc
@@ -141,9 +141,12 @@ int TooltipController::GetMaxWidth(const gfx::Point& location) const {
}
void TooltipController::UpdateTooltip(aura::Window* target) {
- // If tooltip is visible, we may want to hide it. If it is not, we are ok.
- if (tooltip_window_ == target && tooltip_->IsVisible())
+ // Ensure relevant tooltip is updated when it is visible or scheduled to
+ // show. Otherwise, a stale tooltip might be shown.
+ if (tooltip_window_ == target &&
+ (tooltip_->IsVisible() || tooltip_defer_timer_.IsRunning())) {
UpdateIfRequired();
+ }
// Reset |tooltip_window_at_mouse_press_| if the moving within the same window
// but over a region that has different tooltip text.
diff --git a/chromium/ui/views/corewm/tooltip_controller_test_helper.cc b/chromium/ui/views/corewm/tooltip_controller_test_helper.cc
index ebe66420ebe..d64125582fe 100644
--- a/chromium/ui/views/corewm/tooltip_controller_test_helper.cc
+++ b/chromium/ui/views/corewm/tooltip_controller_test_helper.cc
@@ -44,6 +44,11 @@ bool TooltipControllerTestHelper::IsTooltipVisible() {
return controller_->IsTooltipVisible();
}
+void TooltipControllerTestHelper::SetTooltipShowDelayEnable(
+ bool tooltip_show_delay) {
+ controller_->tooltip_show_delayed_ = tooltip_show_delay;
+}
+
TooltipTestView::TooltipTestView() = default;
TooltipTestView::~TooltipTestView() = default;
diff --git a/chromium/ui/views/corewm/tooltip_controller_test_helper.h b/chromium/ui/views/corewm/tooltip_controller_test_helper.h
index e62aaad9f23..3c2909548f2 100644
--- a/chromium/ui/views/corewm/tooltip_controller_test_helper.h
+++ b/chromium/ui/views/corewm/tooltip_controller_test_helper.h
@@ -38,6 +38,7 @@ class TooltipControllerTestHelper {
void FireTooltipShownTimer();
bool IsTooltipShownTimerRunning();
bool IsTooltipVisible();
+ void SetTooltipShowDelayEnable(bool tooltip_show_delay);
private:
TooltipController* controller_;
diff --git a/chromium/ui/views/corewm/tooltip_controller_unittest.cc b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
index eee55c8bb63..30ba48c792c 100644
--- a/chromium/ui/views/corewm/tooltip_controller_unittest.cc
+++ b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
@@ -325,6 +325,36 @@ TEST_F(TooltipControllerTest, DontShowEmptyTooltips) {
EXPECT_FALSE(helper_->IsTooltipVisible());
}
+TEST_F(TooltipControllerTest, TooltipUpdateWhenTooltipDeferTimerIsRunning) {
+ view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
+ EXPECT_EQ(base::string16(), helper_->GetTooltipText());
+ EXPECT_EQ(nullptr, helper_->GetTooltipWindow());
+
+ TooltipTestView* view2 = PrepareSecondView();
+ view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2"));
+
+ aura::Window* window = GetWindow();
+
+ // Tooltips show up with delay
+ helper_->SetTooltipShowDelayEnable(true);
+
+ // Tooltip 1 is scheduled and invisibled
+ generator_->MoveMouseRelativeTo(window, view_->bounds().CenterPoint());
+ EXPECT_FALSE(helper_->IsTooltipVisible());
+ EXPECT_FALSE(helper_->IsTooltipShownTimerRunning());
+
+ // Tooltip 2 is scheduled and invisible, the expected tooltip is tooltip 2
+ generator_->MoveMouseRelativeTo(window, view2->bounds().CenterPoint());
+ EXPECT_FALSE(helper_->IsTooltipVisible());
+ EXPECT_FALSE(helper_->IsTooltipShownTimerRunning());
+ base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2");
+ EXPECT_EQ(expected_tooltip, wm::GetTooltipText(window));
+ EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
+ EXPECT_EQ(window, helper_->GetTooltipWindow());
+
+ helper_->SetTooltipShowDelayEnable(false);
+}
+
TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
diff --git a/chromium/ui/views/debug_utils.cc b/chromium/ui/views/debug_utils.cc
index d176fd40a8e..63355b3b6f4 100644
--- a/chromium/ui/views/debug_utils.cc
+++ b/chromium/ui/views/debug_utils.cc
@@ -144,12 +144,16 @@ std::string PrintViewGraphImpl(const View* view) {
void PrintViewHierarchy(const View* view) {
std::ostringstream out;
- out << "View hierarchy:\n";
- PrintViewHierarchyImp(view, 0, &out);
+ PrintViewHierarchy(view, &out);
// Error so users in the field can generate and upload logs.
LOG(ERROR) << out.str();
}
+void PrintViewHierarchy(const View* view, std::ostringstream* out) {
+ *out << "View hierarchy:\n";
+ PrintViewHierarchyImp(view, 0, out);
+}
+
void PrintFocusHierarchy(const View* view) {
std::ostringstream out;
out << "Focus hierarchy:\n";
diff --git a/chromium/ui/views/debug_utils.h b/chromium/ui/views/debug_utils.h
index 3051359a207..6d0d9cd0d54 100644
--- a/chromium/ui/views/debug_utils.h
+++ b/chromium/ui/views/debug_utils.h
@@ -16,6 +16,9 @@ class View;
// Log the view hierarchy.
VIEWS_EXPORT void PrintViewHierarchy(const View* view);
+// Print the view hierarchy to |out|.
+VIEWS_EXPORT void PrintViewHierarchy(const View* view, std::ostringstream* out);
+
// Log the focus traversal hierarchy.
VIEWS_EXPORT void PrintFocusHierarchy(const View* view);
diff --git a/chromium/ui/views/event_monitor_aura.cc b/chromium/ui/views/event_monitor_aura.cc
index 8ea72524463..69edc44bc48 100644
--- a/chromium/ui/views/event_monitor_aura.cc
+++ b/chromium/ui/views/event_monitor_aura.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/scoped_observer.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
diff --git a/chromium/ui/views/event_monitor_mac.mm b/chromium/ui/views/event_monitor_mac.mm
index cfa72698b19..d16287300d9 100644
--- a/chromium/ui/views/event_monitor_mac.mm
+++ b/chromium/ui/views/event_monitor_mac.mm
@@ -6,7 +6,7 @@
#import <Cocoa/Cocoa.h>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/memory/ptr_util.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
diff --git a/chromium/ui/views/examples/BUILD.gn b/chromium/ui/views/examples/BUILD.gn
index d2223b73a62..ba6f3d7603c 100644
--- a/chromium/ui/views/examples/BUILD.gn
+++ b/chromium/ui/views/examples/BUILD.gn
@@ -4,6 +4,8 @@
import("//build/config/jumbo.gni")
import("//build/config/ui.gni")
+import("//testing/test.gni")
+import("//tools/grit/grit_rule.gni")
jumbo_component("views_examples_lib") {
testonly = true
@@ -21,8 +23,12 @@ jumbo_component("views_examples_lib") {
"button_sticker_sheet.h",
"checkbox_example.cc",
"checkbox_example.h",
+ "colored_dialog_example.cc",
+ "colored_dialog_example.h",
"combobox_example.cc",
"combobox_example.h",
+ "create_examples.cc",
+ "create_examples.h",
"dialog_example.cc",
"dialog_example.h",
"example_base.cc",
@@ -39,6 +45,8 @@ jumbo_component("views_examples_lib") {
"layout_example_base.h",
"link_example.cc",
"link_example.h",
+ "login_bubble_dialog.cc",
+ "login_bubble_dialog.h",
"menu_example.cc",
"menu_example.h",
"message_box_example.cc",
@@ -85,6 +93,8 @@ jumbo_component("views_examples_lib") {
]
deps = [
+ ":views_examples_resources_grd",
+ ":views_examples_resources_pak",
"//base",
"//cc/paint",
"//skia",
@@ -96,6 +106,7 @@ jumbo_component("views_examples_lib") {
"//ui/native_theme",
"//ui/resources",
"//ui/resources:ui_test_pak",
+ "//ui/strings:ui_strings",
"//ui/views",
]
@@ -108,32 +119,47 @@ jumbo_component("views_examples_lib") {
}
}
-executable("views_examples_exe") {
+source_set("views_examples_proc") {
testonly = true
- sources = [ "examples_main.cc" ]
+ sources = [
+ "examples_exit_code.h",
+ "examples_main_proc.cc",
+ "examples_main_proc.h",
+ ]
deps = [
":views_examples_lib",
"//base",
- "//base:i18n",
"//base/test:test_support",
- "//build/win:default_exe_manifest",
+ "//cc/paint",
"//components/viz/host",
"//components/viz/service",
"//mojo/core/embedder",
+ "//skia",
"//ui/base",
- "//ui/base/ime/init",
"//ui/compositor",
"//ui/compositor:test_support",
"//ui/gfx",
- "//ui/gl",
- "//ui/gl/init",
- "//ui/resources:ui_test_pak",
"//ui/views",
"//ui/views:test_support",
]
+ if (is_win || is_mac || (is_linux && !is_chromeos)) {
+ sources += [
+ "examples_skia_gold_pixel_diff.cc",
+ "examples_skia_gold_pixel_diff.h",
+ ]
+ deps += [
+ "//ui/base:pixel_diff_test_support",
+ "//ui/snapshot",
+ ]
+ }
+
+ if (is_win) {
+ deps += [ "//build/win:default_exe_manifest" ]
+ }
+
if (use_aura) {
deps += [
"//ui/aura",
@@ -145,6 +171,21 @@ executable("views_examples_exe") {
}
}
+executable("views_examples") {
+ testonly = true
+
+ sources = [ "examples_main.cc" ]
+
+ deps = [
+ ":views_examples_lib",
+ ":views_examples_proc",
+ "//base",
+ "//base/test:test_support",
+ "//build/win:default_exe_manifest",
+ "//ui/resources:ui_test_pak",
+ ]
+}
+
jumbo_component("views_examples_with_content_lib") {
testonly = true
sources = [
@@ -159,6 +200,8 @@ jumbo_component("views_examples_with_content_lib") {
deps = [
":views_examples_lib",
+ ":views_examples_resources_grd",
+ ":views_examples_resources_pak",
"//base",
"//content",
"//skia",
@@ -169,10 +212,10 @@ jumbo_component("views_examples_with_content_lib") {
]
}
-executable("views_examples_with_content_exe") {
+executable("views_examples_with_content") {
testonly = true
- sources = [ "examples_with_content_main_exe.cc" ]
+ sources = [ "examples_with_content_main.cc" ]
defines = [ "VIEWS_EXAMPLES_WITH_CONTENT_IMPLEMENTATION" ]
@@ -191,6 +234,10 @@ executable("views_examples_with_content_exe") {
configs += [ "//build/config/win:windowed" ]
configs -= [ "//build/config/win:console" ]
}
+
+ if (is_mac) {
+ deps += [ "//sandbox/mac:seatbelt" ]
+ }
}
copy("copy_content_resources") {
@@ -198,3 +245,61 @@ copy("copy_content_resources") {
sources = [ "$root_gen_dir/content/content_resources.pak" ]
outputs = [ "$root_out_dir/content_resources.pak" ]
}
+
+grit("views_examples_resources_grd") {
+ testonly = true
+ source = "views_examples_resources.grd"
+ outputs = [
+ "grit/views_examples_resources.h",
+ "views_examples_resources.pak",
+ ]
+}
+
+copy("views_examples_resources_pak") {
+ testonly = true
+ sources = [ "$target_gen_dir/views_examples_resources.pak" ]
+ outputs = [ "$root_out_dir/views_examples_resources.pak" ]
+ public_deps = [ ":views_examples_resources_grd" ]
+}
+
+test("views_examples_unittests") {
+ sources = [
+ "examples_unittest.cc",
+ "examples_unittest_main.cc",
+ ]
+
+ deps = [
+ ":views_examples_lib",
+ ":views_examples_proc",
+ "//base",
+ "//base/test:test_support",
+ "//components/viz/host",
+ "//components/viz/service",
+ "//mojo/core/embedder",
+ "//ui/base",
+ "//ui/base/ime/init",
+ "//ui/compositor",
+ "//ui/compositor:test_support",
+ "//ui/gfx",
+ "//ui/gl",
+ "//ui/gl/init",
+ "//ui/resources:ui_test_pak",
+ "//ui/snapshot",
+ "//ui/views",
+ "//ui/views:test_support",
+ ]
+
+ if (use_aura) {
+ deps += [
+ "//ui/aura",
+ "//ui/wm",
+ ]
+ }
+
+ data_deps = [
+ ":views_examples_resources_pak",
+ "//ui/resources:ui_test_pak_data",
+ ]
+
+ data = [ "$root_out_dir/views_examples_resources.pak" ]
+}
diff --git a/chromium/ui/views/examples/DEPS b/chromium/ui/views/examples/DEPS
index 7d637be55cc..cf9717c4951 100644
--- a/chromium/ui/views/examples/DEPS
+++ b/chromium/ui/views/examples/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/viz/common/features.h",
"+components/viz/host",
"+components/viz/service", # In-process viz service.
"+content/public",
@@ -7,5 +8,6 @@ include_rules = [
"+sandbox",
"+ui/gl/gl_switches.h", # Disable Direct Composition Workaround.
"+ui/gl/init/gl_factory.h", # To initialize GL bindings.
+ "+ui/snapshot", # Enable Skia Gold testing
"+ui/views_content_client",
]
diff --git a/chromium/ui/views/examples/box_layout_example.cc b/chromium/ui/views/examples/box_layout_example.cc
index 61c39340f07..92665320bf8 100644
--- a/chromium/ui/views/examples/box_layout_example.cc
+++ b/chromium/ui/views/examples/box_layout_example.cc
@@ -38,25 +38,25 @@ void BoxLayoutExample::CreateAdditionalControls(int vertical_pos) {
static const char* cross_axis_values[4] = {"Stretch", "Start", "Center",
"End"};
- orientation_ = CreateCombobox(base::ASCIIToUTF16("Orientation"),
- orientation_values, 2, &vertical_pos);
- main_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Main axis"),
- main_axis_values, 3, &vertical_pos);
- cross_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Cross axis"),
- cross_axis_values, 4, &vertical_pos);
+ orientation_ = CreateAndAddCombobox(base::ASCIIToUTF16("Orientation"),
+ orientation_values, 2, &vertical_pos);
+ main_axis_alignment_ = CreateAndAddCombobox(
+ base::ASCIIToUTF16("Main axis"), main_axis_values, 3, &vertical_pos);
+ cross_axis_alignment_ = CreateAndAddCombobox(
+ base::ASCIIToUTF16("Cross axis"), cross_axis_values, 4, &vertical_pos);
between_child_spacing_ =
- CreateTextfield(base::ASCIIToUTF16("Child spacing"), &vertical_pos);
+ CreateAndAddTextfield(base::ASCIIToUTF16("Child spacing"), &vertical_pos);
default_flex_ =
- CreateTextfield(base::ASCIIToUTF16("Default flex"), &vertical_pos);
- min_cross_axis_size_ =
- CreateTextfield(base::ASCIIToUTF16("Min cross axis"), &vertical_pos);
+ CreateAndAddTextfield(base::ASCIIToUTF16("Default flex"), &vertical_pos);
+ min_cross_axis_size_ = CreateAndAddTextfield(
+ base::ASCIIToUTF16("Min cross axis"), &vertical_pos);
CreateMarginsTextFields(base::ASCIIToUTF16("Insets"), &border_insets_,
&vertical_pos);
- collapse_margins_ =
- CreateCheckbox(base::ASCIIToUTF16("Collapse margins"), &vertical_pos);
+ collapse_margins_ = CreateAndAddCheckbox(
+ base::ASCIIToUTF16("Collapse margins"), &vertical_pos);
UpdateLayoutManager();
}
diff --git a/chromium/ui/views/examples/bubble_example.cc b/chromium/ui/views/examples/bubble_example.cc
index f7877482ecd..040cb595a18 100644
--- a/chromium/ui/views/examples/bubble_example.cc
+++ b/chromium/ui/views/examples/bubble_example.cc
@@ -78,7 +78,7 @@ class ExampleBubble : public BubbleDialogDelegateView {
void Init() override {
SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kVertical, gfx::Insets(50)));
- AddChildView(new Label(GetArrowName(arrow())));
+ AddChildView(std::make_unique<Label>(GetArrowName(arrow())));
}
private:
@@ -94,18 +94,18 @@ BubbleExample::~BubbleExample() = default;
void BubbleExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kHorizontal, gfx::Insets(), 10));
- no_shadow_ = new LabelButton(this, ASCIIToUTF16("No Shadow"));
- container->AddChildView(no_shadow_);
- no_shadow_opaque_ = new LabelButton(this, ASCIIToUTF16("Opaque Border"));
- container->AddChildView(no_shadow_opaque_);
- big_shadow_ = new LabelButton(this, ASCIIToUTF16("Big Shadow"));
- container->AddChildView(big_shadow_);
- small_shadow_ = new LabelButton(this, ASCIIToUTF16("Small Shadow"));
- container->AddChildView(small_shadow_);
- no_assets_ = new LabelButton(this, ASCIIToUTF16("No Assets"));
- container->AddChildView(no_assets_);
- persistent_ = new LabelButton(this, ASCIIToUTF16("Persistent"));
- container->AddChildView(persistent_);
+ no_shadow_ = container->AddChildView(
+ std::make_unique<LabelButton>(this, ASCIIToUTF16("No Shadow")));
+ no_shadow_opaque_ = container->AddChildView(
+ std::make_unique<LabelButton>(this, ASCIIToUTF16("Opaque Border")));
+ big_shadow_ = container->AddChildView(
+ std::make_unique<LabelButton>(this, ASCIIToUTF16("Big Shadow")));
+ small_shadow_ = container->AddChildView(
+ std::make_unique<LabelButton>(this, ASCIIToUTF16("Small Shadow")));
+ no_assets_ = container->AddChildView(
+ std::make_unique<LabelButton>(this, ASCIIToUTF16("No Assets")));
+ persistent_ = container->AddChildView(
+ std::make_unique<LabelButton>(this, ASCIIToUTF16("Persistent")));
}
void BubbleExample::ButtonPressed(Button* sender, const ui::Event& event) {
diff --git a/chromium/ui/views/examples/button_sticker_sheet.cc b/chromium/ui/views/examples/button_sticker_sheet.cc
index 8fca38898e1..1780375bb8b 100644
--- a/chromium/ui/views/examples/button_sticker_sheet.cc
+++ b/chromium/ui/views/examples/button_sticker_sheet.cc
@@ -33,7 +33,8 @@ GridLayout* MakeStretchyGridLayout(View* host, int ncols) {
const GridLayout::Alignment kColumnStretchesHorizontally = GridLayout::FILL;
const GridLayout::Alignment kColumnStretchesVertically = GridLayout::FILL;
const float kColumnDoesNotResize = 0.0;
- const GridLayout::SizeType kColumnUsesFixedSize = GridLayout::FIXED;
+ const GridLayout::ColumnSize kColumnUsesFixedSize =
+ GridLayout::ColumnSize::kFixed;
const int kColumnWidth = 96;
GridLayout* layout =
diff --git a/chromium/ui/views/examples/checkbox_example.cc b/chromium/ui/views/examples/checkbox_example.cc
index 953115abec5..676f0f79cc7 100644
--- a/chromium/ui/views/examples/checkbox_example.cc
+++ b/chromium/ui/views/examples/checkbox_example.cc
@@ -21,9 +21,9 @@ CheckboxExample::CheckboxExample() : ExampleBase("Checkbox") {}
CheckboxExample::~CheckboxExample() = default;
void CheckboxExample::CreateExampleView(View* container) {
- button_ = new Checkbox(base::ASCIIToUTF16("Checkbox"), this);
container->SetLayoutManager(std::make_unique<FillLayout>());
- container->AddChildView(button_);
+ button_ = container->AddChildView(
+ std::make_unique<Checkbox>(base::ASCIIToUTF16("Checkbox"), this));
}
void CheckboxExample::ButtonPressed(Button* sender, const ui::Event& event) {
diff --git a/chromium/ui/views/examples/colored_dialog_example.cc b/chromium/ui/views/examples/colored_dialog_example.cc
new file mode 100644
index 00000000000..de07088cb51
--- /dev/null
+++ b/chromium/ui/views/examples/colored_dialog_example.cc
@@ -0,0 +1,176 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/examples/colored_dialog_example.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/containers/adapters.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/vector_icon_types.h"
+#include "ui/native_theme/native_theme_color_id.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/layout_provider.h"
+#include "ui/views/vector_icons.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace examples {
+
+class ThemeTrackingCheckbox : public views::Checkbox,
+ public views::ButtonListener {
+ public:
+ explicit ThemeTrackingCheckbox(const base::string16& label)
+ : Checkbox(label, this) {}
+ ThemeTrackingCheckbox(const ThemeTrackingCheckbox&) = delete;
+ ThemeTrackingCheckbox& operator=(const ThemeTrackingCheckbox&) = delete;
+ ~ThemeTrackingCheckbox() override = default;
+
+ // views::Checkbox
+ void OnThemeChanged() override {
+ views::Checkbox::OnThemeChanged();
+
+ SetChecked(GetNativeTheme()->ShouldUseDarkColors());
+ }
+
+ // ButtonListener
+ void ButtonPressed(views::Button* sender, const ui::Event& event) override {
+ GetNativeTheme()->set_use_dark_colors(GetChecked());
+ GetWidget()->ThemeChanged();
+ }
+};
+
+class TextVectorImageButton : public views::MdTextButton {
+ public:
+ TextVectorImageButton(ButtonListener* listener,
+ const base::string16& text,
+ const gfx::VectorIcon& icon)
+ : MdTextButton(listener, style::CONTEXT_BUTTON_MD), icon_(icon) {
+ SetText(text);
+ }
+ TextVectorImageButton(const TextVectorImageButton&) = delete;
+ TextVectorImageButton& operator=(const TextVectorImageButton&) = delete;
+ ~TextVectorImageButton() override = default;
+
+ void OnThemeChanged() override {
+ views::MdTextButton::OnThemeChanged();
+
+ // Use the text color for the associated vector image.
+ SetImage(views::Button::ButtonState::STATE_NORMAL,
+ gfx::CreateVectorIcon(icon_, label()->GetEnabledColor()));
+ }
+
+ private:
+ const gfx::VectorIcon& icon_;
+};
+
+ColoredDialog::ColoredDialog(AcceptCallback accept_callback) {
+ SetAcceptCallback(base::BindOnce(
+ [](ColoredDialog* dialog, AcceptCallback callback) {
+ std::move(callback).Run(dialog->textfield_->GetText());
+ },
+ base::Unretained(this), std::move(accept_callback)));
+
+ SetTitle(l10n_util::GetStringUTF16(IDS_COLORED_DIALOG_TITLE));
+
+ SetLayoutManager(std::make_unique<views::FillLayout>());
+ set_margins(views::LayoutProvider::Get()->GetDialogInsetsForContentType(
+ views::CONTROL, views::CONTROL));
+
+ textfield_ = AddChildView(std::make_unique<views::Textfield>());
+ textfield_->SetPlaceholderText(
+ l10n_util::GetStringUTF16(IDS_COLORED_DIALOG_TEXTFIELD_PLACEHOLDER));
+ textfield_->SetAccessibleName(
+ l10n_util::GetStringUTF16(IDS_COLORED_DIALOG_TEXTFIELD_AX_LABEL));
+ textfield_->set_controller(this);
+
+ SetButtonLabel(ui::DIALOG_BUTTON_OK,
+ l10n_util::GetStringUTF16(IDS_COLORED_DIALOG_SUBMIT_BUTTON));
+ SetButtonEnabled(ui::DIALOG_BUTTON_OK, false);
+}
+
+ColoredDialog::~ColoredDialog() = default;
+
+ui::ModalType ColoredDialog::GetModalType() const {
+ return ui::MODAL_TYPE_WINDOW;
+}
+
+bool ColoredDialog::ShouldShowCloseButton() const {
+ return false;
+}
+
+void ColoredDialog::ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) {
+ SetButtonEnabled(ui::DIALOG_BUTTON_OK, !textfield_->GetText().empty());
+ DialogModelChanged();
+}
+
+ColoredDialogChooser::ColoredDialogChooser() {
+ views::LayoutProvider* provider = views::LayoutProvider::Get();
+ const int vertical_spacing =
+ provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL);
+ auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
+ views::BoxLayout::Orientation::kVertical, gfx::Insets(),
+ vertical_spacing));
+ layout->set_cross_axis_alignment(
+ views::BoxLayout::CrossAxisAlignment::kStart);
+
+ AddChildView(std::make_unique<ThemeTrackingCheckbox>(
+ l10n_util::GetStringUTF16(IDS_COLORED_DIALOG_CHOOSER_CHECKBOX)));
+
+ AddChildView(std::make_unique<TextVectorImageButton>(
+ this, l10n_util::GetStringUTF16(IDS_COLORED_DIALOG_CHOOSER_BUTTON),
+ views::kInfoIcon));
+
+ confirmation_label_ = AddChildView(
+ std::make_unique<views::Label>(base::string16(), style::CONTEXT_LABEL));
+ confirmation_label_->SetVisible(false);
+}
+
+ColoredDialogChooser::~ColoredDialogChooser() = default;
+
+void ColoredDialogChooser::ButtonPressed(Button* sender,
+ const ui::Event& event) {
+ // Create the colored dialog.
+ views::Widget* widget = DialogDelegate::CreateDialogWidget(
+ new ColoredDialog(base::BindOnce(&ColoredDialogChooser::OnFeedbackSubmit,
+ base::Unretained(this))),
+ nullptr, GetWidget()->GetNativeView());
+ widget->Show();
+}
+
+void ColoredDialogChooser::OnFeedbackSubmit(base::string16 text) {
+ constexpr base::TimeDelta kConfirmationDuration =
+ base::TimeDelta::FromSeconds(3);
+
+ confirmation_label_->SetText(l10n_util::GetStringFUTF16(
+ IDS_COLORED_DIALOG_CHOOSER_CONFIRM_LABEL, text));
+ confirmation_label_->SetVisible(true);
+
+ confirmation_timer_.Start(
+ FROM_HERE, kConfirmationDuration,
+ base::BindOnce([](views::View* view) { view->SetVisible(false); },
+ confirmation_label_));
+}
+
+ColoredDialogExample::ColoredDialogExample() : ExampleBase("Colored Dialog") {}
+
+ColoredDialogExample::~ColoredDialogExample() = default;
+
+void ColoredDialogExample::CreateExampleView(views::View* container) {
+ container->SetLayoutManager(std::make_unique<views::FillLayout>());
+ container->AddChildView(std::make_unique<ColoredDialogChooser>());
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/colored_dialog_example.h b/chromium/ui/views/examples/colored_dialog_example.h
new file mode 100644
index 00000000000..82b5c0a571c
--- /dev/null
+++ b/chromium/ui/views/examples/colored_dialog_example.h
@@ -0,0 +1,77 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_EXAMPLES_COLORED_DIALOG_EXAMPLE_H_
+#define UI_VIEWS_EXAMPLES_COLORED_DIALOG_EXAMPLE_H_
+
+#include "base/timer/timer.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/examples/example_base.h"
+#include "ui/views/view.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace views {
+
+class Button;
+class Label;
+
+namespace examples {
+
+class ColoredDialog : public views::DialogDelegateView,
+ public views::TextfieldController {
+ public:
+ using AcceptCallback = base::OnceCallback<void(base::string16)>;
+
+ explicit ColoredDialog(AcceptCallback accept_callback);
+ ColoredDialog(const ColoredDialog&) = delete;
+ ColoredDialog& operator=(const ColoredDialog&) = delete;
+ ~ColoredDialog() override;
+
+ protected:
+ // views::DialogDelegateView
+ ui::ModalType GetModalType() const override;
+ bool ShouldShowCloseButton() const override;
+
+ // views::TextfieldController
+ void ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) override;
+
+ private:
+ views::Textfield* textfield_;
+};
+
+class ColoredDialogChooser : public views::View, public views::ButtonListener {
+ public:
+ ColoredDialogChooser();
+ ColoredDialogChooser(const ColoredDialogChooser&) = delete;
+ ColoredDialogChooser& operator=(const ColoredDialogChooser&) = delete;
+ ~ColoredDialogChooser() override;
+
+ // ButtonListener
+ void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+ private:
+ void OnFeedbackSubmit(base::string16 text);
+
+ views::Label* confirmation_label_;
+ base::OneShotTimer confirmation_timer_;
+};
+
+// An example that exercises BubbleDialogDelegateView or DialogDelegateView.
+class VIEWS_EXAMPLES_EXPORT ColoredDialogExample : public ExampleBase {
+ public:
+ ColoredDialogExample();
+ ColoredDialogExample(const ColoredDialogExample&) = delete;
+ ColoredDialogExample& operator=(const ColoredDialogExample&) = delete;
+ ~ColoredDialogExample() override;
+
+ // ExampleBase
+ void CreateExampleView(views::View* container) override;
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_COLORED_DIALOG_EXAMPLE_H_
diff --git a/chromium/ui/views/examples/combobox_example.cc b/chromium/ui/views/examples/combobox_example.cc
index 178a465e430..dc1e8bba76f 100644
--- a/chromium/ui/views/examples/combobox_example.cc
+++ b/chromium/ui/views/examples/combobox_example.cc
@@ -41,20 +41,19 @@ ComboboxExample::ComboboxExample() : ExampleBase("Combo Box") {}
ComboboxExample::~ComboboxExample() = default;
void ComboboxExample::CreateExampleView(View* container) {
- combobox_ = new Combobox(std::make_unique<ComboboxModelExample>());
+ container->SetLayoutManager(std::make_unique<BoxLayout>(
+ BoxLayout::Orientation::kVertical, gfx::Insets(10, 0), 5));
+
+ combobox_ = container->AddChildView(
+ std::make_unique<Combobox>(std::make_unique<ComboboxModelExample>()));
combobox_->set_listener(this);
combobox_->SetSelectedIndex(3);
- auto* disabled_combobox =
- new Combobox(std::make_unique<ComboboxModelExample>());
+ auto* disabled_combobox = container->AddChildView(
+ std::make_unique<Combobox>(std::make_unique<ComboboxModelExample>()));
disabled_combobox->set_listener(this);
disabled_combobox->SetSelectedIndex(4);
disabled_combobox->SetEnabled(false);
-
- container->SetLayoutManager(std::make_unique<BoxLayout>(
- BoxLayout::Orientation::kVertical, gfx::Insets(10, 0), 5));
- container->AddChildView(combobox_);
- container->AddChildView(disabled_combobox);
}
void ComboboxExample::OnPerformAction(Combobox* combobox) {
diff --git a/chromium/ui/views/examples/create_examples.cc b/chromium/ui/views/examples/create_examples.cc
new file mode 100644
index 00000000000..b9805665713
--- /dev/null
+++ b/chromium/ui/views/examples/create_examples.cc
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/examples/create_examples.h"
+
+#include <utility>
+
+#include "ui/views/examples/ax_example.h"
+#include "ui/views/examples/box_layout_example.h"
+#include "ui/views/examples/bubble_example.h"
+#include "ui/views/examples/button_example.h"
+#include "ui/views/examples/button_sticker_sheet.h"
+#include "ui/views/examples/checkbox_example.h"
+#include "ui/views/examples/colored_dialog_example.h"
+#include "ui/views/examples/combobox_example.h"
+#include "ui/views/examples/dialog_example.h"
+#include "ui/views/examples/flex_layout_example.h"
+#include "ui/views/examples/label_example.h"
+#include "ui/views/examples/link_example.h"
+#include "ui/views/examples/login_bubble_dialog.h"
+#include "ui/views/examples/menu_example.h"
+#include "ui/views/examples/message_box_example.h"
+#include "ui/views/examples/multiline_example.h"
+#include "ui/views/examples/native_theme_example.h"
+#include "ui/views/examples/progress_bar_example.h"
+#include "ui/views/examples/radio_button_example.h"
+#include "ui/views/examples/scroll_view_example.h"
+#include "ui/views/examples/slider_example.h"
+#include "ui/views/examples/tabbed_pane_example.h"
+#include "ui/views/examples/table_example.h"
+#include "ui/views/examples/text_example.h"
+#include "ui/views/examples/textfield_example.h"
+#include "ui/views/examples/throbber_example.h"
+#include "ui/views/examples/toggle_button_example.h"
+#include "ui/views/examples/tree_view_example.h"
+#include "ui/views/examples/vector_example.h"
+#include "ui/views/examples/widget_example.h"
+
+namespace views {
+namespace examples {
+
+// Creates the default set of examples.
+ExampleVector CreateExamples(ExampleVector extra_examples) {
+ ExampleVector examples = std::move(extra_examples);
+ examples.push_back(std::make_unique<AxExample>());
+ examples.push_back(std::make_unique<BoxLayoutExample>());
+ examples.push_back(std::make_unique<BubbleExample>());
+ examples.push_back(std::make_unique<ButtonExample>());
+ examples.push_back(std::make_unique<ButtonStickerSheet>());
+ examples.push_back(std::make_unique<CheckboxExample>());
+ examples.push_back(std::make_unique<ColoredDialogExample>());
+ examples.push_back(std::make_unique<ComboboxExample>());
+ examples.push_back(std::make_unique<DialogExample>());
+ examples.push_back(std::make_unique<FlexLayoutExample>());
+ examples.push_back(std::make_unique<LabelExample>());
+ examples.push_back(std::make_unique<LinkExample>());
+ examples.push_back(std::make_unique<LoginBubbleDialogExample>());
+ examples.push_back(std::make_unique<MenuExample>());
+ examples.push_back(std::make_unique<MessageBoxExample>());
+ examples.push_back(std::make_unique<MultilineExample>());
+ examples.push_back(std::make_unique<NativeThemeExample>());
+ examples.push_back(std::make_unique<ProgressBarExample>());
+ examples.push_back(std::make_unique<RadioButtonExample>());
+ examples.push_back(std::make_unique<ScrollViewExample>());
+ examples.push_back(std::make_unique<SliderExample>());
+ examples.push_back(std::make_unique<TabbedPaneExample>());
+ examples.push_back(std::make_unique<TableExample>());
+ examples.push_back(std::make_unique<TextExample>());
+ examples.push_back(std::make_unique<TextfieldExample>());
+ examples.push_back(std::make_unique<ToggleButtonExample>());
+ examples.push_back(std::make_unique<ThrobberExample>());
+ examples.push_back(std::make_unique<TreeViewExample>());
+ examples.push_back(std::make_unique<VectorExample>());
+ examples.push_back(std::make_unique<WidgetExample>());
+ return examples;
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/create_examples.h b/chromium/ui/views/examples/create_examples.h
new file mode 100644
index 00000000000..39f1d02181e
--- /dev/null
+++ b/chromium/ui/views/examples/create_examples.h
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_EXAMPLES_CREATE_EXAMPLES_H_
+#define UI_VIEWS_EXAMPLES_CREATE_EXAMPLES_H_
+
+#include <memory>
+#include <vector>
+
+#include "ui/views/examples/example_base.h"
+#include "ui/views/examples/views_examples_export.h"
+
+namespace views {
+namespace examples {
+
+// Creates the default set of examples.
+ExampleVector VIEWS_EXAMPLES_EXPORT
+CreateExamples(ExampleVector extra_examples = ExampleVector());
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_CREATE_EXAMPLES_H_
diff --git a/chromium/ui/views/examples/dialog_example.cc b/chromium/ui/views/examples/dialog_example.cc
index efdc6f90351..70e7fd417d7 100644
--- a/chromium/ui/views/examples/dialog_example.cc
+++ b/chromium/ui/views/examples/dialog_example.cc
@@ -55,7 +55,7 @@ class DialogExample::Delegate : public virtual DialogType {
this->AddChildView(body);
if (parent_->has_extra_button_->GetChecked()) {
- DialogDelegate::SetExtraView(MdTextButton::CreateSecondaryUiButton(
+ DialogDelegate::SetExtraView(MdTextButton::Create(
nullptr, parent_->extra_button_label_->GetText()));
}
@@ -137,13 +137,13 @@ void DialogExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<views::GridLayout>());
ColumnSet* column_set = layout->AddColumnSet(kFieldsColumnId);
column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, kFixed,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(kFixed, horizontal_spacing);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kStretchy,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(kFixed, horizontal_spacing);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
StartTextfieldRow(layout, &title_, "Dialog Title", "Title");
StartTextfieldRow(layout, &body_, "Dialog Body Text", "Body Text");
@@ -169,13 +169,13 @@ void DialogExample::CreateExampleView(View* container) {
column_set = layout->AddColumnSet(kButtonsColumnId);
column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, kStretchy,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRowWithPadding(
kFixed, kButtonsColumnId, kFixed,
provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL));
- show_ = layout->AddView(
- MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Show")));
+ show_ =
+ layout->AddView(MdTextButton::Create(this, base::ASCIIToUTF16("Show")));
}
void DialogExample::StartRowWithLabel(GridLayout* layout, const char* label) {
diff --git a/chromium/ui/views/examples/example_base.h b/chromium/ui/views/examples/example_base.h
index 231011b6101..69e9105692a 100644
--- a/chromium/ui/views/examples/example_base.h
+++ b/chromium/ui/views/examples/example_base.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_EXAMPLES_EXAMPLE_BASE_H_
#include <string>
+#include <vector>
#include "base/macros.h"
#include "ui/views/examples/views_examples_export.h"
@@ -38,6 +39,8 @@ class VIEWS_EXAMPLES_EXPORT ExampleBase {
DISALLOW_COPY_AND_ASSIGN(ExampleBase);
};
+using ExampleVector = std::vector<std::unique_ptr<ExampleBase>>;
+
} // namespace examples
} // namespace views
diff --git a/chromium/ui/views/examples/examples_exit_code.h b/chromium/ui/views/examples/examples_exit_code.h
new file mode 100644
index 00000000000..3ef5e79a5e5
--- /dev/null
+++ b/chromium/ui/views/examples/examples_exit_code.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_EXAMPLES_EXAMPLES_EXIT_CODE_H_
+#define UI_VIEWS_EXAMPLES_EXAMPLES_EXIT_CODE_H_
+
+namespace views {
+namespace examples {
+
+enum class ExamplesExitCode {
+ // Comparison succeeded.
+ kSucceeded = 0,
+ // Screenshot image empty.
+ kImageEmpty,
+ // Comparison failed.
+ kFailed,
+ // No comparison attempted.
+ kNone,
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_EXAMPLES_EXIT_CODE_H_
diff --git a/chromium/ui/views/examples/examples_main.cc b/chromium/ui/views/examples/examples_main.cc
index a3e2c965c77..82ec4ab5200 100644
--- a/chromium/ui/views/examples/examples_main.cc
+++ b/chromium/ui/views/examples/examples_main.cc
@@ -2,168 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <memory>
-
#include "base/at_exit.h"
-#include "base/base_switches.h"
#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/files/file_path.h"
-#include "base/i18n/icu_util.h"
-#include "base/memory/ptr_util.h"
-#include "base/path_service.h"
-#include "base/power_monitor/power_monitor.h"
-#include "base/power_monitor/power_monitor_device_source.h"
-#include "base/run_loop.h"
-#include "base/test/scoped_run_loop_timeout.h"
-#include "base/test/task_environment.h"
-#include "base/test/test_discardable_memory_allocator.h"
#include "base/test/test_timeouts.h"
-#include "build/build_config.h"
-#include "components/viz/host/host_frame_sink_manager.h"
-#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
-#include "mojo/core/embedder/embedder.h"
-#include "ui/base/ime/init/input_method_initializer.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_paths.h"
-#include "ui/compositor/test/in_process_context_factory.h"
-#include "ui/display/screen.h"
-#include "ui/gfx/font_util.h"
-#include "ui/gl/gl_switches.h"
-#include "ui/gl/init/gl_factory.h"
-#include "ui/views/buildflags.h"
-#include "ui/views/examples/example_base.h"
-#include "ui/views/examples/examples_window.h"
-#include "ui/views/test/desktop_test_views_delegate.h"
-
-#if defined(USE_AURA)
-#include "ui/aura/env.h"
-#include "ui/wm/core/wm_state.h"
-#endif
-
-#if BUILDFLAG(ENABLE_DESKTOP_AURA)
-#include "ui/views/widget/desktop_aura/desktop_screen.h"
-#endif
-
-#if defined(OS_WIN)
-#include "ui/base/win/scoped_ole_initializer.h"
-#endif
-
-#if defined(USE_OZONE)
-#include "ui/ozone/public/ozone_platform.h"
-#endif
-
-#if defined(USE_X11)
-#include "ui/gfx/x/x11_connection.h" // nogncheck
-#endif
-
-base::LazyInstance<base::TestDiscardableMemoryAllocator>::DestructorAtExit
- g_discardable_memory_allocator = LAZY_INSTANCE_INITIALIZER;
+#include "ui/views/examples/examples_main_proc.h"
int main(int argc, char** argv) {
-#if defined(OS_WIN)
- ui::ScopedOleInitializer ole_initializer;
-#endif
-
base::CommandLine::Init(argc, argv);
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
- // Disabling Direct Composition works around the limitation that
- // InProcessContextFactory doesn't work with Direct Composition, causing the
- // window to not render. See http://crbug.com/936249.
- command_line->AppendSwitch(switches::kDisableDirectComposition);
-
- base::FeatureList::InitializeInstance(
- command_line->GetSwitchValueASCII(switches::kEnableFeatures),
- command_line->GetSwitchValueASCII(switches::kDisableFeatures));
-
- base::AtExitManager at_exit;
-
- mojo::core::Init();
-
-#if defined(USE_OZONE)
- ui::OzonePlatform::InitParams params;
- params.single_process = true;
- ui::OzonePlatform::InitializeForGPU(params);
-#endif
-
-#if defined(USE_X11)
- // This demo uses InProcessContextFactory which uses X on a separate Gpu
- // thread.
- gfx::InitializeThreadedX11();
-#endif
-
- gl::init::InitializeGLOneOff();
-
- // The use of base::test::TaskEnvironment below relies on the timeout
- // values from TestTimeouts. This ensures they're properly initialized.
+ // The use of base::test::TaskEnvironment in the following function relies on
+ // the timeout values from TestTimeouts.
TestTimeouts::Initialize();
- // Viz depends on the task environment to correctly tear down.
- base::test::TaskEnvironment task_environment(
- base::test::TaskEnvironment::MainThreadType::UI);
-
- // The ContextFactory must exist before any Compositors are created.
- viz::HostFrameSinkManager host_frame_sink_manager;
- viz::ServerSharedBitmapManager shared_bitmap_manager;
- viz::FrameSinkManagerImpl frame_sink_manager(&shared_bitmap_manager);
- host_frame_sink_manager.SetLocalManager(&frame_sink_manager);
- frame_sink_manager.SetLocalClient(&host_frame_sink_manager);
- auto context_factory = std::make_unique<ui::InProcessContextFactory>(
- &host_frame_sink_manager, &frame_sink_manager);
- context_factory->set_use_test_surface(false);
-
- base::i18n::InitializeICU();
-
- ui::RegisterPathProvider();
-
- base::FilePath ui_test_pak_path;
- CHECK(base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
- ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
-
- base::DiscardableMemoryAllocator::SetInstance(
- g_discardable_memory_allocator.Pointer());
-
- base::PowerMonitor::Initialize(
- std::make_unique<base::PowerMonitorDeviceSource>());
-
- gfx::InitializeFonts();
-
-#if defined(USE_AURA)
- std::unique_ptr<aura::Env> env = aura::Env::CreateInstance();
- aura::Env::GetInstance()->set_context_factory(context_factory.get());
-#endif
- ui::InitializeInputMethodForTesting();
-
- {
- views::DesktopTestViewsDelegate views_delegate;
-#if defined(USE_AURA)
- wm::WMState wm_state;
-#endif
-#if BUILDFLAG(ENABLE_DESKTOP_AURA)
- std::unique_ptr<display::Screen> desktop_screen(
- views::CreateDesktopScreen());
- display::Screen::SetScreenInstance(desktop_screen.get());
-#endif
-
- // This app isn't a test and shouldn't timeout.
- base::test::ScopedDisableRunLoopTimeout disable_timeout;
-
- base::RunLoop run_loop;
- views::examples::ShowExamplesWindow(run_loop.QuitClosure());
-
- run_loop.Run();
-
- ui::ResourceBundle::CleanupSharedInstance();
- }
-
- ui::ShutdownInputMethod();
-
-#if defined(USE_AURA)
- env.reset();
-#endif
+ base::AtExitManager at_exit;
- return 0;
+ return static_cast<int>(views::examples::ExamplesMainProc());
}
diff --git a/chromium/ui/views/examples/examples_main_proc.cc b/chromium/ui/views/examples/examples_main_proc.cc
new file mode 100644
index 00000000000..fe417da38a3
--- /dev/null
+++ b/chromium/ui/views/examples/examples_main_proc.cc
@@ -0,0 +1,198 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/examples/examples_main_proc.h"
+
+#include <memory>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/i18n/icu_util.h"
+#include "base/lazy_instance.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_run_loop_timeout.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_discardable_memory_allocator.h"
+#include "base/test/test_timeouts.h"
+#include "build/build_config.h"
+#include "components/viz/host/host_frame_sink_manager.h"
+#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "mojo/core/embedder/embedder.h"
+#include "ui/base/ime/init/input_method_initializer.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_paths.h"
+#include "ui/compositor/compositor_switches.h"
+#include "ui/compositor/test/in_process_context_factory.h"
+#include "ui/compositor/test/test_context_factories.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/font_util.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gl/gl_switches.h"
+#include "ui/gl/init/gl_factory.h"
+#include "ui/views/buildflags.h"
+#include "ui/views/examples/example_base.h"
+#include "ui/views/examples/examples_window.h"
+#include "ui/views/test/desktop_test_views_delegate.h"
+#include "ui/views/widget/any_widget_observer.h"
+#include "ui/views/widget/widget.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/env.h"
+#include "ui/wm/core/wm_state.h"
+#endif
+
+#if BUILDFLAG(ENABLE_DESKTOP_AURA)
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#endif
+
+#if defined(OS_WIN)
+#include "ui/base/win/scoped_ole_initializer.h"
+#include "ui/views/examples/examples_skia_gold_pixel_diff.h"
+#endif
+
+#if defined(USE_OZONE)
+#include "ui/ozone/public/ozone_platform.h"
+#endif
+
+namespace views {
+namespace examples {
+
+base::LazyInstance<base::TestDiscardableMemoryAllocator>::DestructorAtExit
+ g_discardable_memory_allocator = LAZY_INSTANCE_INITIALIZER;
+
+ExamplesExitCode ExamplesMainProc(bool under_test) {
+#if defined(OS_WIN)
+ ui::ScopedOleInitializer ole_initializer;
+#endif
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
+ // Disabling Direct Composition works around the limitation that
+ // InProcessContextFactory doesn't work with Direct Composition, causing the
+ // window to not render. See http://crbug.com/936249.
+ command_line->AppendSwitch(switches::kDisableDirectComposition);
+
+ base::FeatureList::InitializeInstance(
+ command_line->GetSwitchValueASCII(switches::kEnableFeatures),
+ command_line->GetSwitchValueASCII(switches::kDisableFeatures));
+
+ if (under_test)
+ command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
+
+ mojo::core::Init();
+
+#if defined(USE_OZONE)
+ ui::OzonePlatform::InitParams params;
+ params.single_process = true;
+ ui::OzonePlatform::InitializeForGPU(params);
+#endif
+
+ gl::init::InitializeGLOneOff();
+
+ // Viz depends on the task environment to correctly tear down.
+ base::test::TaskEnvironment task_environment(
+ base::test::TaskEnvironment::MainThreadType::UI);
+
+ // The ContextFactory must exist before any Compositors are created.
+ auto context_factories =
+ std::make_unique<ui::TestContextFactories>(under_test);
+ context_factories->SetUseTestSurface(false);
+
+ base::i18n::InitializeICU();
+
+ ui::RegisterPathProvider();
+
+ base::FilePath ui_test_pak_path;
+ CHECK(base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
+
+ base::FilePath views_examples_resources_pak_path;
+ CHECK(base::PathService::Get(base::DIR_MODULE,
+ &views_examples_resources_pak_path));
+ ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+ views_examples_resources_pak_path.AppendASCII(
+ "views_examples_resources.pak"),
+ ui::SCALE_FACTOR_100P);
+
+ base::DiscardableMemoryAllocator::SetInstance(
+ g_discardable_memory_allocator.Pointer());
+
+ base::PowerMonitor::Initialize(
+ std::make_unique<base::PowerMonitorDeviceSource>());
+
+ gfx::InitializeFonts();
+
+#if defined(USE_AURA)
+ std::unique_ptr<aura::Env> env = aura::Env::CreateInstance();
+ aura::Env::GetInstance()->set_context_factory(
+ context_factories->GetContextFactory());
+#endif
+ ui::InitializeInputMethodForTesting();
+
+ ExamplesExitCode compare_result = ExamplesExitCode::kSucceeded;
+
+ {
+ views::DesktopTestViewsDelegate views_delegate;
+#if defined(USE_AURA)
+ wm::WMState wm_state;
+#endif
+#if BUILDFLAG(ENABLE_DESKTOP_AURA)
+ std::unique_ptr<display::Screen> desktop_screen =
+ base::WrapUnique(views::CreateDesktopScreen());
+ display::Screen::SetScreenInstance(desktop_screen.get());
+#endif
+
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+
+#if defined(OS_WIN)
+ ExamplesSkiaGoldPixelDiff pixel_diff;
+ views::AnyWidgetObserver widget_observer{
+ views::test::AnyWidgetTestPasskey()};
+
+ // If this app isn't a test, it shouldn't timeout.
+ auto disable_timeout =
+ std::make_unique<base::test::ScopedDisableRunLoopTimeout>();
+
+ if (under_test) {
+ pixel_diff.Init("ViewsExamples");
+ widget_observer.set_shown_callback(
+ base::BindRepeating(&ExamplesSkiaGoldPixelDiff::OnExamplesWindowShown,
+ base::Unretained(&pixel_diff)));
+ // Enable the timeout since we're not running in a test.
+ disable_timeout.reset();
+ }
+#else
+ base::test::ScopedDisableRunLoopTimeout disable_timeout;
+#endif
+
+ views::examples::ShowExamplesWindow(run_loop.QuitClosure());
+
+ run_loop.Run();
+
+#if defined(OS_WIN)
+ compare_result = pixel_diff.get_result();
+#endif
+
+ ui::ResourceBundle::CleanupSharedInstance();
+ }
+
+ ui::ShutdownInputMethod();
+
+#if defined(USE_AURA)
+ env.reset();
+#endif
+
+ return compare_result;
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/examples_main_proc.h b/chromium/ui/views/examples/examples_main_proc.h
new file mode 100644
index 00000000000..61b258f262a
--- /dev/null
+++ b/chromium/ui/views/examples/examples_main_proc.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_EXAMPLES_EXAMPLES_MAIN_PROC_H_
+#define UI_VIEWS_EXAMPLES_EXAMPLES_MAIN_PROC_H_
+
+#include "ui/views/examples/examples_exit_code.h"
+
+namespace views {
+namespace examples {
+
+ExamplesExitCode ExamplesMainProc(bool under_test = false);
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_EXAMPLES_MAIN_PROC_H_
diff --git a/chromium/ui/views/examples/examples_skia_gold_pixel_diff.cc b/chromium/ui/views/examples/examples_skia_gold_pixel_diff.cc
new file mode 100644
index 00000000000..ffabc89ae2b
--- /dev/null
+++ b/chromium/ui/views/examples/examples_skia_gold_pixel_diff.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/examples/examples_skia_gold_pixel_diff.h"
+
+#include "base/run_loop.h"
+#include "ui/snapshot/snapshot.h"
+#include "ui/views/examples/examples_window.h"
+
+#if defined(USE_AURA)
+#include "ui/snapshot/snapshot_aura.h"
+#endif
+
+namespace views {
+namespace examples {
+
+ExamplesSkiaGoldPixelDiff::ExamplesSkiaGoldPixelDiff() = default;
+ExamplesSkiaGoldPixelDiff::~ExamplesSkiaGoldPixelDiff() = default;
+
+ExamplesExitCode ExamplesSkiaGoldPixelDiff::CompareScreenshot(
+ const std::string& screenshot_name,
+ const views::Widget* widget) const {
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ gfx::Rect widget_bounds = widget->GetRootView()->bounds();
+#if defined(USE_AURA)
+ ui::GrabWindowSnapshotAsyncAura(
+#else
+ ui::GrabWindowSnapshotAsync(
+#endif
+ widget->GetNativeWindow(), widget_bounds,
+ base::BindOnce(
+ [](gfx::Image* screenshot, base::OnceClosure quit_loop,
+ gfx::Image image) {
+ *screenshot = image;
+ std::move(quit_loop).Run();
+ },
+ &screenshot_, run_loop.QuitClosure()));
+ run_loop.Run();
+ if (screenshot_.IsEmpty())
+ return ExamplesExitCode::kImageEmpty;
+ return SkiaGoldPixelDiff::CompareScreenshot(screenshot_name,
+ *screenshot_.ToSkBitmap())
+ ? ExamplesExitCode::kSucceeded
+ : ExamplesExitCode::kFailed;
+}
+
+void ExamplesSkiaGoldPixelDiff::DoScreenshot(views::Widget* widget) {
+ result_ = CompareScreenshot("ExampleWindow", widget);
+ widget->Close();
+}
+
+void ExamplesSkiaGoldPixelDiff::OnExamplesWindowShown(views::Widget* widget) {
+ if (widget->GetName() == views::examples::kExamplesWidgetName) {
+ DoScreenshot(widget);
+ }
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/examples_skia_gold_pixel_diff.h b/chromium/ui/views/examples/examples_skia_gold_pixel_diff.h
new file mode 100644
index 00000000000..4bb102d97eb
--- /dev/null
+++ b/chromium/ui/views/examples/examples_skia_gold_pixel_diff.h
@@ -0,0 +1,39 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_EXAMPLES_EXAMPLES_SKIA_GOLD_PIXEL_DIFF_H_
+#define UI_VIEWS_EXAMPLES_EXAMPLES_SKIA_GOLD_PIXEL_DIFF_H_
+
+#include "ui/base/test/skia_gold_pixel_diff.h"
+
+#include "base/run_loop.h"
+#include "ui/gfx/image/image.h"
+#include "ui/views/examples/examples_exit_code.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace examples {
+
+class ExamplesSkiaGoldPixelDiff : public SkiaGoldPixelDiff {
+ public:
+ ExamplesSkiaGoldPixelDiff();
+ ~ExamplesSkiaGoldPixelDiff() override;
+
+ void OnExamplesWindowShown(views::Widget* widget);
+
+ ExamplesExitCode get_result() const { return result_; }
+
+ private:
+ ExamplesExitCode CompareScreenshot(const std::string& screenshot_name,
+ const views::Widget* widget) const;
+ void DoScreenshot(views::Widget* widget);
+
+ mutable gfx::Image screenshot_;
+ ExamplesExitCode result_ = ExamplesExitCode::kNone;
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_EXAMPLES_SKIA_GOLD_PIXEL_DIFF_H_
diff --git a/chromium/ui/views/examples/examples_unittest.cc b/chromium/ui/views/examples/examples_unittest.cc
new file mode 100644
index 00000000000..054ef30a83f
--- /dev/null
+++ b/chromium/ui/views/examples/examples_unittest.cc
@@ -0,0 +1,26 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/examples/examples_exit_code.h"
+#include "ui/views/examples/examples_main_proc.h"
+
+namespace views {
+namespace examples {
+
+#if defined(OS_WIN)
+#define TestViewsExamplesLaunches_MAYBE TestViewsExamplesLaunches
+#else
+#define TestViewsExamplesLaunches_MAYBE TestViewsExamplesLaunches_DISABLED
+#endif
+
+TEST(ExamplesTest, TestViewsExamplesLaunches_MAYBE) {
+ const ExamplesExitCode exit_code = ExamplesMainProc(true);
+ // Check the status of the Skia Gold comparison.
+ EXPECT_EQ(ExamplesExitCode::kSucceeded, exit_code);
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/examples_unittest_main.cc b/chromium/ui/views/examples/examples_unittest_main.cc
new file mode 100644
index 00000000000..65ed57e7fd7
--- /dev/null
+++ b/chromium/ui/views/examples/examples_unittest_main.cc
@@ -0,0 +1,14 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+
+int main(int argc, char** argv) {
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv,
+ base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc
index 4956b07f3ac..d2cde9bb4e0 100644
--- a/chromium/ui/views/examples/examples_window.cc
+++ b/chromium/ui/views/examples/examples_window.cc
@@ -10,43 +10,20 @@
#include <string>
#include <utility>
+#include "base/command_line.h"
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/ui_base_paths.h"
#include "ui/views/background.h"
#include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/controls/label.h"
-#include "ui/views/examples/ax_example.h"
-#include "ui/views/examples/box_layout_example.h"
-#include "ui/views/examples/bubble_example.h"
-#include "ui/views/examples/button_example.h"
-#include "ui/views/examples/button_sticker_sheet.h"
-#include "ui/views/examples/checkbox_example.h"
-#include "ui/views/examples/combobox_example.h"
-#include "ui/views/examples/dialog_example.h"
-#include "ui/views/examples/flex_layout_example.h"
-#include "ui/views/examples/label_example.h"
-#include "ui/views/examples/link_example.h"
-#include "ui/views/examples/menu_example.h"
-#include "ui/views/examples/message_box_example.h"
-#include "ui/views/examples/multiline_example.h"
-#include "ui/views/examples/native_theme_example.h"
-#include "ui/views/examples/progress_bar_example.h"
-#include "ui/views/examples/radio_button_example.h"
-#include "ui/views/examples/scroll_view_example.h"
-#include "ui/views/examples/slider_example.h"
-#include "ui/views/examples/tabbed_pane_example.h"
-#include "ui/views/examples/table_example.h"
-#include "ui/views/examples/text_example.h"
-#include "ui/views/examples/textfield_example.h"
-#include "ui/views/examples/throbber_example.h"
-#include "ui/views/examples/toggle_button_example.h"
-#include "ui/views/examples/tree_view_example.h"
-#include "ui/views/examples/vector_example.h"
-#include "ui/views/examples/widget_example.h"
+#include "ui/views/examples/create_examples.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/widget/widget.h"
@@ -55,55 +32,49 @@
namespace views {
namespace examples {
-using ExampleVector = std::vector<std::unique_ptr<ExampleBase>>;
+const char kExamplesWidgetName[] = "ExamplesWidget";
namespace {
-// Creates the default set of examples.
-ExampleVector CreateExamples() {
- ExampleVector examples;
- examples.push_back(std::make_unique<AxExample>());
- examples.push_back(std::make_unique<BoxLayoutExample>());
- examples.push_back(std::make_unique<BubbleExample>());
- examples.push_back(std::make_unique<ButtonExample>());
- examples.push_back(std::make_unique<ButtonStickerSheet>());
- examples.push_back(std::make_unique<CheckboxExample>());
- examples.push_back(std::make_unique<ComboboxExample>());
- examples.push_back(std::make_unique<DialogExample>());
- examples.push_back(std::make_unique<FlexLayoutExample>());
- examples.push_back(std::make_unique<LabelExample>());
- examples.push_back(std::make_unique<LinkExample>());
- examples.push_back(std::make_unique<MenuExample>());
- examples.push_back(std::make_unique<MessageBoxExample>());
- examples.push_back(std::make_unique<MultilineExample>());
- examples.push_back(std::make_unique<NativeThemeExample>());
- examples.push_back(std::make_unique<ProgressBarExample>());
- examples.push_back(std::make_unique<RadioButtonExample>());
- examples.push_back(std::make_unique<ScrollViewExample>());
- examples.push_back(std::make_unique<SliderExample>());
- examples.push_back(std::make_unique<TabbedPaneExample>());
- examples.push_back(std::make_unique<TableExample>());
- examples.push_back(std::make_unique<TextExample>());
- examples.push_back(std::make_unique<TextfieldExample>());
- examples.push_back(std::make_unique<ToggleButtonExample>());
- examples.push_back(std::make_unique<ThrobberExample>());
- examples.push_back(std::make_unique<TreeViewExample>());
- examples.push_back(std::make_unique<VectorExample>());
- examples.push_back(std::make_unique<WidgetExample>());
- return examples;
-}
+const char kEnableExamples[] = "enable-examples";
+
+ExampleVector GetExamplesToShow(ExampleVector examples) {
+ using StringVector = std::vector<std::string>;
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-struct ExampleTitleCompare {
- bool operator()(const std::unique_ptr<ExampleBase>& a,
- const std::unique_ptr<ExampleBase>& b) {
+ std::sort(examples.begin(), examples.end(), [](const auto& a, const auto& b) {
return a->example_title() < b->example_title();
+ });
+
+ std::string enable_examples =
+ command_line->GetSwitchValueASCII(kEnableExamples);
+ if (!enable_examples.empty()) {
+ StringVector enabled =
+ base::SplitString(enable_examples, ";,", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+
+ // Transform list of examples to just the list of names.
+ StringVector example_names;
+ std::transform(
+ examples.begin(), examples.end(), std::back_inserter(example_names),
+ [](const auto& example) { return example->example_title(); });
+
+ std::sort(enabled.begin(), enabled.end());
+
+ // Get an intersection of list of titles between the full list and the list
+ // from the command-line.
+ StringVector valid_examples =
+ base::STLSetIntersection<StringVector>(enabled, example_names);
+
+ // If there are still example names in the list, only include the examples
+ // from the list.
+ if (!valid_examples.empty()) {
+ base::EraseIf(examples, [valid_examples](auto& example) {
+ return std::find(valid_examples.begin(), valid_examples.end(),
+ example->example_title()) == valid_examples.end();
+ });
+ }
}
-};
-
-ExampleVector GetExamplesToShow(ExampleVector extra) {
- ExampleVector examples = CreateExamples();
- std::move(extra.begin(), extra.end(), std::back_inserter(examples));
- std::sort(examples.begin(), examples.end(), ExampleTitleCompare());
for (auto& example : examples)
example->CreateExampleView(example->example_view());
@@ -158,13 +129,15 @@ class ExamplesWindowContents : public WidgetDelegateView,
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddPaddingColumn(0, 5);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(0, 5);
layout->AddPaddingRow(0, 5);
layout->StartRow(0 /* no expand */, 0);
combobox_ = layout->AddView(std::move(combobox));
- if (combobox_model_->GetItemCount() > 0) {
+ auto item_count = combobox_model_->GetItemCount();
+ if (item_count > 0) {
+ combobox_->SetVisible(item_count > 1);
layout->StartRow(1, 0);
auto example_shown = std::make_unique<View>();
example_shown->SetLayoutManager(std::make_unique<FillLayout>());
@@ -236,17 +209,18 @@ class ExamplesWindowContents : public WidgetDelegateView,
ExamplesWindowContents* ExamplesWindowContents::instance_ = nullptr;
void ShowExamplesWindow(base::OnceClosure on_close,
- gfx::NativeWindow window_context,
- ExampleVector extra_examples) {
+ ExampleVector examples,
+ gfx::NativeWindow window_context) {
if (ExamplesWindowContents::instance()) {
ExamplesWindowContents::instance()->GetWidget()->Activate();
} else {
- ExampleVector examples = GetExamplesToShow(std::move(extra_examples));
+ examples = GetExamplesToShow(std::move(examples));
Widget* widget = new Widget;
Widget::InitParams params;
params.delegate =
new ExamplesWindowContents(std::move(on_close), std::move(examples));
params.context = window_context;
+ params.name = kExamplesWidgetName;
widget->Init(std::move(params));
widget->Show();
}
diff --git a/chromium/ui/views/examples/examples_window.h b/chromium/ui/views/examples/examples_window.h
index d7198df6a3d..93cff092763 100644
--- a/chromium/ui/views/examples/examples_window.h
+++ b/chromium/ui/views/examples/examples_window.h
@@ -9,23 +9,25 @@
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/strings/stringprintf.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/views/examples/create_examples.h"
+#include "ui/views/examples/example_base.h"
#include "ui/views/examples/views_examples_export.h"
namespace views {
namespace examples {
-class VIEWS_EXAMPLES_EXPORT ExampleBase;
+VIEWS_EXAMPLES_EXPORT extern const char kExamplesWidgetName[];
// Shows a window with the views examples in it. |extra_examples| contains any
// additional examples to add. |window_context| is used to determine where the
// window should be created (see |Widget::InitParams::context| for details).
VIEWS_EXAMPLES_EXPORT void ShowExamplesWindow(
base::OnceClosure on_close,
- gfx::NativeWindow window_context = nullptr,
- std::vector<std::unique_ptr<ExampleBase>> extra_examples =
- std::vector<std::unique_ptr<ExampleBase>>());
+ ExampleVector examples = CreateExamples(),
+ gfx::NativeWindow window_context = nullptr);
// Prints |string| in the status area, at the bottom of the window.
VIEWS_EXAMPLES_EXPORT void LogStatus(const std::string& string);
diff --git a/chromium/ui/views/examples/examples_window_with_content.cc b/chromium/ui/views/examples/examples_window_with_content.cc
index c9391fa8bd8..009108cebad 100644
--- a/chromium/ui/views/examples/examples_window_with_content.cc
+++ b/chromium/ui/views/examples/examples_window_with_content.cc
@@ -9,6 +9,8 @@
#include <vector>
#include "content/public/browser/browser_context.h"
+#include "ui/views/examples/create_examples.h"
+#include "ui/views/examples/example_base.h"
#include "ui/views/examples/webview_example.h"
namespace views {
@@ -17,10 +19,10 @@ namespace examples {
void ShowExamplesWindowWithContent(base::OnceClosure on_close,
content::BrowserContext* browser_context,
gfx::NativeWindow window_context) {
- std::vector<std::unique_ptr<ExampleBase>> extra_examples;
- extra_examples.push_back(std::make_unique<WebViewExample>(browser_context));
- ShowExamplesWindow(std::move(on_close), window_context,
- std::move(extra_examples));
+ ExampleVector examples;
+ examples.push_back(std::make_unique<WebViewExample>(browser_context));
+ ShowExamplesWindow(std::move(on_close), CreateExamples(std::move(examples)),
+ window_context);
}
} // namespace examples
diff --git a/chromium/ui/views/examples/examples_window_with_content.h b/chromium/ui/views/examples/examples_window_with_content.h
index dbcb1fbd806..26ad63ac75e 100644
--- a/chromium/ui/views/examples/examples_window_with_content.h
+++ b/chromium/ui/views/examples/examples_window_with_content.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_EXAMPLES_EXAMPLES_WINDOW_WITH_CONTENT_H_
#define UI_VIEWS_EXAMPLES_EXAMPLES_WINDOW_WITH_CONTENT_H_
+#include "base/callback_forward.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/examples/examples_window.h"
#include "ui/views/examples/views_examples_with_content_export.h"
diff --git a/chromium/ui/views/examples/examples_with_content_main_exe.cc b/chromium/ui/views/examples/examples_with_content_main.cc
index 7f978cae9ec..501a2fb7131 100644
--- a/chromium/ui/views/examples/examples_with_content_main_exe.cc
+++ b/chromium/ui/views/examples/examples_with_content_main.cc
@@ -3,11 +3,19 @@
// found in the LICENSE file.
#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
#include "build/build_config.h"
#include "content/public/browser/browser_context.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/views/examples/examples_window_with_content.h"
#include "ui/views_content_client/views_content_client.h"
+#if defined(OS_MACOSX)
+#include "sandbox/mac/seatbelt_exec.h"
+#endif
+
#if defined(OS_WIN)
#include "content/public/app/sandbox_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
@@ -15,6 +23,16 @@
namespace {
+void OnResourcesLoaded() {
+ base::FilePath views_examples_resources_pak_path;
+ CHECK(base::PathService::Get(base::DIR_MODULE,
+ &views_examples_resources_pak_path));
+ ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+ views_examples_resources_pak_path.AppendASCII(
+ "views_examples_resources.pak"),
+ ui::SCALE_FACTOR_100P);
+}
+
void ShowContentExampleWindow(ui::ViewsContentClient* views_content_client,
content::BrowserContext* browser_context,
gfx::NativeWindow window_context) {
@@ -43,9 +61,26 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
ui::ViewsContentClient views_content_client(instance, &sandbox_info);
#else
int main(int argc, const char** argv) {
+ base::CommandLine::Init(argc, argv);
ui::ViewsContentClient views_content_client(argc, argv);
#endif
+#if defined(OS_MACOSX)
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ // ViewsContentClient expects a const char** argv and
+ // CreateFromArgumentsResult expects a regular char** argv. Given this is a
+ // test program, a refactor from either end didn't seem worth it. As a result,
+ // use a const_cast instead.
+ sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
+ sandbox::SeatbeltExecServer::CreateFromArguments(
+ command_line->GetProgram().value().c_str(), argc,
+ const_cast<char**>(argv));
+ if (seatbelt.sandbox_required)
+ CHECK(seatbelt.server->InitializeSandbox());
+#endif
+
+ views_content_client.set_on_resources_loaded_callback(
+ base::BindOnce(&OnResourcesLoaded));
views_content_client.set_on_pre_main_message_loop_run_callback(base::BindOnce(
&ShowContentExampleWindow, base::Unretained(&views_content_client)));
return views_content_client.RunMain();
diff --git a/chromium/ui/views/examples/flex_layout_example.cc b/chromium/ui/views/examples/flex_layout_example.cc
index 3049fed0c78..2dedbc6a592 100644
--- a/chromium/ui/views/examples/flex_layout_example.cc
+++ b/chromium/ui/views/examples/flex_layout_example.cc
@@ -38,12 +38,12 @@ void FlexLayoutExample::CreateAdditionalControls(int vertical_pos) {
static const char* const cross_axis_values[4] = {"Stretch", "Start", "Center",
"End"};
- orientation_ = CreateCombobox(base::ASCIIToUTF16("Orientation"),
- orientation_values, 2, &vertical_pos);
- main_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Main axis"),
- main_axis_values, 3, &vertical_pos);
- cross_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Cross axis"),
- cross_axis_values, 4, &vertical_pos);
+ orientation_ = CreateAndAddCombobox(base::ASCIIToUTF16("Orientation"),
+ orientation_values, 2, &vertical_pos);
+ main_axis_alignment_ = CreateAndAddCombobox(
+ base::ASCIIToUTF16("Main axis"), main_axis_values, 3, &vertical_pos);
+ cross_axis_alignment_ = CreateAndAddCombobox(
+ base::ASCIIToUTF16("Cross axis"), cross_axis_values, 4, &vertical_pos);
CreateMarginsTextFields(base::ASCIIToUTF16("Interior margin"),
&interior_margin_, &vertical_pos);
@@ -51,10 +51,10 @@ void FlexLayoutExample::CreateAdditionalControls(int vertical_pos) {
CreateMarginsTextFields(base::ASCIIToUTF16("Default margins"),
&default_child_margins_, &vertical_pos);
- collapse_margins_ =
- CreateCheckbox(base::ASCIIToUTF16("Collapse margins"), &vertical_pos);
+ collapse_margins_ = CreateAndAddCheckbox(
+ base::ASCIIToUTF16("Collapse margins"), &vertical_pos);
- ignore_default_main_axis_margins_ = CreateCheckbox(
+ ignore_default_main_axis_margins_ = CreateAndAddCheckbox(
base::ASCIIToUTF16("Ignore main axis margins"), &vertical_pos);
layout_ = layout_panel()->SetLayoutManager(std::make_unique<FlexLayout>());
diff --git a/chromium/ui/views/examples/label_example.cc b/chromium/ui/views/examples/label_example.cc
index 8ec7651301f..61c25bb995e 100644
--- a/chromium/ui/views/examples/label_example.cc
+++ b/chromium/ui/views/examples/label_example.cc
@@ -167,9 +167,9 @@ void LabelExample::AddCustomLabel(View* container) {
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0.0f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(0, 0);
layout->AddView(std::make_unique<Label>(ASCIIToUTF16("Content: ")));
@@ -189,11 +189,11 @@ void LabelExample::AddCustomLabel(View* container) {
column_set = layout->AddColumnSet(1);
column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(0, 1);
multiline_ = layout->AddView(
std::make_unique<Checkbox>(base::ASCIIToUTF16("Multiline"), this));
@@ -205,7 +205,7 @@ void LabelExample::AddCustomLabel(View* container) {
column_set = layout->AddColumnSet(2);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(0, 2);
auto custom_label = std::make_unique<ExamplePreferredSizeLabel>();
custom_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
diff --git a/chromium/ui/views/examples/layout_example_base.cc b/chromium/ui/views/examples/layout_example_base.cc
index bb577f56a50..a2e85e23749 100644
--- a/chromium/ui/views/examples/layout_example_base.cc
+++ b/chromium/ui/views/examples/layout_example_base.cc
@@ -11,12 +11,14 @@
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/combobox/combobox.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/examples/example_combobox_model.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view_class_properties.h"
@@ -45,6 +47,20 @@ class FullPanel : public View {
DISALLOW_COPY_AND_ASSIGN(FullPanel);
};
+std::unique_ptr<Textfield> CreateCommonTextfield(
+ int vertical_pos,
+ int horizontal_pos,
+ TextfieldController* container) {
+ auto textfield = std::make_unique<Textfield>();
+ textfield->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
+ textfield->SetDefaultWidthInChars(3);
+ textfield->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
+ textfield->SizeToPreferredSize();
+ textfield->SetText(base::ASCIIToUTF16("0"));
+ textfield->set_controller(container);
+ return textfield;
+}
+
} // namespace
LayoutExampleBase::ChildPanel::ChildPanel(LayoutExampleBase* example)
@@ -125,146 +141,113 @@ void LayoutExampleBase::ChildPanel::ContentsChanged(
}
Textfield* LayoutExampleBase::ChildPanel::CreateTextfield() {
- Textfield* textfield = new Textfield();
+ auto textfield = std::make_unique<Textfield>();
textfield->SetDefaultWidthInChars(3);
textfield->SizeToPreferredSize();
textfield->SetText(base::ASCIIToUTF16("0"));
textfield->set_controller(this);
textfield->SetVisible(false);
- AddChildView(textfield);
- return textfield;
+ return AddChildView(std::move(textfield));
}
LayoutExampleBase::LayoutExampleBase(const char* title) : ExampleBase(title) {}
LayoutExampleBase::~LayoutExampleBase() = default;
-Combobox* LayoutExampleBase::CreateCombobox(const base::string16& label_text,
- const char* const* items,
- int count,
- int* vertical_pos) {
- Label* label = new Label(label_text);
+Combobox* LayoutExampleBase::CreateAndAddCombobox(
+ const base::string16& label_text,
+ const char* const* items,
+ int count,
+ int* vertical_pos) {
+ auto label = std::make_unique<Label>(label_text);
label->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
label->SizeToPreferredSize();
- Combobox* combo_box =
- new Combobox(std::make_unique<ExampleComboboxModel>(items, count));
+
+ auto combo_box = std::make_unique<Combobox>(
+ std::make_unique<ExampleComboboxModel>(items, count));
combo_box->SetPosition(
gfx::Point(label->x() + label->width() + kLayoutExampleVerticalSpacing,
*vertical_pos));
combo_box->SizeToPreferredSize();
combo_box->set_listener(this);
label->SetSize(gfx::Size(label->width(), combo_box->height()));
- control_panel_->AddChildView(label);
- control_panel_->AddChildView(combo_box);
- *vertical_pos += combo_box->height() + kLayoutExampleVerticalSpacing;
- return combo_box;
-}
+ control_panel_->AddChildView(std::move(label));
-Textfield* LayoutExampleBase::CreateRawTextfield(int vertical_pos,
- bool add,
- int* horizontal_pos) {
- Textfield* text_field = new Textfield();
- text_field->SetPosition(gfx::Point(*horizontal_pos, vertical_pos));
- text_field->SetDefaultWidthInChars(3);
- text_field->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
- text_field->SizeToPreferredSize();
- text_field->SetText(base::ASCIIToUTF16("0"));
- text_field->set_controller(this);
- *horizontal_pos += text_field->width() + kLayoutExampleVerticalSpacing;
- if (add)
- control_panel_->AddChildView(text_field);
- return text_field;
+ auto* combo_box_ptr = control_panel_->AddChildView(std::move(combo_box));
+ *vertical_pos += combo_box_ptr->height() + kLayoutExampleVerticalSpacing;
+ return combo_box_ptr;
}
-Textfield* LayoutExampleBase::CreateTextfield(const base::string16& label_text,
- int* vertical_pos) {
- Label* label = new Label(label_text);
+Textfield* LayoutExampleBase::CreateAndAddTextfield(
+ const base::string16& label_text,
+ int* vertical_pos) {
+ auto label = std::make_unique<Label>(label_text);
label->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
label->SizeToPreferredSize();
int horizontal_pos =
label->x() + label->width() + kLayoutExampleVerticalSpacing;
- Textfield* text_field =
- CreateRawTextfield(*vertical_pos, false, &horizontal_pos);
- label->SetSize(gfx::Size(label->width(), text_field->height()));
- control_panel_->AddChildView(label);
- control_panel_->AddChildView(text_field);
- *vertical_pos += text_field->height() + kLayoutExampleVerticalSpacing;
- return text_field;
-}
-
-void LayoutExampleBase::CreateMarginsTextFields(
- const base::string16& label_text,
- Textfield* textfields[4],
- int* vertical_pos) {
- textfields[0] = CreateTextfield(label_text, vertical_pos);
- int center = textfields[0]->x() + textfields[0]->width() / 2;
- int horizontal_pos = std::max(
- 0, center - (textfields[0]->width() + kLayoutExampleVerticalSpacing / 2));
- textfields[1] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
- textfields[3] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
- *vertical_pos = textfields[1]->y() + textfields[1]->height() +
- kLayoutExampleVerticalSpacing;
- horizontal_pos = textfields[0]->x();
- textfields[2] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
- *vertical_pos = textfields[2]->y() + textfields[2]->height() +
- kLayoutExampleVerticalSpacing;
+ std::unique_ptr<Textfield> textfield =
+ CreateCommonTextfield(*vertical_pos, horizontal_pos, this);
+ label->SetSize(gfx::Size(label->width(), textfield->height()));
+ control_panel_->AddChildView(std::move(label));
+ auto* textfield_ptr = control_panel_->AddChildView(std::move(textfield));
+ *vertical_pos += textfield_ptr->height() + kLayoutExampleVerticalSpacing;
+ return textfield_ptr;
}
void LayoutExampleBase::CreateMarginsTextFields(
const base::string16& label_text,
InsetTextfields* textfields,
int* vertical_pos) {
- textfields->top = CreateTextfield(label_text, vertical_pos);
+ textfields->top = CreateAndAddTextfield(label_text, vertical_pos);
int center = textfields->top->x() + textfields->top->width() / 2;
int horizontal_pos = std::max(
0,
center - (textfields->top->width() + kLayoutExampleVerticalSpacing / 2));
- textfields->left = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
- textfields->right = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
+ textfields->left = CreateAndAddRawTextfield(*vertical_pos, &horizontal_pos);
+ textfields->right = CreateAndAddRawTextfield(*vertical_pos, &horizontal_pos);
*vertical_pos = textfields->left->y() + textfields->left->height() +
kLayoutExampleVerticalSpacing;
horizontal_pos = textfields->top->x();
- textfields->bottom = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
+ textfields->bottom = CreateAndAddRawTextfield(*vertical_pos, &horizontal_pos);
*vertical_pos = textfields->bottom->y() + textfields->bottom->height() +
kLayoutExampleVerticalSpacing;
}
-Checkbox* LayoutExampleBase::CreateCheckbox(const base::string16& label_text,
- int* vertical_pos) {
- Checkbox* checkbox = new Checkbox(label_text, this);
+Checkbox* LayoutExampleBase::CreateAndAddCheckbox(
+ const base::string16& label_text,
+ int* vertical_pos) {
+ auto checkbox = std::make_unique<Checkbox>(label_text, this);
checkbox->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
checkbox->SizeToPreferredSize();
- control_panel_->AddChildView(checkbox);
- *vertical_pos += checkbox->height() + kLayoutExampleVerticalSpacing;
- return checkbox;
+ auto* checkbox_ptr = control_panel_->AddChildView(std::move(checkbox));
+ *vertical_pos += checkbox_ptr->height() + kLayoutExampleVerticalSpacing;
+ return checkbox_ptr;
}
void LayoutExampleBase::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<FillLayout>());
- View* full_panel = new FullPanel();
- container->AddChildView(full_panel);
+ View* full_panel = container->AddChildView(std::make_unique<FullPanel>());
auto* manager = full_panel->SetLayoutManager(
std::make_unique<BoxLayout>(views::BoxLayout::Orientation::kHorizontal));
- layout_panel_ = new View();
+ layout_panel_ = full_panel->AddChildView(std::make_unique<View>());
layout_panel_->SetBorder(CreateSolidBorder(1, SK_ColorLTGRAY));
- full_panel->AddChildView(layout_panel_);
manager->SetFlexForView(layout_panel_, 3);
- control_panel_ = new View();
- full_panel->AddChildView(control_panel_);
+ control_panel_ = full_panel->AddChildView(std::make_unique<View>());
manager->SetFlexForView(control_panel_, 1);
int vertical_pos = kLayoutExampleVerticalSpacing;
int horizontal_pos = kLayoutExampleLeftPadding;
- auto add_button =
- MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Add"));
+ auto add_button = MdTextButton::Create(
+ this, l10n_util::GetStringUTF16(IDS_LAYOUT_BASE_ADD_LABEL));
add_button->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
add_button->SizeToPreferredSize();
add_button_ = control_panel_->AddChildView(std::move(add_button));
horizontal_pos += add_button_->width() + kLayoutExampleVerticalSpacing;
preferred_width_view_ =
- CreateRawTextfield(vertical_pos, true, &horizontal_pos);
+ CreateAndAddRawTextfield(vertical_pos, &horizontal_pos);
preferred_width_view_->SetY(
vertical_pos +
(add_button_->height() - preferred_width_view_->height()) / 2);
@@ -272,7 +255,7 @@ void LayoutExampleBase::CreateExampleView(View* container) {
base::NumberToString16(kLayoutExampleDefaultChildSize.width()));
preferred_height_view_ =
- CreateRawTextfield(vertical_pos, true, &horizontal_pos);
+ CreateAndAddRawTextfield(vertical_pos, &horizontal_pos);
preferred_height_view_->SetY(
vertical_pos +
(add_button_->height() - preferred_height_view_->height()) / 2);
@@ -339,5 +322,13 @@ gfx::Insets LayoutExampleBase::TextfieldsToInsets(
std::max(0, right));
}
+Textfield* LayoutExampleBase::CreateAndAddRawTextfield(int vertical_pos,
+ int* horizontal_pos) {
+ std::unique_ptr<Textfield> textfield =
+ CreateCommonTextfield(vertical_pos, *horizontal_pos, this);
+ *horizontal_pos += textfield->width() + kLayoutExampleVerticalSpacing;
+ return control_panel_->AddChildView(std::move(textfield));
+}
+
} // namespace examples
} // namespace views
diff --git a/chromium/ui/views/examples/layout_example_base.h b/chromium/ui/views/examples/layout_example_base.h
index a6d1db36c49..7e41f985931 100644
--- a/chromium/ui/views/examples/layout_example_base.h
+++ b/chromium/ui/views/examples/layout_example_base.h
@@ -81,32 +81,17 @@ class VIEWS_EXAMPLES_EXPORT LayoutExampleBase : public ExampleBase,
protected:
View* layout_panel() { return layout_panel_; }
- // Creates a Combobox with a label with |label_text| to the left. Adjust
- // |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
- Combobox* CreateCombobox(const base::string16& label_text,
- const char* const* items,
- int count,
- int* vertical_pos);
-
- // Creates just a Textfield at the current position of |horizontal_pos| and
- // |vertical_pos|. Update |horizontal_pos| to |horizontal_pos| +
- // text_field->width() + kSpacing.
- Textfield* CreateRawTextfield(int vertical_pos,
- bool add,
- int* horizontal_pos);
-
- // Creates a Textfield with a label with |label_text| to the left. Adjust
- // |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
- Textfield* CreateTextfield(const base::string16& label_text,
- int* vertical_pos);
-
- // Creates a set of labeled Textfields with |label_text|, and four text fields
- // arranged at compass points representing a set of insets. |vertical_pos| is
- // updated to the bottom of the last Textfield + kSpacing, and |textfields| is
- // populated with the fieds that are created.
- void CreateMarginsTextFields(const base::string16& label_text,
- Textfield* textfields[4],
- int* vertical_pos);
+ // Creates and adds a Combobox with a label with |label_text| to the left.
+ // Adjust |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
+ Combobox* CreateAndAddCombobox(const base::string16& label_text,
+ const char* const* items,
+ int count,
+ int* vertical_pos);
+
+ // Creates and adds a Textfield with a label with |label_text| to the left.
+ // Adjusts |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
+ Textfield* CreateAndAddTextfield(const base::string16& label_text,
+ int* vertical_pos);
// Creates a set of labeled Textfields with |label_text|, and four text fields
// arranged at compass points representing a set of insets. |vertical_pos| is
@@ -116,9 +101,10 @@ class VIEWS_EXAMPLES_EXPORT LayoutExampleBase : public ExampleBase,
InsetTextfields* textfields,
int* vertical_pos);
- // Creates a Checkbox with label |label_text|. Adjust |vertical_pos| to
- // |vertical_pos| + checkbox->height() + kSpacing.
- Checkbox* CreateCheckbox(const base::string16& label_text, int* vertical_pos);
+ // Creates and adds a Checkbox with label |label_text|. Adjust |vertical_pos|
+ // to |vertical_pos| + checkbox->height() + kSpacing.
+ Checkbox* CreateAndAddCheckbox(const base::string16& label_text,
+ int* vertical_pos);
// ButtonListener:
// Be sure to call LayoutExampleBase::ButtonPressed() to ensure the "add"
@@ -145,6 +131,11 @@ class VIEWS_EXAMPLES_EXPORT LayoutExampleBase : public ExampleBase,
virtual void UpdateLayoutManager() = 0;
private:
+ // Creates and adds a Textfield at the current position of |horizontal_pos|
+ // and |vertical_pos|. Update |horizontal_pos| to |horizontal_pos| +
+ // text_field->width() + kSpacing.
+ Textfield* CreateAndAddRawTextfield(int vertical_pos, int* horizontal_pos);
+
View* layout_panel_ = nullptr;
View* control_panel_ = nullptr;
LabelButton* add_button_ = nullptr;
diff --git a/chromium/ui/views/examples/link_example.cc b/chromium/ui/views/examples/link_example.cc
index aa61e567010..553c40d0d7e 100644
--- a/chromium/ui/views/examples/link_example.cc
+++ b/chromium/ui/views/examples/link_example.cc
@@ -8,21 +8,29 @@
#include <utility>
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/link.h"
#include "ui/views/examples/examples_window.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
+
namespace views {
namespace examples {
-LinkExample::LinkExample() : ExampleBase("Link") {}
+LinkExample::LinkExample()
+ : ExampleBase(GetStringUTF8(IDS_LINK_SELECT_LABEL).c_str()) {}
LinkExample::~LinkExample() = default;
void LinkExample::CreateExampleView(View* container) {
- auto link = std::make_unique<Link>(base::ASCIIToUTF16("Click me!"));
- link->set_callback(base::BindRepeating(&LogStatus, "Link clicked"));
+ auto link =
+ std::make_unique<Link>(GetStringUTF16(IDS_LINK_CLICK_PROMPT_LABEL));
+ link->set_callback(base::BindRepeating(
+ &LogStatus, GetStringUTF8(IDS_LINK_CLICK_CONFIRMED_LABEL)));
container->SetLayoutManager(std::make_unique<FillLayout>());
container->AddChildView(std::move(link));
diff --git a/chromium/ui/views/examples/login_bubble_dialog.cc b/chromium/ui/views/examples/login_bubble_dialog.cc
new file mode 100644
index 00000000000..a83e00b9d78
--- /dev/null
+++ b/chromium/ui/views/examples/login_bubble_dialog.cc
@@ -0,0 +1,164 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/examples/login_bubble_dialog.h"
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_provider.h"
+
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
+
+namespace views {
+namespace examples {
+
+namespace {
+
+// Adds a label textfield pair to the login dialog's layout.
+Textfield* AddFormRow(LoginBubbleDialogView* bubble,
+ GridLayout* layout,
+ const base::string16& label_text) {
+ layout->StartRow(0, 0);
+ Label* label = layout->AddView(std::make_unique<Label>(label_text));
+ Textfield* textfield = layout->AddView(std::make_unique<Textfield>());
+ textfield->SetAssociatedLabel(label);
+ textfield->set_controller(bubble);
+ constexpr int kDefaultTextfieldWidth = 30;
+ constexpr int kMinimumTextfieldWidth = 5;
+ textfield->SetDefaultWidthInChars(kDefaultTextfieldWidth);
+ textfield->SetMinimumWidthInChars(kMinimumTextfieldWidth);
+ return textfield;
+}
+
+} // namespace
+
+// static
+void LoginBubbleDialogView::Show(View* anchor_view,
+ BubbleBorder::Arrow anchor_position,
+ OnSubmitCallback accept_callback) {
+ BubbleDialogDelegateView::CreateBubble(
+ new LoginBubbleDialogView(anchor_view, anchor_position,
+ std::move(accept_callback)))
+ ->Show();
+}
+
+LoginBubbleDialogView::~LoginBubbleDialogView() = default;
+
+void LoginBubbleDialogView::ContentsChanged(
+ Textfield* sender,
+ const base::string16& new_contents) {
+ SetButtonEnabled(ui::DIALOG_BUTTON_OK, !username_->GetText().empty() &&
+ !password_->GetText().empty());
+ DialogModelChanged();
+}
+
+LoginBubbleDialogView::LoginBubbleDialogView(
+ View* anchor_view,
+ BubbleBorder::Arrow anchor_position,
+ OnSubmitCallback accept_callback)
+ : BubbleDialogDelegateView(anchor_view, anchor_position) {
+ SetButtonEnabled(ui::DIALOG_BUTTON_OK, false);
+
+ const auto on_submit = [](const LoginBubbleDialogView* bubble_view,
+ OnSubmitCallback accept_callback) {
+ std::move(accept_callback)
+ .Run(bubble_view->username_->GetText(),
+ bubble_view->password_->GetText());
+ };
+ SetAcceptCallback(base::BindOnce(on_submit, base::Unretained(this),
+ std::move(accept_callback)));
+
+ SetTitle(l10n_util::GetStringUTF16(IDS_LOGIN_TITLE_LABEL));
+ SetButtonLabel(ui::DIALOG_BUTTON_OK,
+ l10n_util::GetStringUTF16(IDS_LOGIN_OK_BUTTON_LABEL));
+
+ const LayoutProvider* provider = LayoutProvider::Get();
+ set_margins(
+ provider->GetDialogInsetsForContentType(views::CONTROL, views::CONTROL));
+ const int related_control_padding =
+ provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL);
+ const int label_padding =
+ provider->GetDistanceMetric(views::DISTANCE_RELATED_LABEL_HORIZONTAL);
+
+ GridLayout* layout = SetLayoutManager(std::make_unique<GridLayout>());
+ ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL,
+ GridLayout::kFixedSize,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ column_set->AddPaddingColumn(0, label_padding);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+
+ username_ = AddFormRow(this, layout,
+ l10n_util::GetStringUTF16(IDS_LOGIN_USERNAME_LABEL));
+
+ layout->AddPaddingRow(0, related_control_padding);
+
+ password_ = AddFormRow(this, layout,
+ l10n_util::GetStringUTF16(IDS_LOGIN_PASSWORD_LABEL));
+ password_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+}
+
+LoginBubbleDialogExample::LoginBubbleDialogExample()
+ : ExampleBase(GetStringUTF8(IDS_LOGIN_SELECT_LABEL).c_str()) {}
+
+LoginBubbleDialogExample::~LoginBubbleDialogExample() = default;
+
+void LoginBubbleDialogExample::CreateExampleView(View* container) {
+ const int related_control_padding = LayoutProvider::Get()->GetDistanceMetric(
+ views::DISTANCE_RELATED_CONTROL_VERTICAL);
+ const int label_padding = LayoutProvider::Get()->GetDistanceMetric(
+ views::DISTANCE_RELATED_LABEL_HORIZONTAL);
+
+ GridLayout* layout =
+ container->SetLayoutManager(std::make_unique<GridLayout>());
+ ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL,
+ GridLayout::kFixedSize,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ column_set->AddPaddingColumn(0, label_padding);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+
+ layout->StartRowWithPadding(0, 0, 0, related_control_padding);
+ button_ = layout->AddView(
+ MdTextButton::Create(this, GetStringUTF16(IDS_LOGIN_SHOW_BUTTON_LABEL)));
+
+ layout->StartRowWithPadding(0, 0, 0, related_control_padding);
+ layout->AddView(std::make_unique<Label>(
+ l10n_util::GetStringUTF16(IDS_LOGIN_USERNAME_LABEL)));
+ username_label_ = layout->AddView(std::make_unique<Label>());
+
+ layout->StartRowWithPadding(0, 0, 0, related_control_padding);
+ layout->AddView(std::make_unique<Label>(
+ l10n_util::GetStringUTF16(IDS_LOGIN_PASSWORD_LABEL)));
+ password_label_ = layout->AddView(std::make_unique<Label>());
+}
+
+void LoginBubbleDialogExample::ButtonPressed(Button* sender,
+ const ui::Event& event) {
+ LoginBubbleDialogView::Show(
+ button_, BubbleBorder::TOP_LEFT,
+ base::BindOnce(&LoginBubbleDialogExample::OnSubmit,
+ base::Unretained(this)));
+}
+
+void LoginBubbleDialogExample::OnSubmit(base::string16 username,
+ base::string16 password) {
+ username_label_->SetText(username);
+ password_label_->SetText(password);
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/login_bubble_dialog.h b/chromium/ui/views/examples/login_bubble_dialog.h
new file mode 100644
index 00000000000..d62ad3ef64b
--- /dev/null
+++ b/chromium/ui/views/examples/login_bubble_dialog.h
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_EXAMPLES_LOGIN_BUBBLE_DIALOG_H_
+#define UI_VIEWS_EXAMPLES_LOGIN_BUBBLE_DIALOG_H_
+
+#include "base/strings/string16.h"
+#include "ui/views/bubble/bubble_border.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/examples/example_base.h"
+
+namespace views {
+
+class LabelButton;
+
+namespace examples {
+
+class LoginBubbleDialogView : public BubbleDialogDelegateView,
+ public TextfieldController {
+ public:
+ using OnSubmitCallback = base::OnceCallback<void(base::string16 username,
+ base::string16 password)>;
+
+ static void Show(View* anchor_view,
+ BubbleBorder::Arrow anchor_position,
+ OnSubmitCallback accept_callback);
+
+ ~LoginBubbleDialogView() override;
+
+ // TextfieldController:
+ void ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) override;
+
+ private:
+ LoginBubbleDialogView(View* anchor_view,
+ BubbleBorder::Arrow anchor_position,
+ OnSubmitCallback accept_callback);
+
+ Textfield* username_ = nullptr;
+ Textfield* password_ = nullptr;
+};
+
+// Instantiates the login dialog example.
+class LoginBubbleDialogExample : public ExampleBase, public ButtonListener {
+ public:
+ LoginBubbleDialogExample();
+ ~LoginBubbleDialogExample() override;
+
+ // ExampleBase:
+ void CreateExampleView(View* container) override;
+
+ // ButtonListener:
+ void ButtonPressed(Button* sender, const ui::Event& event) override;
+
+ // LoginBubbleDialogController:
+ void OnSubmit(base::string16 username, base::string16 password);
+
+ private:
+ LabelButton* button_ = nullptr;
+ Label* username_label_ = nullptr;
+ Label* password_label_ = nullptr;
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_LOGIN_BUBBLE_DIALOG_H_
diff --git a/chromium/ui/views/examples/menu_example.cc b/chromium/ui/views/examples/menu_example.cc
index 01a37140511..76d851f1a6b 100644
--- a/chromium/ui/views/examples/menu_example.cc
+++ b/chromium/ui/views/examples/menu_example.cc
@@ -9,15 +9,18 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
-using base::ASCIIToUTF16;
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
namespace views {
namespace examples {
@@ -77,23 +80,25 @@ class ExampleMenuButton : public MenuButton, public ButtonListener {
// ExampleMenuModel ---------------------------------------------------------
ExampleMenuModel::ExampleMenuModel() : ui::SimpleMenuModel(this) {
- AddItem(COMMAND_DO_SOMETHING, ASCIIToUTF16("Do Something"));
+ AddItem(COMMAND_DO_SOMETHING, GetStringUTF16(IDS_MENU_DO_SOMETHING_LABEL));
AddSeparator(ui::NORMAL_SEPARATOR);
- AddRadioItem(COMMAND_SELECT_ASCII, ASCIIToUTF16("ASCII"),
+ AddRadioItem(COMMAND_SELECT_ASCII, GetStringUTF16(IDS_MENU_ASCII_LABEL),
GROUP_MAKE_DECISION);
- AddRadioItem(COMMAND_SELECT_UTF8, ASCIIToUTF16("UTF-8"), GROUP_MAKE_DECISION);
- AddRadioItem(COMMAND_SELECT_UTF16, ASCIIToUTF16("UTF-16"),
+ AddRadioItem(COMMAND_SELECT_UTF8, GetStringUTF16(IDS_MENU_UTF8_LABEL),
+ GROUP_MAKE_DECISION);
+ AddRadioItem(COMMAND_SELECT_UTF16, GetStringUTF16(IDS_MENU_UTF16_LABEL),
GROUP_MAKE_DECISION);
AddSeparator(ui::NORMAL_SEPARATOR);
- AddCheckItem(COMMAND_CHECK_APPLE, ASCIIToUTF16("Apple"));
- AddCheckItem(COMMAND_CHECK_ORANGE, ASCIIToUTF16("Orange"));
- AddCheckItem(COMMAND_CHECK_KIWI, ASCIIToUTF16("Kiwi"));
+ AddCheckItem(COMMAND_CHECK_APPLE, GetStringUTF16(IDS_MENU_APPLE_LABEL));
+ AddCheckItem(COMMAND_CHECK_ORANGE, GetStringUTF16(IDS_MENU_ORANGE_LABEL));
+ AddCheckItem(COMMAND_CHECK_KIWI, GetStringUTF16(IDS_MENU_KIWI_LABEL));
AddSeparator(ui::NORMAL_SEPARATOR);
- AddItem(COMMAND_GO_HOME, ASCIIToUTF16("Go Home"));
+ AddItem(COMMAND_GO_HOME, GetStringUTF16(IDS_MENU_GO_HOME_LABEL));
submenu_ = std::make_unique<ui::SimpleMenuModel>(this);
- submenu_->AddItem(COMMAND_DO_SOMETHING, ASCIIToUTF16("Do Something 2"));
- AddSubMenu(0, ASCIIToUTF16("Submenu"), submenu_.get());
+ submenu_->AddItem(COMMAND_DO_SOMETHING,
+ GetStringUTF16(IDS_MENU_DO_SOMETHING_2_LABEL));
+ AddSubMenu(0, GetStringUTF16(IDS_MENU_SUBMENU_LABEL), submenu_.get());
}
bool ExampleMenuModel::IsCommandIdChecked(int command_id) const {
@@ -189,16 +194,16 @@ ui::SimpleMenuModel* ExampleMenuButton::GetMenuModel() {
} // namespace
-MenuExample::MenuExample() : ExampleBase("Menu") {}
+MenuExample::MenuExample()
+ : ExampleBase(GetStringUTF8(IDS_MENU_SELECT_LABEL).c_str()) {}
MenuExample::~MenuExample() = default;
void MenuExample::CreateExampleView(View* container) {
// We add a button to open a menu.
- ExampleMenuButton* menu_button =
- new ExampleMenuButton(ASCIIToUTF16("Open a menu"));
container->SetLayoutManager(std::make_unique<FillLayout>());
- container->AddChildView(menu_button);
+ container->AddChildView(std::make_unique<ExampleMenuButton>(
+ GetStringUTF16(IDS_MENU_BUTTON_LABEL)));
}
} // namespace examples
diff --git a/chromium/ui/views/examples/message_box_example.cc b/chromium/ui/views/examples/message_box_example.cc
index 496dfc95a29..13aa6925d66 100644
--- a/chromium/ui/views/examples/message_box_example.cc
+++ b/chromium/ui/views/examples/message_box_example.cc
@@ -8,18 +8,22 @@
#include <utility>
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/message_box_view.h"
#include "ui/views/examples/examples_window.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
-using base::ASCIIToUTF16;
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
namespace views {
namespace examples {
-MessageBoxExample::MessageBoxExample() : ExampleBase("Message Box View") {}
+MessageBoxExample::MessageBoxExample()
+ : ExampleBase(GetStringUTF8(IDS_MESSAGE_SELECT_LABEL).c_str()) {}
MessageBoxExample::~MessageBoxExample() = default;
@@ -28,38 +32,42 @@ void MessageBoxExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<views::GridLayout>());
auto message_box_view = std::make_unique<MessageBoxView>(
- MessageBoxView::InitParams(ASCIIToUTF16("Hello, world!")));
- message_box_view->SetCheckBoxLabel(ASCIIToUTF16("Check Box"));
+ MessageBoxView::InitParams(GetStringUTF16(IDS_MESSAGE_INTRO_LABEL)));
+ message_box_view->SetCheckBoxLabel(
+ GetStringUTF16(IDS_MESSAGE_CHECK_BOX_LABEL));
const int message_box_column = 0;
ColumnSet* column_set = layout->AddColumnSet(message_box_column);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(1 /* expand */, message_box_column);
message_box_view_ = layout->AddView(std::move(message_box_view));
const int button_column = 1;
column_set = layout->AddColumnSet(button_column);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.5f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.5f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(0 /* no expand */, button_column);
- status_ = layout->AddView(
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Show Status")));
- toggle_ = layout->AddView(
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Toggle Checkbox")));
+ status_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_MESSAGE_STATUS_LABEL)));
+ toggle_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_MESSAGE_TOGGLE_LABEL)));
}
void MessageBoxExample::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == status_) {
message_box_view_->SetCheckBoxLabel(
- ASCIIToUTF16(message_box_view_->IsCheckBoxSelected() ? "on" : "off"));
- LogStatus(message_box_view_->IsCheckBoxSelected()
- ? "Check Box Selected"
- : "Check Box Not Selected");
+ message_box_view_->IsCheckBoxSelected()
+ ? GetStringUTF16(IDS_MESSAGE_ON_LABEL)
+ : GetStringUTF16(IDS_MESSAGE_OFF_LABEL));
+ LogStatus(
+ message_box_view_->IsCheckBoxSelected()
+ ? GetStringUTF8(IDS_MESSAGE_CHECK_SELECTED_LABEL).c_str()
+ : GetStringUTF8(IDS_MESSAGE_CHECK_NOT_SELECTED_LABEL).c_str());
} else if (sender == toggle_) {
message_box_view_->SetCheckBoxSelected(
!message_box_view_->IsCheckBoxSelected());
diff --git a/chromium/ui/views/examples/multiline_example.cc b/chromium/ui/views/examples/multiline_example.cc
index c8b056c9cdc..dea9016b42e 100644
--- a/chromium/ui/views/examples/multiline_example.cc
+++ b/chromium/ui/views/examples/multiline_example.cc
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/events/event.h"
#include "ui/gfx/render_text.h"
#include "ui/views/background.h"
@@ -19,10 +20,12 @@
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
-using base::ASCIIToUTF16;
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
namespace views {
namespace examples {
@@ -123,7 +126,8 @@ class MultilineExample::RenderTextView : public View {
DISALLOW_COPY_AND_ASSIGN(RenderTextView);
};
-MultilineExample::MultilineExample() : ExampleBase("Multiline RenderText") {}
+MultilineExample::MultilineExample()
+ : ExampleBase(GetStringUTF8(IDS_MULTILINE_SELECT_LABEL).c_str()) {}
MultilineExample::~MultilineExample() = default;
@@ -142,12 +146,12 @@ void MultilineExample::CreateExampleView(View* container) {
label->SetBorder(CreateSolidBorder(2, SK_ColorCYAN));
auto label_checkbox =
- std::make_unique<Checkbox>(ASCIIToUTF16("views::Label:"), this);
+ std::make_unique<Checkbox>(GetStringUTF16(IDS_MULTILINE_LABEL), this);
label_checkbox->SetChecked(true);
label_checkbox->set_request_focus_on_press(false);
- auto elision_checkbox =
- std::make_unique<Checkbox>(ASCIIToUTF16("elide text?"), this);
+ auto elision_checkbox = std::make_unique<Checkbox>(
+ GetStringUTF16(IDS_MULTILINE_ELIDE_LABEL), this);
elision_checkbox->SetChecked(false);
elision_checkbox->set_request_focus_on_press(false);
@@ -160,12 +164,13 @@ void MultilineExample::CreateExampleView(View* container) {
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0.0f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0f,
- GridLayout::FIXED, 0, 0);
+ GridLayout::ColumnSize::kFixed, 0, 0);
layout->StartRow(0, 0);
- layout->AddView(std::make_unique<Label>(ASCIIToUTF16("gfx::RenderText:")));
+ layout->AddView(
+ std::make_unique<Label>(GetStringUTF16(IDS_MULTILINE_RENDER_TEXT_LABEL)));
render_text_view_ = layout->AddView(std::move(render_text_view));
layout->StartRow(0, 0);
@@ -176,7 +181,8 @@ void MultilineExample::CreateExampleView(View* container) {
elision_checkbox_ = layout->AddView(std::move(elision_checkbox));
layout->StartRow(0, 0);
- layout->AddView(std::make_unique<Label>(ASCIIToUTF16("Sample Text:")));
+ layout->AddView(
+ std::make_unique<Label>(GetStringUTF16(IDS_MULTILINE_SAMPLE_TEXT_LABEL)));
textfield_ = layout->AddView(std::move(textfield));
}
diff --git a/chromium/ui/views/examples/native_theme_example.cc b/chromium/ui/views/examples/native_theme_example.cc
index f2fd54edc0c..04f32e5eb02 100644
--- a/chromium/ui/views/examples/native_theme_example.cc
+++ b/chromium/ui/views/examples/native_theme_example.cc
@@ -14,10 +14,12 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/scroll_view.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/grid_layout.h"
@@ -69,9 +71,9 @@ std::unique_ptr<View> CreateAllColorsView() {
auto* layout = container->SetLayoutManager(std::make_unique<GridLayout>());
auto* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_WindowBackground));
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_DialogBackground));
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_DialogForeground));
@@ -80,7 +82,6 @@ std::unique_ptr<View> CreateAllColorsView() {
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_UnfocusedBorderColor));
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_ButtonEnabledColor));
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_ButtonDisabledColor));
- InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_ButtonPressedShade));
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_ButtonUncheckedColor));
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_ProminentButtonColor));
InsertColorRow(layout,
@@ -101,6 +102,7 @@ std::unique_ptr<View> CreateAllColorsView() {
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_MenuSeparatorColor));
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_MenuBackgroundColor));
InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_MenuBorderColor));
+ InsertColorRow(layout, COLOR_LABEL_ARGS(kColorId_MenuIconColor));
InsertColorRow(layout,
COLOR_LABEL_ARGS(kColorId_HighlightedMenuItemBackgroundColor));
InsertColorRow(layout,
@@ -168,7 +170,8 @@ std::unique_ptr<View> CreateAllColorsView() {
} // namespace
-NativeThemeExample::NativeThemeExample() : ExampleBase("Native Theme Colors") {}
+NativeThemeExample::NativeThemeExample()
+ : ExampleBase(l10n_util::GetStringUTF8(IDS_THEME_SELECT_LABEL).c_str()) {}
NativeThemeExample::~NativeThemeExample() = default;
diff --git a/chromium/ui/views/examples/progress_bar_example.cc b/chromium/ui/views/examples/progress_bar_example.cc
index d59bc19b851..4879f5fe217 100644
--- a/chromium/ui/views/examples/progress_bar_example.cc
+++ b/chromium/ui/views/examples/progress_bar_example.cc
@@ -10,15 +10,21 @@
#include "base/numerics/ranges.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/progress_bar.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
+
namespace views {
namespace examples {
-ProgressBarExample::ProgressBarExample() : ExampleBase("Progress Bar") {}
+ProgressBarExample::ProgressBarExample()
+ : ExampleBase(GetStringUTF8(IDS_PROGRESS_SELECT_LABEL).c_str()) {}
ProgressBarExample::~ProgressBarExample() = default;
@@ -28,13 +34,13 @@ void ProgressBarExample::CreateExampleView(View* container) {
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(0, 8);
column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
- GridLayout::FIXED, 200, 0);
+ GridLayout::ColumnSize::kFixed, 200, 0);
column_set->AddPaddingColumn(0, 8);
column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(0, 0);
minus_button_ =
@@ -45,14 +51,14 @@ void ProgressBarExample::CreateExampleView(View* container) {
layout->StartRowWithPadding(0, 0, 0, 10);
layout->AddView(
- std::make_unique<Label>(base::ASCIIToUTF16("Infinite loader:")));
+ std::make_unique<Label>(GetStringUTF16(IDS_PROGRESS_LOADER_LABEL)));
auto infinite_bar = std::make_unique<ProgressBar>();
infinite_bar->SetValue(-1);
layout->AddView(std::move(infinite_bar));
layout->StartRowWithPadding(0, 0, 0, 10);
- layout->AddView(std::make_unique<Label>(
- base::ASCIIToUTF16("Infinite loader (very short):")));
+ layout->AddView(
+ std::make_unique<Label>(GetStringUTF16(IDS_PROGRESS_LOADER_SHORT_LABEL)));
auto shorter_bar = std::make_unique<ProgressBar>(2);
shorter_bar->SetValue(-1);
layout->AddView(std::move(shorter_bar));
diff --git a/chromium/ui/views/examples/radio_button_example.cc b/chromium/ui/views/examples/radio_button_example.cc
index b9644096d1f..598c8b18a20 100644
--- a/chromium/ui/views/examples/radio_button_example.cc
+++ b/chromium/ui/views/examples/radio_button_example.cc
@@ -11,12 +11,17 @@
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/radio_button.h"
#include "ui/views/examples/examples_window.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
+
namespace views {
namespace examples {
@@ -28,7 +33,8 @@ const char* BoolToOnOff(bool value) {
} // namespace
-RadioButtonExample::RadioButtonExample() : ExampleBase("Radio Button") {}
+RadioButtonExample::RadioButtonExample()
+ : ExampleBase(GetStringUTF8(IDS_RADIO_BUTTON_SELECT_LABEL).c_str()) {}
RadioButtonExample::~RadioButtonExample() = default;
@@ -37,7 +43,7 @@ void RadioButtonExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<views::GridLayout>());
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
const int group = 1;
for (size_t i = 0; i < 3; ++i) {
layout->StartRow(0, 0);
@@ -48,11 +54,11 @@ void RadioButtonExample::CreateExampleView(View* container) {
}
layout->StartRow(0, 0);
- select_ = layout->AddView(
- std::make_unique<LabelButton>(this, base::ASCIIToUTF16("Select")));
+ select_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_RADIO_BUTTON_SELECT_BUTTON_LABEL)));
layout->StartRow(0, 0);
- status_ = layout->AddView(
- std::make_unique<LabelButton>(this, base::ASCIIToUTF16("Show Status")));
+ status_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_RADIO_BUTTON_STATUS_LABEL)));
}
void RadioButtonExample::ButtonPressed(Button* sender, const ui::Event& event) {
diff --git a/chromium/ui/views/examples/scroll_view_example.cc b/chromium/ui/views/examples/scroll_view_example.cc
index 48082b47df1..90a68d46c93 100644
--- a/chromium/ui/views/examples/scroll_view_example.cc
+++ b/chromium/ui/views/examples/scroll_view_example.cc
@@ -11,17 +11,20 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "cc/paint/paint_flags.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/skia_paint_util.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/radio_button.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
-using base::ASCIIToUTF16;
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
namespace views {
namespace examples {
@@ -42,8 +45,10 @@ class ScrollViewExample::ScrollableView : public View {
views::BoxLayout::Orientation::kVertical));
container->AddChildView(std::move(view));
};
- add_child(std::make_unique<LabelButton>(nullptr, ASCIIToUTF16("Button")));
- add_child(std::make_unique<RadioButton>(ASCIIToUTF16("Radio Button"), 0));
+ add_child(std::make_unique<LabelButton>(
+ nullptr, GetStringUTF16(IDS_SCROLL_VIEW_BUTTON_LABEL)));
+ add_child(std::make_unique<RadioButton>(
+ GetStringUTF16(IDS_SCROLL_VIEW_RADIO_BUTTON_LABEL), 0));
layout_manager->SetDefaultFlex(1);
}
@@ -67,7 +72,8 @@ class ScrollViewExample::ScrollableView : public View {
DISALLOW_COPY_AND_ASSIGN(ScrollableView);
};
-ScrollViewExample::ScrollViewExample() : ExampleBase("Scroll View") {}
+ScrollViewExample::ScrollViewExample()
+ : ExampleBase(GetStringUTF8(IDS_SCROLL_VIEW_SELECT_LABEL).c_str()) {}
ScrollViewExample::~ScrollViewExample() = default;
@@ -83,7 +89,7 @@ void ScrollViewExample::CreateExampleView(View* container) {
// Add scroll view.
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(1, 0);
scroll_view_ = layout->AddView(std::move(scroll_view));
@@ -91,19 +97,19 @@ void ScrollViewExample::CreateExampleView(View* container) {
column_set = layout->AddColumnSet(1);
for (size_t i = 0; i < 5; i++) {
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
}
layout->StartRow(0, 1);
- wide_ = layout->AddView(
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Wide")));
- tall_ = layout->AddView(
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Tall")));
- big_square_ = layout->AddView(
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Big Square")));
- small_square_ = layout->AddView(
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Small Square")));
- scroll_to_ = layout->AddView(
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Scroll to")));
+ wide_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_SCROLL_VIEW_WIDE_LABEL)));
+ tall_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_SCROLL_VIEW_TALL_LABEL)));
+ big_square_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_SCROLL_VIEW_BIG_SQUARE_LABEL)));
+ small_square_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_SCROLL_VIEW_SMALL_SQUARE_LABEL)));
+ scroll_to_ = layout->AddView(std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_SCROLL_VIEW_SCROLL_TO_LABEL)));
}
void ScrollViewExample::ButtonPressed(Button* sender, const ui::Event& event) {
diff --git a/chromium/ui/views/examples/slider_example.cc b/chromium/ui/views/examples/slider_example.cc
index 2f151f3f5b5..4b23bee018f 100644
--- a/chromium/ui/views/examples/slider_example.cc
+++ b/chromium/ui/views/examples/slider_example.cc
@@ -8,29 +8,30 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/slider.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
namespace views {
namespace examples {
-SliderExample::SliderExample() : ExampleBase("Slider") {}
+SliderExample::SliderExample()
+ : ExampleBase(l10n_util::GetStringUTF8(IDS_SLIDER_SELECT_LABEL).c_str()) {}
SliderExample::~SliderExample() = default;
void SliderExample::CreateExampleView(View* container) {
- label_ = new Label();
- slider_ = new views::Slider(this);
+ label_ = container->AddChildView(std::make_unique<Label>());
+ slider_ = container->AddChildView(std::make_unique<Slider>(this));
slider_->SetValue(0.5);
container->SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kHorizontal, gfx::Insets(3), 3));
- container->AddChildView(slider_);
- container->AddChildView(label_);
}
void SliderExample::SliderValueChanged(Slider* sender,
diff --git a/chromium/ui/views/examples/tabbed_pane_example.cc b/chromium/ui/views/examples/tabbed_pane_example.cc
index 15fedb4ba88..b561f983ffc 100644
--- a/chromium/ui/views/examples/tabbed_pane_example.cc
+++ b/chromium/ui/views/examples/tabbed_pane_example.cc
@@ -8,27 +8,33 @@
#include <utility>
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/examples/examples_window.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/grid_layout.h"
-using base::ASCIIToUTF16;
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
namespace views {
namespace examples {
-TabbedPaneExample::TabbedPaneExample() : ExampleBase("Tabbed Pane") {}
+TabbedPaneExample::TabbedPaneExample()
+ : ExampleBase(GetStringUTF8(IDS_TABBED_PANE_SELECT_LABEL).c_str()) {}
TabbedPaneExample::~TabbedPaneExample() = default;
void TabbedPaneExample::CreateExampleView(View* container) {
auto tabbed_pane = std::make_unique<TabbedPane>();
tabbed_pane->set_listener(this);
- auto add = std::make_unique<LabelButton>(this, ASCIIToUTF16("Add"));
- auto add_at = std::make_unique<LabelButton>(this, ASCIIToUTF16("Add At 1"));
- auto select_at =
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Select At 1"));
+ auto add = std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TABBED_PANE_ADD_LABEL));
+ auto add_at = std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TABBED_PANE_ADD_1_LABEL));
+ auto select_at = std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TABBED_PANE_SELECT_1_LABEL));
GridLayout* layout =
container->SetLayoutManager(std::make_unique<views::GridLayout>());
@@ -36,21 +42,21 @@ void TabbedPaneExample::CreateExampleView(View* container) {
const int tabbed_pane_column = 0;
ColumnSet* column_set = layout->AddColumnSet(tabbed_pane_column);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(1 /* expand */, tabbed_pane_column);
tabbed_pane_ = layout->AddView(std::move(tabbed_pane));
// Create a few tabs with a button first.
- AddButton("Tab 1");
- AddButton("Tab 2");
- AddButton("Tab 3");
+ AddButton(GetStringUTF16(IDS_TABBED_PANE_TAB_1_LABEL));
+ AddButton(GetStringUTF16(IDS_TABBED_PANE_TAB_2_LABEL));
+ AddButton(GetStringUTF16(IDS_TABBED_PANE_TAB_3_LABEL));
// Add control buttons horizontally.
const int button_column = 1;
column_set = layout->AddColumnSet(button_column);
for (size_t i = 0; i < 3; i++) {
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
}
layout->StartRow(0 /* no expand */, button_column);
@@ -61,9 +67,9 @@ void TabbedPaneExample::CreateExampleView(View* container) {
void TabbedPaneExample::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == add_) {
- AddButton("Added");
+ AddButton(GetStringUTF16(IDS_TABBED_PANE_ADDED_LABEL));
} else if (sender == add_at_) {
- const base::string16 label = ASCIIToUTF16("Added at 1");
+ const base::string16 label = GetStringUTF16(IDS_TABBED_PANE_ADDED_1_LABEL);
tabbed_pane_->AddTabAtIndex(1, label,
std::make_unique<LabelButton>(nullptr, label));
} else if (sender == select_at_) {
@@ -83,9 +89,8 @@ void TabbedPaneExample::PrintCurrentStatus() {
tabbed_pane_->GetTabCount(), tabbed_pane_->GetSelectedTabIndex());
}
-void TabbedPaneExample::AddButton(const std::string& label) {
- tabbed_pane_->AddTab(ASCIIToUTF16(label), std::make_unique<LabelButton>(
- nullptr, ASCIIToUTF16(label)));
+void TabbedPaneExample::AddButton(const base::string16& label) {
+ tabbed_pane_->AddTab(label, std::make_unique<LabelButton>(nullptr, label));
}
} // namespace examples
diff --git a/chromium/ui/views/examples/tabbed_pane_example.h b/chromium/ui/views/examples/tabbed_pane_example.h
index 5806ca9c5c2..ce4fe34d4e9 100644
--- a/chromium/ui/views/examples/tabbed_pane_example.h
+++ b/chromium/ui/views/examples/tabbed_pane_example.h
@@ -38,7 +38,7 @@ class VIEWS_EXAMPLES_EXPORT TabbedPaneExample : public ExampleBase,
// Print the status of the tab in the status area.
void PrintCurrentStatus();
- void AddButton(const std::string& label);
+ void AddButton(const base::string16& label);
// The tabbed pane to be tested.
TabbedPane* tabbed_pane_;
diff --git a/chromium/ui/views/examples/table_example.cc b/chromium/ui/views/examples/table_example.cc
index e5913af4951..c272f3b3eca 100644
--- a/chromium/ui/views/examples/table_example.cc
+++ b/chromium/ui/views/examples/table_example.cc
@@ -67,20 +67,20 @@ void TableExample::CreateExampleView(View* container) {
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(1 /* expand */, 0);
table_ = table.get();
layout->AddView(TableView::CreateScrollViewWithTable(std::move(table)));
column_set = layout->AddColumnSet(1);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.5f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.5f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.5f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.5f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(0 /* no expand */, 1);
diff --git a/chromium/ui/views/examples/text_example.cc b/chromium/ui/views/examples/text_example.cc
index 61a68575fde..7e0e015d872 100644
--- a/chromium/ui/views/examples/text_example.cc
+++ b/chromium/ui/views/examples/text_example.cc
@@ -168,10 +168,10 @@ void TextExample::CreateExampleView(View* container) {
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddPaddingColumn(0, 8);
column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0.1f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
for (int i = 0; i < kNumColumns - 1; i++)
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.1f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(0, 8);
h_align_cb_ = AddCombobox(layout, "H-Align", kHorizontalAligments,
@@ -196,7 +196,7 @@ void TextExample::CreateExampleView(View* container) {
column_set = layout->AddColumnSet(1);
column_set->AddPaddingColumn(0, 16);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(0, 16);
layout->StartRow(1, 1);
text_view_ = layout->AddView(std::move(text_view));
diff --git a/chromium/ui/views/examples/textfield_example.cc b/chromium/ui/views/examples/textfield_example.cc
index 4daa1e35f4b..7f1d9b2ddc4 100644
--- a/chromium/ui/views/examples/textfield_example.cc
+++ b/chromium/ui/views/examples/textfield_example.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/events/event.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/range/range.h"
@@ -18,11 +19,12 @@
#include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/examples/examples_window.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
-using base::ASCIIToUTF16;
-using base::UTF16ToUTF8;
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
namespace views {
namespace examples {
@@ -41,7 +43,8 @@ T* MakeRow(GridLayout* layout,
} // namespace
-TextfieldExample::TextfieldExample() : ExampleBase("Textfield") {}
+TextfieldExample::TextfieldExample()
+ : ExampleBase(GetStringUTF8(IDS_TEXTFIELD_SELECT_LABEL).c_str()) {}
TextfieldExample::~TextfieldExample() = default;
@@ -50,14 +53,15 @@ void TextfieldExample::CreateExampleView(View* container) {
name->set_controller(this);
auto password = std::make_unique<Textfield>();
password->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
- password->SetPlaceholderText(ASCIIToUTF16("password"));
+ password->SetPlaceholderText(
+ GetStringUTF16(IDS_TEXTFIELD_PASSWORD_PLACEHOLDER));
password->set_controller(this);
auto disabled = std::make_unique<Textfield>();
disabled->SetEnabled(false);
- disabled->SetText(ASCIIToUTF16("disabled"));
+ disabled->SetText(GetStringUTF16(IDS_TEXTFIELD_DISABLED_PLACEHOLDER));
auto read_only = std::make_unique<Textfield>();
read_only->SetReadOnly(true);
- read_only->SetText(ASCIIToUTF16("read only"));
+ read_only->SetText(GetStringUTF16(IDS_TEXTFFIELD_READ_ONLY_PLACEHOLDER));
auto invalid = std::make_unique<Textfield>();
invalid->SetInvalid(true);
auto rtl = std::make_unique<Textfield>();
@@ -68,57 +72,59 @@ void TextfieldExample::CreateExampleView(View* container) {
ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0.2f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.8f,
- GridLayout::USE_PREF, 0, 0);
-
- name_ = MakeRow(layout, std::make_unique<Label>(ASCIIToUTF16("Name:")),
- std::move(name));
- password_ =
- MakeRow(layout, std::make_unique<Label>(ASCIIToUTF16("Password:")),
- std::move(password));
- disabled_ =
- MakeRow(layout, std::make_unique<Label>(ASCIIToUTF16("Disabled:")),
- std::move(disabled));
- read_only_ =
- MakeRow(layout, std::make_unique<Label>(ASCIIToUTF16("Read Only:")),
- std::move(read_only));
- invalid_ = MakeRow(layout, std::make_unique<Label>(ASCIIToUTF16("Invalid:")),
- std::move(invalid));
- rtl_ = MakeRow(layout, std::make_unique<Label>(ASCIIToUTF16("RTL:")),
- std::move(rtl));
- MakeRow<View, Label>(layout, nullptr,
- std::make_unique<Label>(ASCIIToUTF16("Name:")));
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+
+ name_ = MakeRow(
+ layout, std::make_unique<Label>(GetStringUTF16(IDS_TEXTFIELD_NAME_LABEL)),
+ std::move(name));
+ password_ = MakeRow(
+ layout,
+ std::make_unique<Label>(GetStringUTF16(IDS_TEXTFIELD_PASSWORD_LABEL)),
+ std::move(password));
+ disabled_ = MakeRow(
+ layout,
+ std::make_unique<Label>(GetStringUTF16(IDS_TEXTFIELD_DISABLED_LABEL)),
+ std::move(disabled));
+ read_only_ = MakeRow(
+ layout,
+ std::make_unique<Label>(GetStringUTF16(IDS_TEXTFIELD_READ_ONLY_LABEL)),
+ std::move(read_only));
+ invalid_ = MakeRow(
+ layout,
+ std::make_unique<Label>(GetStringUTF16(IDS_TEXTFIELD_INVALID_LABEL)),
+ std::move(invalid));
+ rtl_ = MakeRow(
+ layout, std::make_unique<Label>(GetStringUTF16(IDS_TEXTFIELD_RTL_LABEL)),
+ std::move(rtl));
+ MakeRow<View, Label>(
+ layout, nullptr,
+ std::make_unique<Label>(GetStringUTF16(IDS_TEXTFIELD_NAME_LABEL)));
show_password_ = MakeRow<View, LabelButton>(
layout, nullptr,
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Show password")));
+ std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TEXTFIELD_SHOW_PASSWORD_LABEL)));
set_background_ = MakeRow<View, LabelButton>(
layout, nullptr,
std::make_unique<LabelButton>(
- this, ASCIIToUTF16("Set non-default background")));
+ this, GetStringUTF16(IDS_TEXTFIELD_BACKGROUND_LABEL)));
clear_all_ = MakeRow<View, LabelButton>(
layout, nullptr,
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Clear All")));
+ std::make_unique<LabelButton>(this,
+ GetStringUTF16(IDS_TEXTFIELD_CLEAR_LABEL)));
append_ = MakeRow<View, LabelButton>(
layout, nullptr,
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Append")));
+ std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TEXTFIELD_APPEND_LABEL)));
set_ = MakeRow<View, LabelButton>(
layout, nullptr,
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Set")));
+ std::make_unique<LabelButton>(this,
+ GetStringUTF16(IDS_TEXTFIELD_SET_LABEL)));
set_style_ = MakeRow<View, LabelButton>(
layout, nullptr,
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Set Styles")));
-}
-
-void TextfieldExample::ContentsChanged(Textfield* sender,
- const base::string16& new_contents) {
- if (sender == name_) {
- PrintStatus("Name [%s]", UTF16ToUTF8(new_contents).c_str());
- } else if (sender == password_) {
- PrintStatus("Password [%s]", UTF16ToUTF8(new_contents).c_str());
- } else {
- NOTREACHED();
- }
+ std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TEXTFIELD_SET_STYLE_LABEL)));
}
bool TextfieldExample::HandleKeyEvent(Textfield* sender,
@@ -134,7 +140,8 @@ bool TextfieldExample::HandleMouseEvent(Textfield* sender,
void TextfieldExample::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == show_password_) {
- PrintStatus("Password [%s]", UTF16ToUTF8(password_->GetText()).c_str());
+ PrintStatus("Password [%s]",
+ base::UTF16ToUTF8(password_->GetText()).c_str());
} else if (sender == set_background_) {
password_->SetBackgroundColor(gfx::kGoogleRed300);
} else if (sender == clear_all_) {
@@ -146,19 +153,19 @@ void TextfieldExample::ButtonPressed(Button* sender, const ui::Event& event) {
invalid_->SetText(empty);
rtl_->SetText(empty);
} else if (sender == append_) {
- name_->AppendText(ASCIIToUTF16("[append]"));
- password_->AppendText(ASCIIToUTF16("[append]"));
- disabled_->SetText(ASCIIToUTF16("[append]"));
- read_only_->AppendText(ASCIIToUTF16("[append]"));
- invalid_->AppendText(ASCIIToUTF16("[append]"));
- rtl_->AppendText(ASCIIToUTF16("[append]"));
+ name_->AppendText(GetStringUTF16(IDS_TEXTFIELD_APPEND_UPDATE_TEXT));
+ password_->AppendText(GetStringUTF16(IDS_TEXTFIELD_APPEND_UPDATE_TEXT));
+ disabled_->SetText(GetStringUTF16(IDS_TEXTFIELD_APPEND_UPDATE_TEXT));
+ read_only_->AppendText(GetStringUTF16(IDS_TEXTFIELD_APPEND_UPDATE_TEXT));
+ invalid_->AppendText(GetStringUTF16(IDS_TEXTFIELD_APPEND_UPDATE_TEXT));
+ rtl_->AppendText(GetStringUTF16(IDS_TEXTFIELD_APPEND_UPDATE_TEXT));
} else if (sender == set_) {
- name_->SetText(ASCIIToUTF16("[set]"));
- password_->SetText(ASCIIToUTF16("[set]"));
- disabled_->SetText(ASCIIToUTF16("[set]"));
- read_only_->SetText(ASCIIToUTF16("[set]"));
- invalid_->SetText(ASCIIToUTF16("[set]"));
- rtl_->SetText(ASCIIToUTF16("[set]"));
+ name_->SetText(GetStringUTF16(IDS_TEXTFIELD_SET_UPDATE_TEXT));
+ password_->SetText(GetStringUTF16(IDS_TEXTFIELD_SET_UPDATE_TEXT));
+ disabled_->SetText(GetStringUTF16(IDS_TEXTFIELD_SET_UPDATE_TEXT));
+ read_only_->SetText(GetStringUTF16(IDS_TEXTFIELD_SET_UPDATE_TEXT));
+ invalid_->SetText(GetStringUTF16(IDS_TEXTFIELD_SET_UPDATE_TEXT));
+ rtl_->SetText(GetStringUTF16(IDS_TEXTFIELD_SET_UPDATE_TEXT));
} else if (sender == set_style_) {
if (!name_->GetText().empty()) {
name_->SetColor(SK_ColorGREEN);
diff --git a/chromium/ui/views/examples/textfield_example.h b/chromium/ui/views/examples/textfield_example.h
index 9ea0144b72d..6ab66ff47f9 100644
--- a/chromium/ui/views/examples/textfield_example.h
+++ b/chromium/ui/views/examples/textfield_example.h
@@ -31,8 +31,6 @@ class VIEWS_EXAMPLES_EXPORT TextfieldExample : public ExampleBase,
private:
// TextfieldController:
- void ContentsChanged(Textfield* sender,
- const base::string16& new_contents) override;
bool HandleKeyEvent(Textfield* sender,
const ui::KeyEvent& key_event) override;
bool HandleMouseEvent(Textfield* sender,
diff --git a/chromium/ui/views/examples/throbber_example.cc b/chromium/ui/views/examples/throbber_example.cc
index 6ad3f26e663..4d90b9e804c 100644
--- a/chromium/ui/views/examples/throbber_example.cc
+++ b/chromium/ui/views/examples/throbber_example.cc
@@ -7,7 +7,9 @@
#include <memory>
#include "base/macros.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/throbber.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
@@ -18,8 +20,8 @@ namespace {
class ThrobberView : public View {
public:
- ThrobberView() : throbber_(new Throbber()) {
- AddChildView(throbber_);
+ ThrobberView() {
+ throbber_ = AddChildView(std::make_unique<Throbber>());
throbber_->Start();
}
@@ -57,13 +59,15 @@ class ThrobberView : public View {
} // namespace
-ThrobberExample::ThrobberExample() : ExampleBase("Throbber") {}
+ThrobberExample::ThrobberExample()
+ : ExampleBase(l10n_util::GetStringUTF8(IDS_THROBBER_SELECT_LABEL).c_str()) {
+}
ThrobberExample::~ThrobberExample() = default;
void ThrobberExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<FillLayout>());
- container->AddChildView(new ThrobberView());
+ container->AddChildView(std::make_unique<ThrobberView>());
}
} // namespace examples
diff --git a/chromium/ui/views/examples/toggle_button_example.cc b/chromium/ui/views/examples/toggle_button_example.cc
index 88084f387e1..3bc279ffc1e 100644
--- a/chromium/ui/views/examples/toggle_button_example.cc
+++ b/chromium/ui/views/examples/toggle_button_example.cc
@@ -9,24 +9,27 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/controls/button/toggle_button.h"
#include "ui/views/examples/examples_window.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/box_layout.h"
namespace views {
namespace examples {
-ToggleButtonExample::ToggleButtonExample() : ExampleBase("Toggle button") {}
+ToggleButtonExample::ToggleButtonExample()
+ : ExampleBase(
+ l10n_util::GetStringUTF8(IDS_TOGGLE_BUTTON_SELECT_LABEL).c_str()) {}
ToggleButtonExample::~ToggleButtonExample() = default;
void ToggleButtonExample::CreateExampleView(View* container) {
- button_ = new ToggleButton(this);
auto layout = std::make_unique<BoxLayout>(BoxLayout::Orientation::kVertical);
layout->set_cross_axis_alignment(BoxLayout::CrossAxisAlignment::kCenter);
container->SetLayoutManager(std::move(layout));
- container->AddChildView(button_);
+ button_ = container->AddChildView(std::make_unique<ToggleButton>(this));
}
void ToggleButtonExample::ButtonPressed(Button* sender,
diff --git a/chromium/ui/views/examples/tree_view_example.cc b/chromium/ui/views/examples/tree_view_example.cc
index 0e84bce0823..dea712ae3e9 100644
--- a/chromium/ui/views/examples/tree_view_example.cc
+++ b/chromium/ui/views/examples/tree_view_example.cc
@@ -7,15 +7,18 @@
#include <utility>
#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/tree/tree_view.h"
#include "ui/views/controls/tree/tree_view_drawing_provider.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/grid_layout.h"
-using base::ASCIIToUTF16;
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
namespace {
@@ -27,7 +30,7 @@ class ExampleTreeViewDrawingProvider : public views::TreeViewDrawingProvider {
base::string16 GetAuxiliaryTextForNode(views::TreeView* tree_view,
ui::TreeModelNode* node) override {
if (tree_view->GetSelectedNode() == node)
- return base::UTF8ToUTF16("Selected");
+ return GetStringUTF16(IDS_TREE_VIEW_SELECTED_LABEL);
return views::TreeViewDrawingProvider::GetAuxiliaryTextForNode(tree_view,
node);
}
@@ -44,8 +47,10 @@ namespace views {
namespace examples {
TreeViewExample::TreeViewExample()
- : ExampleBase("Tree View"),
- model_(std::make_unique<NodeType>(ASCIIToUTF16("root"), 1)) {}
+ : ExampleBase(GetStringUTF8(IDS_TREE_VIEW_SELECT_LABEL).c_str()),
+ model_(std::make_unique<NodeType>(
+ GetStringUTF16(IDS_TREE_VIEW_ROOT_NODE_LABEL),
+ 1)) {}
TreeViewExample::~TreeViewExample() {
// Remove the model from the view.
@@ -56,15 +61,29 @@ TreeViewExample::~TreeViewExample() {
void TreeViewExample::CreateExampleView(View* container) {
// Add some sample data.
NodeType* colors_node = model_.GetRoot()->Add(
- std::make_unique<NodeType>(ASCIIToUTF16("colors"), 1), 0);
- colors_node->Add(std::make_unique<NodeType>(ASCIIToUTF16("red"), 1), 0);
- colors_node->Add(std::make_unique<NodeType>(ASCIIToUTF16("green"), 1), 1);
- colors_node->Add(std::make_unique<NodeType>(ASCIIToUTF16("blue"), 1), 2);
+ std::make_unique<NodeType>(GetStringUTF16(IDS_TREE_VIEW_COLOR_NODE_LABEL),
+ 1),
+ 0);
+ colors_node->Add(std::make_unique<NodeType>(
+ GetStringUTF16(IDS_TREE_VIEW_COLOR_RED_LABEL), 1),
+ 0);
+ colors_node->Add(std::make_unique<NodeType>(
+ GetStringUTF16(IDS_TREE_VIEW_COLOR_GREEN_LABEL), 1),
+ 1);
+ colors_node->Add(std::make_unique<NodeType>(
+ GetStringUTF16(IDS_TREE_VIEW_COLOR_BLUE_LABEL), 1),
+ 2);
NodeType* sheep_node = model_.GetRoot()->Add(
- std::make_unique<NodeType>(ASCIIToUTF16("sheep"), 1), 0);
- sheep_node->Add(std::make_unique<NodeType>(ASCIIToUTF16("Sheep 1"), 1), 0);
- sheep_node->Add(std::make_unique<NodeType>(ASCIIToUTF16("Sheep 2"), 1), 1);
+ std::make_unique<NodeType>(GetStringUTF16(IDS_TREE_VIEW_SHEEP_NODE_LABEL),
+ 1),
+ 0);
+ sheep_node->Add(
+ std::make_unique<NodeType>(GetStringUTF16(IDS_TREE_VIEW_SHEEP1_LABEL), 1),
+ 0);
+ sheep_node->Add(
+ std::make_unique<NodeType>(GetStringUTF16(IDS_TREE_VIEW_SHEEP2_LABEL), 1),
+ 1);
auto tree_view = std::make_unique<TreeView>();
tree_view->set_context_menu_controller(this);
@@ -73,14 +92,16 @@ void TreeViewExample::CreateExampleView(View* container) {
tree_view->SetController(this);
tree_view->SetDrawingProvider(
std::make_unique<ExampleTreeViewDrawingProvider>());
- auto add = std::make_unique<LabelButton>(this, ASCIIToUTF16("Add"));
+ auto add = std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TREE_VIEW_ADD_BUTTON_LABEL));
add->SetFocusForPlatform();
add->set_request_focus_on_press(true);
- auto remove = std::make_unique<LabelButton>(this, ASCIIToUTF16("Remove"));
+ auto remove = std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TREE_VIEW_REMOVE_BUTTON_LABEL));
remove->SetFocusForPlatform();
remove->set_request_focus_on_press(true);
- auto change_title =
- std::make_unique<LabelButton>(this, ASCIIToUTF16("Change Title"));
+ auto change_title = std::make_unique<LabelButton>(
+ this, GetStringUTF16(IDS_TREE_VIEW_CHANGE_TITLE_LABEL));
change_title->SetFocusForPlatform();
change_title->set_request_focus_on_press(true);
@@ -90,7 +111,7 @@ void TreeViewExample::CreateExampleView(View* container) {
const int tree_view_column = 0;
ColumnSet* column_set = layout->AddColumnSet(tree_view_column);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(1 /* expand */, tree_view_column);
tree_view_ = tree_view.get();
layout->AddView(TreeView::CreateScrollViewWithTree(std::move(tree_view)));
@@ -100,7 +121,7 @@ void TreeViewExample::CreateExampleView(View* container) {
column_set = layout->AddColumnSet(button_column);
for (size_t i = 0; i < 3; i++) {
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1.0f,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
}
layout->StartRow(0 /* no expand */, button_column);
@@ -136,7 +157,8 @@ void TreeViewExample::ButtonPressed(Button* sender, const ui::Event& event) {
} else if (sender == change_title_) {
DCHECK(selected_node);
model_.SetTitle(selected_node,
- selected_node->GetTitle() + ASCIIToUTF16("new"));
+ selected_node->GetTitle() +
+ GetStringUTF16(IDS_TREE_VIEW_NEW_NODE_LABEL));
}
}
@@ -160,9 +182,12 @@ void TreeViewExample::ShowContextMenuForViewImpl(
const gfx::Point& point,
ui::MenuSourceType source_type) {
context_menu_model_ = std::make_unique<ui::SimpleMenuModel>(this);
- context_menu_model_->AddItem(ID_EDIT, ASCIIToUTF16("Edit"));
- context_menu_model_->AddItem(ID_REMOVE, ASCIIToUTF16("Remove"));
- context_menu_model_->AddItem(ID_ADD, ASCIIToUTF16("Add"));
+ context_menu_model_->AddItem(ID_EDIT,
+ GetStringUTF16(IDS_TREE_VIEW_EDIT_BUTTON_LABEL));
+ context_menu_model_->AddItem(
+ ID_REMOVE, GetStringUTF16(IDS_TREE_VIEW_REMOVE_BUTTON_LABEL));
+ context_menu_model_->AddItem(ID_ADD,
+ GetStringUTF16(IDS_TREE_VIEW_ADD_BUTTON_LABEL));
context_menu_runner_ =
std::make_unique<MenuRunner>(context_menu_model_.get(), 0);
context_menu_runner_->RunMenuAt(source->GetWidget(), nullptr,
diff --git a/chromium/ui/views/examples/vector_example.cc b/chromium/ui/views/examples/vector_example.cc
index a3cebf68456..c447df47fcf 100644
--- a/chromium/ui/views/examples/vector_example.cc
+++ b/chromium/ui/views/examples/vector_example.cc
@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/border.h"
@@ -23,10 +24,14 @@
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
+
namespace views {
namespace examples {
@@ -59,20 +64,22 @@ class VectorIconGallery : public View,
auto file_chooser = std::make_unique<Textfield>();
file_chooser->SetPlaceholderText(
- base::ASCIIToUTF16("Enter a file to read"));
+ GetStringUTF16(IDS_VECTOR_FILE_SELECT_LABEL));
auto file_container = std::make_unique<View>();
BoxLayout* file_box =
file_container->SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kHorizontal, gfx::Insets(10), 10));
file_chooser_ = file_container->AddChildView(std::move(file_chooser));
file_go_button_ = file_container->AddChildView(
- MdTextButton::Create(this, base::ASCIIToUTF16("Render")));
+ MdTextButton::Create(this, GetStringUTF16(IDS_VECTOR_RENDER_LABEL)));
file_box->SetFlexForView(file_chooser_, 1);
AddChildView(std::move(file_container));
- size_input_->SetPlaceholderText(base::ASCIIToUTF16("Size in dip"));
+ size_input_->SetPlaceholderText(
+ GetStringUTF16(IDS_VECTOR_DIP_SIZE_DESC_LABEL));
size_input_->set_controller(this);
- color_input_->SetPlaceholderText(base::ASCIIToUTF16("Color (AARRGGBB)"));
+ color_input_->SetPlaceholderText(
+ GetStringUTF16(IDS_VECTOR_COLOR_DESC_LABEL));
color_input_->set_controller(this);
}
@@ -105,10 +112,10 @@ class VectorIconGallery : public View,
void ButtonPressed(Button* sender, const ui::Event& event) override {
DCHECK_EQ(file_go_button_, sender);
base::ScopedAllowBlockingForTesting allow_blocking;
-#if defined(OS_POSIX)
- base::FilePath path(base::UTF16ToUTF8(file_chooser_->GetText()));
-#elif defined(OS_WIN)
+#if defined(OS_WIN)
base::FilePath path(file_chooser_->GetText());
+#else
+ base::FilePath path(base::UTF16ToUTF8(file_chooser_->GetText()));
#endif
base::ReadFileToString(path, &contents_);
// Skip over comments.
@@ -147,13 +154,14 @@ class VectorIconGallery : public View,
} // namespace
-VectorExample::VectorExample() : ExampleBase("Vector Icon") {}
+VectorExample::VectorExample()
+ : ExampleBase(GetStringUTF8(IDS_VECTOR_SELECT_LABEL).c_str()) {}
VectorExample::~VectorExample() = default;
void VectorExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<FillLayout>());
- container->AddChildView(new VectorIconGallery());
+ container->AddChildView(std::make_unique<VectorIconGallery>());
}
} // namespace examples
diff --git a/chromium/ui/views/examples/views_examples_resources.grd b/chromium/ui/views/examples/views_examples_resources.grd
new file mode 100644
index 00000000000..207bbd371cf
--- /dev/null
+++ b/chromium/ui/views/examples/views_examples_resources.grd
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit base_dir="." latest_public_release="0" current_release="1"
+ output_all_resource_defines="false" source_lang_id="en" enc_check="möl">
+ <outputs>
+ <output filename="grit/views_examples_resources.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="views_examples_resources.pak" type="data_package" lang="en" />
+ </outputs>
+ <release seq="1" allow_pseudo="false">
+ <messages fallback_to_english="true">
+ <!-- colored dialog example -->
+ <message translateable="false" name="IDS_COLORED_DIALOG_CHOOSER_CHECKBOX">
+ Use Dark Theme
+ </message>
+ <message translateable="false" name="IDS_COLORED_DIALOG_CHOOSER_BUTTON">
+ Send Feedback
+ </message>
+ <message translateable="false" name="IDS_COLORED_DIALOG_CHOOSER_CONFIRM_LABEL">
+ Thank you! We received the following response: <ph name="USER_FEEDBACK">$1<ex>I like it.</ex></ph>
+ </message>
+ <message translateable="false" name="IDS_COLORED_DIALOG_TITLE">
+ Send Feedback to Chromium
+ </message>
+ <message translateable="false" name="IDS_COLORED_DIALOG_TEXTFIELD_PLACEHOLDER">
+ Please type your quick feedback here...
+ </message>
+ <message translateable="false" name="IDS_COLORED_DIALOG_TEXTFIELD_AX_LABEL">
+ Input Feedback
+ </message>
+ <message translateable="false" name="IDS_COLORED_DIALOG_SUBMIT_BUTTON">
+ Submit
+ </message>
+
+ <!-- layout base example -->
+ <message translateable="false" name="IDS_LAYOUT_BASE_ADD_LABEL">
+ Add
+ </message>
+
+ <!-- link example -->
+ <message translateable="false" name="IDS_LINK_SELECT_LABEL">
+ Link
+ </message>
+ <message translateable="false" name="IDS_LINK_CLICK_PROMPT_LABEL">
+ Click me!
+ </message>
+ <message translateable="false" name="IDS_LINK_CLICK_CONFIRMED_LABEL">
+ Link clicked
+ </message>
+
+ <!-- Login example -->
+ <message translateable="false" name="IDS_LOGIN_SELECT_LABEL">
+ Login Bubble Dialog
+ </message>
+ <message translateable="false" name="IDS_LOGIN_SHOW_BUTTON_LABEL">
+ Show
+ </message>
+ <message translateable="false" name="IDS_LOGIN_TITLE_LABEL">
+ Login Dialog
+ </message>
+ <message translateable="false" name="IDS_LOGIN_USERNAME_LABEL">
+ Username
+ </message>
+ <message translateable="false" name="IDS_LOGIN_PASSWORD_LABEL">
+ Password
+ </message>
+ <message translateable="false" name="IDS_LOGIN_OK_BUTTON_LABEL">
+ LOGIN
+ </message>
+
+ <!-- menu example -->
+ <message translateable="false" name="IDS_MENU_DO_SOMETHING_LABEL">
+ Do Something
+ </message>
+ <message translateable="false" name="IDS_MENU_ASCII_LABEL">
+ ASCII
+ </message>
+ <message translateable="false" name="IDS_MENU_UTF8_LABEL">
+ UTF-8
+ </message>
+ <message translateable="false" name="IDS_MENU_UTF16_LABEL">
+ UTF-16
+ </message>
+ <message translateable="false" name="IDS_MENU_APPLE_LABEL">
+ Apple
+ </message>
+ <message translateable="false" name="IDS_MENU_ORANGE_LABEL">
+ Orange
+ </message>
+ <message translateable="false" name="IDS_MENU_KIWI_LABEL">
+ Kiwi
+ </message>
+ <message translateable="false" name="IDS_MENU_GO_HOME_LABEL">
+ Go Home
+ </message>
+ <message translateable="false" name="IDS_MENU_DO_SOMETHING_2_LABEL">
+ Do Something 2
+ </message>
+ <message translateable="false" name="IDS_MENU_SUBMENU_LABEL">
+ Submenu
+ </message>
+ <message translateable="false" name="IDS_MENU_SELECT_LABEL">
+ Menu
+ </message>
+ <message translateable="false" name="IDS_MENU_BUTTON_LABEL">
+ Open a menu
+ </message>
+
+ <!-- message box example -->
+ <message translateable="false" name="IDS_MESSAGE_SELECT_LABEL">
+ Message Box View
+ </message>
+ <message translateable="false" name="IDS_MESSAGE_INTRO_LABEL">
+ Hello, world!
+ </message>
+ <message translateable="false" name="IDS_MESSAGE_CHECK_BOX_LABEL">
+ Check Box
+ </message>
+ <message translateable="false" name="IDS_MESSAGE_STATUS_LABEL">
+ Show Status
+ </message>
+ <message translateable="false" name="IDS_MESSAGE_TOGGLE_LABEL">
+ Toggle Checkbox
+ </message>
+ <message translateable="false" name="IDS_MESSAGE_ON_LABEL">
+ on
+ </message>
+ <message translateable="false" name="IDS_MESSAGE_OFF_LABEL">
+ off
+ </message>
+ <message translateable="false" name="IDS_MESSAGE_CHECK_SELECTED_LABEL">
+ Check Box Selected
+ </message>
+ <message translateable="false" name="IDS_MESSAGE_CHECK_NOT_SELECTED_LABEL">
+ Check Box Not Selected
+ </message>
+
+ <!-- multiline example -->
+ <message translateable="false" name="IDS_MULTILINE_SELECT_LABEL">
+ Multiline RenderText
+ </message>
+ <message translateable="false" name="IDS_MULTILINE_LABEL">
+ views::Label:
+ </message>
+ <message translateable="false" name="IDS_MULTILINE_ELIDE_LABEL">
+ elide text?
+ </message>
+ <message translateable="false" name="IDS_MULTILINE_RENDER_TEXT_LABEL">
+ gfx::RenderText:
+ </message>
+ <message translateable="false" name="IDS_MULTILINE_SAMPLE_TEXT_LABEL">
+ Sample Text:
+ </message>
+
+ <!-- native theme example -->
+ <message translateable="false" name="IDS_THEME_SELECT_LABEL">
+ Native Theme Colors
+ </message>
+
+ <!-- progress example -->
+ <message translateable="false" name="IDS_PROGRESS_SELECT_LABEL">
+ Progress Bar
+ </message>
+ <message translateable="false" name="IDS_PROGRESS_LOADER_LABEL">
+ Infinite Loader:
+ </message>
+ <message translateable="false" name="IDS_PROGRESS_LOADER_SHORT_LABEL">
+ Infinite loader (very short):
+ </message>
+
+ <!-- radio button example -->
+ <message translateable="false" name="IDS_RADIO_BUTTON_SELECT_LABEL">
+ Radio Button
+ </message>
+ <message translateable="false" name="IDS_RADIO_BUTTON_SELECT_BUTTON_LABEL">
+ Select
+ </message>
+ <message translateable="false" name="IDS_RADIO_BUTTON_STATUS_LABEL">
+ Show Status
+ </message>
+
+
+ <!-- scroll view example -->
+ <message translateable="false" name="IDS_SCROLL_VIEW_BUTTON_LABEL">
+ Button
+ </message>
+ <message translateable="false" name="IDS_SCROLL_VIEW_RADIO_BUTTON_LABEL">
+ Radio Button
+ </message>
+ <message translateable="false" name="IDS_SCROLL_VIEW_SELECT_LABEL">
+ Scroll View
+ </message>
+ <message translateable="false" name="IDS_SCROLL_VIEW_WIDE_LABEL">
+ Wide
+ </message>
+ <message translateable="false" name="IDS_SCROLL_VIEW_TALL_LABEL">
+ Tall
+ </message>
+ <message translateable="false" name="IDS_SCROLL_VIEW_BIG_SQUARE_LABEL">
+ Big Square
+ </message>
+ <message translateable="false" name="IDS_SCROLL_VIEW_SMALL_SQUARE_LABEL">
+ Small Square
+ </message>
+ <message translateable="false" name="IDS_SCROLL_VIEW_SCROLL_TO_LABEL">
+ Scroll to
+ </message>
+
+ <!-- slider example -->
+ <message translateable="false" name="IDS_SLIDER_SELECT_LABEL">
+ Slider
+ </message>
+
+ <!-- tabbed pane example -->
+ <message translateable="false" name="IDS_TABBED_PANE_SELECT_LABEL">
+ Tabbed Pane
+ </message>
+ <message translateable="false" name="IDS_TABBED_PANE_ADD_LABEL">
+ Add
+ </message>
+ <message translateable="false" name="IDS_TABBED_PANE_ADD_1_LABEL">
+ Add At 1
+ </message>
+ <message translateable="false" name="IDS_TABBED_PANE_SELECT_1_LABEL">
+ Select At 1
+ </message>
+ <message translateable="false" name="IDS_TABBED_PANE_TAB_1_LABEL">
+ Tab 1
+ </message>
+ <message translateable="false" name="IDS_TABBED_PANE_TAB_2_LABEL">
+ Tab 2
+ </message>
+ <message translateable="false" name="IDS_TABBED_PANE_TAB_3_LABEL">
+ Tab 3
+ </message>
+ <message translateable="false" name="IDS_TABBED_PANE_ADDED_LABEL">
+ Added
+ </message>
+ <message translateable="false" name="IDS_TABBED_PANE_ADDED_1_LABEL">
+ Added at 1
+ </message>
+
+ <!-- textfield example -->
+ <message translateable="false" name="IDS_TEXTFIELD_SELECT_LABEL">
+ Textfield
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_PASSWORD_PLACEHOLDER">
+ password
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_DISABLED_PLACEHOLDER">
+ disabled
+ </message>
+ <message translateable="false" name="IDS_TEXTFFIELD_READ_ONLY_PLACEHOLDER">
+ read only
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_NAME_LABEL">
+ Name:
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_PASSWORD_LABEL">
+ Password:
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_DISABLED_LABEL">
+ Disabled:
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_READ_ONLY_LABEL">
+ Read Only:
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_INVALID_LABEL">
+ Invalid:
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_RTL_LABEL">
+ RTL:
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_SHOW_PASSWORD_LABEL">
+ Show password
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_BACKGROUND_LABEL">
+ Set non-default background
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_CLEAR_LABEL">
+ Clear All
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_APPEND_LABEL">
+ Append
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_SET_LABEL">
+ Set
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_SET_STYLE_LABEL">
+ Set Styles
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_APPEND_UPDATE_TEXT">
+ [append]
+ </message>
+ <message translateable="false" name="IDS_TEXTFIELD_SET_UPDATE_TEXT">
+ [set]
+ </message>
+
+ <!-- throbber example -->
+ <message translateable="false" name="IDS_THROBBER_SELECT_LABEL">
+ Throbber
+ </message>
+
+ <!-- toggle button example -->
+ <message translateable="false" name="IDS_TOGGLE_BUTTON_SELECT_LABEL">
+ Toggle Button
+ </message>
+
+ <!-- tree view example -->
+ <message translateable="false" name="IDS_TREE_VIEW_SELECTED_LABEL">
+ Selected
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_SELECT_LABEL">
+ Tree View
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_ROOT_NODE_LABEL">
+ root
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_COLOR_NODE_LABEL">
+ colors
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_COLOR_RED_LABEL">
+ red
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_COLOR_GREEN_LABEL">
+ green
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_COLOR_BLUE_LABEL">
+ blue
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_SHEEP_NODE_LABEL">
+ sheep
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_SHEEP1_LABEL">
+ Sheep 1
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_SHEEP2_LABEL">
+ Sheep 2
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_ADD_BUTTON_LABEL">
+ Add
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_REMOVE_BUTTON_LABEL">
+ Remove
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_CHANGE_TITLE_LABEL">
+ Change Title
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_NEW_NODE_LABEL">
+ new
+ </message>
+ <message translateable="false" name="IDS_TREE_VIEW_EDIT_BUTTON_LABEL">
+ Edit
+ </message>
+
+ <!-- vector example -->
+ <message translateable="false" name="IDS_VECTOR_FILE_SELECT_LABEL">
+ Enter a file to read
+ </message>
+ <message translateable="false" name="IDS_VECTOR_RENDER_LABEL">
+ Render
+ </message>
+ <message translateable="false" name="IDS_VECTOR_DIP_SIZE_DESC_LABEL">
+ Size in dip
+ </message>
+ <message translateable="false" name="IDS_VECTOR_COLOR_DESC_LABEL">
+ Color (AARRGGBB)
+ </message>
+ <message translateable="false" name="IDS_VECTOR_SELECT_LABEL">
+ Vector Icon
+ </message>
+
+ <!-- webview example -->
+ <message translateable="false" name="IDS_WEBVIEW_SELECT_LABEL">
+ WebView
+ </message>
+
+ <!-- widget example -->
+ <message translateable="false" name="IDS_WIDGET_EXTRA_BUTTON">
+ Extra button!
+ </message>
+ <message translateable="false" name="IDS_WIDGET_FOOTNOTE_LABEL">
+ Footnote label!
+ </message>
+ <message translateable="false" name="IDS_WIDGET_DIALOG_CONTENTS_LABEL">
+ Dialog contents label!
+ </message>
+ <message translateable="false" name="IDS_WIDGET_WINDOW_TITLE">
+ Dialog Widget Example
+ </message>
+ <message translateable="false" name="IDS_WIDGET_SELECT_LABEL">
+ Widget
+ </message>
+ <message translateable="false" name="IDS_WIDGET_POPUP_BUTTON_LABEL">
+ Popup widget
+ </message>
+ <message translateable="false" name="IDS_WIDGET_DIALOG_BUTTON_LABEL">
+ Dialog widget
+ </message>
+ <message translateable="false" name="IDS_WIDGET_MODAL_BUTTON_LABEL">
+ Modal Dialog
+ </message>
+ <message translateable="false" name="IDS_WIDGET_CHILD_WIDGET_BUTTON_LABEL">
+ Child widget
+ </message>
+ <message translateable="false" name="IDS_WIDGET_CLOSE_BUTTON_LABEL">
+ Close
+ </message>
+ </messages>
+ </release>
+</grit> \ No newline at end of file
diff --git a/chromium/ui/views/examples/webview_example.cc b/chromium/ui/views/examples/webview_example.cc
index 8058e35c25a..1571dd2fc9e 100644
--- a/chromium/ui/views/examples/webview_example.cc
+++ b/chromium/ui/views/examples/webview_example.cc
@@ -8,14 +8,16 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/webview/webview.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/fill_layout.h"
namespace views {
namespace examples {
WebViewExample::WebViewExample(content::BrowserContext* browser_context)
- : ExampleBase("WebView"),
+ : ExampleBase(l10n_util::GetStringUTF8(IDS_WEBVIEW_SELECT_LABEL).c_str()),
webview_(nullptr),
browser_context_(browser_context) {}
diff --git a/chromium/ui/views/examples/widget_example.cc b/chromium/ui/views/examples/widget_example.cc
index a09246ab1fb..7a4106184e2 100644
--- a/chromium/ui/views/examples/widget_example.cc
+++ b/chromium/ui/views/examples/widget_example.cc
@@ -10,16 +10,19 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/label.h"
+#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
-using base::ASCIIToUTF16;
+using l10n_util::GetStringUTF16;
+using l10n_util::GetStringUTF8;
namespace views {
namespace examples {
@@ -48,40 +51,45 @@ WidgetDialogExample::WidgetDialogExample() {
SetBackground(CreateSolidBackground(SK_ColorGRAY));
SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kVertical, gfx::Insets(10), 10));
- SetExtraView(MdTextButton::CreateSecondaryUiButton(
- nullptr, ASCIIToUTF16("Extra button!")));
- SetFootnoteView(std::make_unique<Label>(ASCIIToUTF16("Footnote label!")));
- AddChildView(new Label(ASCIIToUTF16("Dialog contents label!")));
+ SetExtraView(
+ MdTextButton::Create(nullptr, GetStringUTF16(IDS_WIDGET_EXTRA_BUTTON)));
+ SetFootnoteView(
+ std::make_unique<Label>(GetStringUTF16(IDS_WIDGET_FOOTNOTE_LABEL)));
+ AddChildView(new Label(GetStringUTF16(IDS_WIDGET_DIALOG_CONTENTS_LABEL)));
}
WidgetDialogExample::~WidgetDialogExample() = default;
base::string16 WidgetDialogExample::GetWindowTitle() const {
- return ASCIIToUTF16("Dialog Widget Example");
+ return GetStringUTF16(IDS_WIDGET_WINDOW_TITLE);
}
} // namespace
-WidgetExample::WidgetExample() : ExampleBase("Widget") {}
+WidgetExample::WidgetExample()
+ : ExampleBase(GetStringUTF8(IDS_WIDGET_SELECT_LABEL).c_str()) {}
WidgetExample::~WidgetExample() = default;
void WidgetExample::CreateExampleView(View* container) {
container->SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::Orientation::kHorizontal, gfx::Insets(), 10));
- BuildButton(container, "Popup widget", POPUP);
- BuildButton(container, "Dialog widget", DIALOG);
- BuildButton(container, "Modal Dialog", MODAL_DIALOG);
+ BuildButton(container, GetStringUTF16(IDS_WIDGET_POPUP_BUTTON_LABEL), POPUP);
+ BuildButton(container, GetStringUTF16(IDS_WIDGET_DIALOG_BUTTON_LABEL),
+ DIALOG);
+ BuildButton(container, GetStringUTF16(IDS_WIDGET_MODAL_BUTTON_LABEL),
+ MODAL_DIALOG);
#if defined(OS_LINUX)
// Windows does not support TYPE_CONTROL top-level widgets.
- BuildButton(container, "Child widget", CHILD);
+ BuildButton(container, GetStringUTF16(IDS_WIDGET_CHILD_WIDGET_BUTTON_LABEL),
+ CHILD);
#endif
}
void WidgetExample::BuildButton(View* container,
- const std::string& label,
+ const base::string16& label,
int tag) {
- LabelButton* button = new LabelButton(this, ASCIIToUTF16(label));
+ LabelButton* button = new LabelButton(this, label);
button->SetFocusForPlatform();
button->set_request_focus_on_press(true);
button->set_tag(tag);
@@ -103,7 +111,8 @@ void WidgetExample::ShowWidget(View* sender, Widget::InitParams params) {
contents->SetLayoutManager(
std::make_unique<BoxLayout>(BoxLayout::Orientation::kHorizontal));
contents->SetBackground(CreateSolidBackground(SK_ColorGRAY));
- BuildButton(contents, "Close", CLOSE_WIDGET);
+ BuildButton(contents, GetStringUTF16(IDS_WIDGET_CLOSE_BUTTON_LABEL),
+ CLOSE_WIDGET);
widget->SetContentsView(contents);
}
diff --git a/chromium/ui/views/examples/widget_example.h b/chromium/ui/views/examples/widget_example.h
index 1d8cce31d74..1094f135c01 100644
--- a/chromium/ui/views/examples/widget_example.h
+++ b/chromium/ui/views/examples/widget_example.h
@@ -36,7 +36,7 @@ class VIEWS_EXAMPLES_EXPORT WidgetExample : public ExampleBase,
};
// Construct a button with the specified |label| and |tag| in |container|.
- void BuildButton(View* container, const std::string& label, int tag);
+ void BuildButton(View* container, const base::string16& label, int tag);
// Construct a Widget for |sender|, initialize with |params|, and call Show().
void ShowWidget(View* sender, Widget::InitParams params);
diff --git a/chromium/ui/views/focus/external_focus_tracker.cc b/chromium/ui/views/focus/external_focus_tracker.cc
index 5eef3af77e3..62143e3d6c5 100644
--- a/chromium/ui/views/focus/external_focus_tracker.cc
+++ b/chromium/ui/views/focus/external_focus_tracker.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/logging.h"
+#include "base/check.h"
#include "ui/views/view.h"
#include "ui/views/view_tracker.h"
diff --git a/chromium/ui/views/focus/focus_manager.cc b/chromium/ui/views/focus/focus_manager.cc
index 462a3e67c80..0b634e3f151 100644
--- a/chromium/ui/views/focus/focus_manager.cc
+++ b/chromium/ui/views/focus/focus_manager.cc
@@ -9,14 +9,15 @@
#include <vector>
#include "base/auto_reset.h"
+#include "base/check_op.h"
#include "base/i18n/rtl.h"
-#include "base/logging.h"
#include "build/build_config.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/focus/focus_manager_delegate.h"
#include "ui/views/focus/focus_search.h"
#include "ui/views/focus/widget_focus_manager.h"
@@ -312,7 +313,7 @@ View* FocusManager::GetNextFocusableView(View* original_starting_view,
// the starting views widget or |widget_|.
Widget* widget = starting_view ? starting_view->GetWidget()
: original_starting_view->GetWidget();
- if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
+ if (widget->widget_delegate()->focus_traverses_out())
widget = widget_;
return GetNextFocusableView(nullptr, widget, reverse, true);
}
@@ -522,7 +523,22 @@ void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
if (accelerator_manager_.Process(accelerator))
return true;
- return delegate_ && delegate_->ProcessAccelerator(accelerator);
+ if (delegate_ && delegate_->ProcessAccelerator(accelerator))
+ return true;
+
+#if defined(OS_MACOSX)
+ // On MacOS accelerators are processed when a bubble is opened without
+ // manual redirection to bubble anchor widget. Including redirect on MacOS
+ // breaks processing accelerators by the bubble itself.
+ return false;
+#else
+ return RedirectAcceleratorToBubbleAnchorWidget(accelerator);
+#endif
+}
+
+bool FocusManager::IsAcceleratorRegistered(
+ const ui::Accelerator& accelerator) const {
+ return accelerator_manager_.IsRegistered(accelerator);
}
bool FocusManager::HasPriorityHandler(
@@ -591,4 +607,25 @@ void FocusManager::OnViewIsDeleting(View* view) {
SetFocusedView(nullptr);
}
+bool FocusManager::RedirectAcceleratorToBubbleAnchorWidget(
+ const ui::Accelerator& accelerator) {
+ Widget* anchor_widget = GetBubbleAnchorWidget();
+ if (!anchor_widget)
+ return false;
+
+ FocusManager* focus_manager = anchor_widget->GetFocusManager();
+ if (!focus_manager->IsAcceleratorRegistered(accelerator))
+ return false;
+
+ // The parent view must be focused for it to process events.
+ focus_manager->SetFocusedView(anchor_widget->GetRootView());
+ return focus_manager->ProcessAccelerator(accelerator);
+}
+
+Widget* FocusManager::GetBubbleAnchorWidget() {
+ BubbleDialogDelegateView* widget_delegate =
+ widget_->widget_delegate()->AsBubbleDialogDelegate();
+ return widget_delegate ? widget_delegate->anchor_widget() : nullptr;
+}
+
} // namespace views
diff --git a/chromium/ui/views/focus/focus_manager.h b/chromium/ui/views/focus/focus_manager.h
index 909a4fee3fe..8c7888aeff3 100644
--- a/chromium/ui/views/focus/focus_manager.h
+++ b/chromium/ui/views/focus/focus_manager.h
@@ -256,6 +256,9 @@ class VIEWS_EXPORT FocusManager : public ViewObserver {
void AddFocusChangeListener(FocusChangeListener* listener);
void RemoveFocusChangeListener(FocusChangeListener* listener);
+ // Whether the given |accelerator| is registered.
+ bool IsAcceleratorRegistered(const ui::Accelerator& accelerator) const;
+
// Whether the given |accelerator| has a priority handler associated with it.
bool HasPriorityHandler(const ui::Accelerator& accelerator) const;
@@ -293,11 +296,10 @@ class VIEWS_EXPORT FocusManager : public ViewObserver {
}
// Returns the next focusable view. Traversal starts at |starting_view|. If
- // |starting_view| is NULL |starting_widget| is consuled to determine which
- // Widget to start from. See
- // WidgetDelegate::ShouldAdvanceFocusToTopLevelWidget() for details. If both
- // |starting_view| and |starting_widget| are NULL, traversal starts at
- // |widget_|.
+ // |starting_view| is null, |starting_widget| is consulted to determine which
+ // Widget to start from. See WidgetDelegate::Params::focus_traverses_out for
+ // details. If both |starting_view| and |starting_widget| are null, traversal
+ // starts at |widget_|.
View* GetNextFocusableView(View* starting_view,
Widget* starting_widget,
bool reverse,
@@ -329,6 +331,14 @@ class VIEWS_EXPORT FocusManager : public ViewObserver {
// ViewObserver:
void OnViewIsDeleting(View* view) override;
+ // Try to redirect the accelerator to bubble's anchor widget to process it if
+ // the bubble didn't.
+ bool RedirectAcceleratorToBubbleAnchorWidget(
+ const ui::Accelerator& accelerator);
+
+ // Returns bubble's anchor widget.
+ Widget* GetBubbleAnchorWidget();
+
// Whether arrow key traversal is enabled globally.
static bool arrow_key_traversal_enabled_;
diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc
index b96e317503e..b4438b0aa46 100644
--- a/chromium/ui/views/focus/focus_manager_unittest.cc
+++ b/chromium/ui/views/focus/focus_manager_unittest.cc
@@ -54,6 +54,9 @@ class SimpleTestView : public View {
SetID(view_id);
}
+ SimpleTestView(const SimpleTestView&) = delete;
+ SimpleTestView& operator=(const SimpleTestView&) = delete;
+
void OnFocus() override {
event_list_->push_back({
ON_FOCUS,
@@ -72,8 +75,6 @@ class SimpleTestView : public View {
private:
std::vector<FocusTestEvent>* event_list_;
-
- DISALLOW_COPY_AND_ASSIGN(SimpleTestView);
};
// Tests that the appropriate Focus related methods are called when a View
@@ -379,6 +380,11 @@ class SelfUnregisteringAcceleratorTarget : public ui::TestAcceleratorTarget {
FocusManager* focus_manager)
: accelerator_(accelerator), focus_manager_(focus_manager) {}
+ SelfUnregisteringAcceleratorTarget(
+ const SelfUnregisteringAcceleratorTarget&) = delete;
+ SelfUnregisteringAcceleratorTarget& operator=(
+ const SelfUnregisteringAcceleratorTarget&) = delete;
+
// ui::TestAcceleratorTarget:
bool AcceleratorPressed(const ui::Accelerator& accelerator) override {
focus_manager_->UnregisterAccelerator(accelerator, this);
@@ -388,8 +394,6 @@ class SelfUnregisteringAcceleratorTarget : public ui::TestAcceleratorTarget {
private:
ui::Accelerator accelerator_;
FocusManager* focus_manager_;
-
- DISALLOW_COPY_AND_ASSIGN(SelfUnregisteringAcceleratorTarget);
};
TEST_F(FocusManagerTest, CallsSelfDeletingAcceleratorTarget) {
@@ -438,20 +442,22 @@ class FocusManagerDtorTest : public FocusManagerTest {
: FocusManager(widget, nullptr /* delegate */),
dtor_tracker_(dtor_tracker) {}
+ FocusManagerDtorTracked(const FocusManagerDtorTracked&) = delete;
+ FocusManagerDtorTracked& operator=(const FocusManagerDtorTracked&) = delete;
+
~FocusManagerDtorTracked() override {
dtor_tracker_->push_back("FocusManagerDtorTracked");
}
DtorTrackVector* dtor_tracker_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FocusManagerDtorTracked);
};
class TestFocusManagerFactory : public FocusManagerFactory {
public:
explicit TestFocusManagerFactory(DtorTrackVector* dtor_tracker)
: dtor_tracker_(dtor_tracker) {}
+ TestFocusManagerFactory(const TestFocusManagerFactory&) = delete;
+ TestFocusManagerFactory& operator=(const TestFocusManagerFactory&) = delete;
~TestFocusManagerFactory() override = default;
std::unique_ptr<FocusManager> CreateFocusManager(Widget* widget) override {
@@ -460,8 +466,6 @@ class FocusManagerDtorTest : public FocusManagerTest {
private:
DtorTrackVector* dtor_tracker_;
-
- DISALLOW_COPY_AND_ASSIGN(TestFocusManagerFactory);
};
class WindowDtorTracked : public Widget {
@@ -506,6 +510,11 @@ class FocusInAboutToRequestFocusFromTabTraversalView : public View {
public:
FocusInAboutToRequestFocusFromTabTraversalView() = default;
+ FocusInAboutToRequestFocusFromTabTraversalView(
+ const FocusInAboutToRequestFocusFromTabTraversalView&) = delete;
+ FocusInAboutToRequestFocusFromTabTraversalView& operator=(
+ const FocusInAboutToRequestFocusFromTabTraversalView&) = delete;
+
void set_view_to_focus(View* view) { view_to_focus_ = view; }
void AboutToRequestFocusFromTabTraversal(bool reverse) override {
@@ -514,8 +523,6 @@ class FocusInAboutToRequestFocusFromTabTraversalView : public View {
private:
views::View* view_to_focus_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(FocusInAboutToRequestFocusFromTabTraversalView);
};
} // namespace
@@ -643,6 +650,10 @@ class FocusManagerArrowKeyTraversalTest
public testing::WithParamInterface<bool> {
public:
FocusManagerArrowKeyTraversalTest() = default;
+ FocusManagerArrowKeyTraversalTest(const FocusManagerArrowKeyTraversalTest&) =
+ delete;
+ FocusManagerArrowKeyTraversalTest& operator=(
+ const FocusManagerArrowKeyTraversalTest&) = delete;
~FocusManagerArrowKeyTraversalTest() override = default;
// FocusManagerTest overrides:
@@ -671,8 +682,6 @@ class FocusManagerArrowKeyTraversalTest
base::test::ScopedRestoreICUDefaultLocale restore_locale_;
bool previous_arrow_key_traversal_enabled_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(FocusManagerArrowKeyTraversalTest);
};
// Instantiate the Boolean which is used to toggle RTL in
@@ -851,26 +860,18 @@ namespace {
// ShouldAdvanceFocusToTopLevelWidget().
class AdvanceFocusWidgetDelegate : public WidgetDelegate {
public:
- explicit AdvanceFocusWidgetDelegate(Widget* widget)
- : widget_(widget), should_advance_focus_to_parent_(false) {}
+ explicit AdvanceFocusWidgetDelegate(Widget* widget) : widget_(widget) {}
+ AdvanceFocusWidgetDelegate(const AdvanceFocusWidgetDelegate&) = delete;
+ AdvanceFocusWidgetDelegate& operator=(const AdvanceFocusWidgetDelegate&) =
+ delete;
~AdvanceFocusWidgetDelegate() override = default;
- void set_should_advance_focus_to_parent(bool value) {
- should_advance_focus_to_parent_ = value;
- }
-
// WidgetDelegate:
- bool ShouldAdvanceFocusToTopLevelWidget() const override {
- return should_advance_focus_to_parent_;
- }
Widget* GetWidget() override { return widget_; }
const Widget* GetWidget() const override { return widget_; }
private:
Widget* widget_;
- bool should_advance_focus_to_parent_;
-
- DISALLOW_COPY_AND_ASSIGN(AdvanceFocusWidgetDelegate);
};
class TestBubbleDialogDelegateView : public BubbleDialogDelegateView {
@@ -879,8 +880,23 @@ class TestBubbleDialogDelegateView : public BubbleDialogDelegateView {
: BubbleDialogDelegateView(anchor, BubbleBorder::NONE) {
DialogDelegate::SetButtons(ui::DIALOG_BUTTON_NONE);
}
+ TestBubbleDialogDelegateView(const TestBubbleDialogDelegateView&) = delete;
+ TestBubbleDialogDelegateView& operator=(const TestBubbleDialogDelegateView&) =
+ delete;
~TestBubbleDialogDelegateView() override = default;
+ static TestBubbleDialogDelegateView* CreateAndShowBubble(View* anchor) {
+ TestBubbleDialogDelegateView* bubble =
+ new TestBubbleDialogDelegateView(anchor);
+ Widget* bubble_widget = BubbleDialogDelegateView::CreateBubble(bubble);
+ bubble_widget->SetFocusTraversableParent(
+ bubble->anchor_widget()->GetFocusTraversable());
+ bubble_widget->SetFocusTraversableParentView(anchor);
+ bubble->set_close_on_deactivate(false);
+ bubble_widget->Show();
+ return bubble;
+ }
+
// If this is called, the bubble will be forced to use a NativeWidgetAura.
// If not set, it might get a DesktopNativeWidgetAura depending on the
// platform and other factors.
@@ -899,8 +915,6 @@ class TestBubbleDialogDelegateView : public BubbleDialogDelegateView {
private:
bool use_native_widget_aura_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(TestBubbleDialogDelegateView);
};
} // namespace
@@ -950,7 +964,7 @@ TEST_F(FocusManagerTest, AdvanceFocusStaysInWidget) {
// Allow focus to go to the parent, and focus backwards which should now move
// up |widget_view| (in the parent).
- delegate->set_should_advance_focus_to_parent(true);
+ delegate->SetFocusTraversesOut(true);
GetFocusManager()->AdvanceFocus(true);
EXPECT_EQ(widget_view, GetFocusManager()->GetFocusedView());
}
@@ -984,21 +998,15 @@ TEST_F(FocusManagerTest, NavigateIntoAnchoredDialog) {
parent3->AddChildView(new View());
BubbleDialogDelegateView* bubble_delegate =
- new TestBubbleDialogDelegateView(parent3);
- test::WidgetTest::WidgetAutoclosePtr bubble_widget(
- BubbleDialogDelegateView::CreateBubble(bubble_delegate));
- bubble_widget->SetFocusTraversableParent(
- bubble_delegate->anchor_widget()->GetFocusTraversable());
+ TestBubbleDialogDelegateView::CreateAndShowBubble(parent3);
+ Widget* bubble_widget = bubble_delegate->GetWidget();
- bubble_widget->SetFocusTraversableParentView(parent3);
View* child1 = new View();
View* child2 = new View();
child1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
child2->SetFocusBehavior(View::FocusBehavior::ALWAYS);
bubble_widget->GetRootView()->AddChildView(child1);
bubble_widget->GetRootView()->AddChildView(child2);
- bubble_delegate->set_close_on_deactivate(false);
- bubble_widget->Show();
parent1->RequestFocus();
@@ -1048,20 +1056,15 @@ TEST_F(FocusManagerTest, AnchoredDialogOnContainerView) {
GetWidget()->GetRootView()->AddChildView(parent4);
BubbleDialogDelegateView* bubble_delegate =
- new TestBubbleDialogDelegateView(parent_group);
- test::WidgetTest::WidgetAutoclosePtr bubble_widget(
- BubbleDialogDelegateView::CreateBubble(bubble_delegate));
- bubble_widget->SetFocusTraversableParent(
- bubble_delegate->anchor_widget()->GetFocusTraversable());
- bubble_widget->SetFocusTraversableParentView(parent_group);
+ TestBubbleDialogDelegateView::CreateAndShowBubble(parent3);
+ Widget* bubble_widget = bubble_delegate->GetWidget();
+
View* child1 = new View();
View* child2 = new View();
child1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
child2->SetFocusBehavior(View::FocusBehavior::ALWAYS);
bubble_widget->GetRootView()->AddChildView(child1);
bubble_widget->GetRootView()->AddChildView(child2);
- bubble_delegate->set_close_on_deactivate(false);
- bubble_widget->Show();
parent1->RequestFocus();
@@ -1097,14 +1100,8 @@ TEST_F(FocusManagerTest, AnchoredDialogInPane) {
View* anchor = pane->AddChildView(std::make_unique<View>());
anchor->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- BubbleDialogDelegateView* bubble = new TestBubbleDialogDelegateView(anchor);
- test::WidgetTest::WidgetAutoclosePtr bubble_widget(
- BubbleDialogDelegateView::CreateBubble(bubble));
- bubble_widget->SetFocusTraversableParent(
- bubble->anchor_widget()->GetFocusTraversable());
- bubble_widget->SetFocusTraversableParentView(anchor);
- bubble->set_close_on_deactivate(false);
- bubble_widget->Show();
+ BubbleDialogDelegateView* bubble =
+ TestBubbleDialogDelegateView::CreateAndShowBubble(anchor);
// We need a focusable view inside our bubble to check that focus traverses
// in.
@@ -1127,6 +1124,9 @@ TEST_F(FocusManagerTest, AnchoredDialogInPane) {
class DesktopWidgetFocusManagerTest : public FocusManagerTest {
public:
DesktopWidgetFocusManagerTest() = default;
+ DesktopWidgetFocusManagerTest(const DesktopWidgetFocusManagerTest&) = delete;
+ DesktopWidgetFocusManagerTest& operator=(
+ const DesktopWidgetFocusManagerTest&) = delete;
~DesktopWidgetFocusManagerTest() override = default;
// FocusManagerTest:
@@ -1134,9 +1134,6 @@ class DesktopWidgetFocusManagerTest : public FocusManagerTest {
set_native_widget_type(NativeWidgetType::kDesktop);
FocusManagerTest::SetUp();
}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DesktopWidgetFocusManagerTest);
};
TEST_F(DesktopWidgetFocusManagerTest, AnchoredDialogInDesktopNativeWidgetAura) {
@@ -1158,18 +1155,13 @@ TEST_F(DesktopWidgetFocusManagerTest, AnchoredDialogInDesktopNativeWidgetAura) {
widget.GetRootView()->AddChildView(parent2);
TestBubbleDialogDelegateView* bubble_delegate =
- new TestBubbleDialogDelegateView(parent2);
+ TestBubbleDialogDelegateView::CreateAndShowBubble(parent2);
+ Widget* bubble_widget = bubble_delegate->GetWidget();
bubble_delegate->UseNativeWidgetAura();
- test::WidgetTest::WidgetAutoclosePtr bubble_widget(
- BubbleDialogDelegateView::CreateBubble(bubble_delegate));
- bubble_widget->SetFocusTraversableParent(
- bubble_delegate->anchor_widget()->GetFocusTraversable());
- bubble_widget->SetFocusTraversableParentView(parent2);
+
View* child = new View();
child->SetFocusBehavior(View::FocusBehavior::ALWAYS);
bubble_widget->GetRootView()->AddChildView(child);
- bubble_delegate->set_close_on_deactivate(false);
- bubble_widget->Show();
widget.Activate();
parent1->RequestFocus();
@@ -1234,4 +1226,83 @@ TEST_F(FocusManagerTest, HandlesFocusCycles) {
EXPECT_FALSE(left->HasFocus());
}
+#if defined(USE_AURA)
+class RedirectToParentFocusManagerTest : public FocusManagerTest {
+ public:
+ RedirectToParentFocusManagerTest() = default;
+ RedirectToParentFocusManagerTest(const RedirectToParentFocusManagerTest&) =
+ delete;
+ RedirectToParentFocusManagerTest& operator=(
+ const RedirectToParentFocusManagerTest&) = delete;
+ ~RedirectToParentFocusManagerTest() override = default;
+
+ // FocusManagerTest:
+ void SetUp() override {
+ FocusManagerTest::SetUp();
+
+ View* anchor =
+ GetWidget()->GetRootView()->AddChildView(std::make_unique<View>());
+ anchor->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+
+ BubbleDialogDelegateView* bubble_delegate =
+ TestBubbleDialogDelegateView::CreateAndShowBubble(anchor);
+ Widget* bubble_widget = bubble_delegate->GetWidget();
+
+ parent_focus_manager_ = anchor->GetFocusManager();
+ bubble_focus_manager_ = bubble_widget->GetFocusManager();
+ }
+
+ void TearDown() override {
+ FocusManagerFactory::Install(nullptr);
+ FocusManagerTest::TearDown();
+ }
+
+ protected:
+ FocusManager* parent_focus_manager_;
+ FocusManager* bubble_focus_manager_;
+};
+
+// Test that when an accelerator is sent to a bubble that isn't registered,
+// the bubble's parent handles it instead.
+TEST_F(RedirectToParentFocusManagerTest, ParentHandlesAcceleratorFromBubble) {
+ ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
+ ui::TestAcceleratorTarget parent_return_target(true);
+
+ EXPECT_EQ(0, parent_return_target.accelerator_count());
+ parent_focus_manager_->RegisterAccelerator(
+ return_accelerator, ui::AcceleratorManager::kNormalPriority,
+ &parent_return_target);
+
+ EXPECT_TRUE(
+ !bubble_focus_manager_->IsAcceleratorRegistered(return_accelerator));
+ // Accelerator was proccesed by the parent.
+ EXPECT_TRUE(bubble_focus_manager_->ProcessAccelerator(return_accelerator));
+ EXPECT_EQ(parent_return_target.accelerator_count(), 1);
+}
+
+// Test that when an accelerator is sent to a bubble that is registered on both
+// it and its parent, the bubble handles it.
+TEST_F(RedirectToParentFocusManagerTest, BubbleHandlesRegisteredAccelerators) {
+ ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
+ ui::TestAcceleratorTarget parent_return_target(true);
+ ui::TestAcceleratorTarget bubble_return_target(true);
+
+ EXPECT_EQ(0, bubble_return_target.accelerator_count());
+ EXPECT_EQ(0, parent_return_target.accelerator_count());
+
+ bubble_focus_manager_->RegisterAccelerator(
+ return_accelerator, ui::AcceleratorManager::kNormalPriority,
+ &bubble_return_target);
+ parent_focus_manager_->RegisterAccelerator(
+ return_accelerator, ui::AcceleratorManager::kNormalPriority,
+ &parent_return_target);
+
+ // Accelerator was proccesed by the bubble and not by the parent.
+ EXPECT_TRUE(bubble_focus_manager_->ProcessAccelerator(return_accelerator));
+ EXPECT_EQ(1, bubble_return_target.accelerator_count());
+ EXPECT_EQ(0, parent_return_target.accelerator_count());
+}
+
+#endif
+
} // namespace views
diff --git a/chromium/ui/views/layout/animating_layout_manager.cc b/chromium/ui/views/layout/animating_layout_manager.cc
index a2e72769780..d436f28da5e 100644
--- a/chromium/ui/views/layout/animating_layout_manager.cc
+++ b/chromium/ui/views/layout/animating_layout_manager.cc
@@ -207,10 +207,10 @@ void AnimatingLayoutManager::AnimationDelegate::AnimationEnded(
AnimatingLayoutManager::AnimatingLayoutManager() = default;
AnimatingLayoutManager::~AnimatingLayoutManager() = default;
-AnimatingLayoutManager& AnimatingLayoutManager::SetShouldAnimateBounds(
- bool should_animate_bounds) {
- if (should_animate_bounds_ != should_animate_bounds) {
- should_animate_bounds_ = should_animate_bounds;
+AnimatingLayoutManager& AnimatingLayoutManager::SetBoundsAnimationMode(
+ BoundsAnimationMode bounds_animation_mode) {
+ if (bounds_animation_mode_ != bounds_animation_mode) {
+ bounds_animation_mode_ = bounds_animation_mode;
ResetLayout();
}
return *this;
@@ -329,9 +329,21 @@ gfx::Size AnimatingLayoutManager::GetPreferredSize(const View* host) const {
if (!target_layout_manager())
return gfx::Size();
- return should_animate_bounds_
- ? current_layout_.host_size
- : target_layout_manager()->GetPreferredSize(host);
+ switch (bounds_animation_mode_) {
+ case BoundsAnimationMode::kUseHostBounds:
+ return target_layout_manager()->GetPreferredSize(host);
+ case BoundsAnimationMode::kAnimateMainAxis: {
+ // Animating only main axis, so cross axis is preferred size.
+ gfx::Size result = current_layout_.host_size;
+ SetCrossAxis(
+ &result, orientation(),
+ GetCrossAxis(orientation(),
+ target_layout_manager()->GetPreferredSize(host)));
+ return result;
+ }
+ case BoundsAnimationMode::kAnimateBothAxes:
+ return current_layout_.host_size;
+ }
}
gfx::Size AnimatingLayoutManager::GetMinimumSize(const View* host) const {
@@ -340,8 +352,20 @@ gfx::Size AnimatingLayoutManager::GetMinimumSize(const View* host) const {
// TODO(dfried): consider cases where the minimum size might not be just the
// minimum size of the embedded layout.
gfx::Size minimum_size = target_layout_manager()->GetMinimumSize(host);
- if (should_animate_bounds_)
- minimum_size.SetToMin(current_layout_.host_size);
+ switch (bounds_animation_mode_) {
+ case BoundsAnimationMode::kUseHostBounds:
+ // No modification required.
+ break;
+ case BoundsAnimationMode::kAnimateMainAxis:
+ SetMainAxis(
+ &minimum_size, orientation(),
+ std::min(GetMainAxis(orientation(), minimum_size),
+ GetMainAxis(orientation(), current_layout_.host_size)));
+ break;
+ case BoundsAnimationMode::kAnimateBothAxes:
+ minimum_size.SetToMin(current_layout_.host_size);
+ break;
+ }
return minimum_size;
}
@@ -351,9 +375,12 @@ int AnimatingLayoutManager::GetPreferredHeightForWidth(const View* host,
return 0;
// TODO(dfried): revisit this computation.
- return should_animate_bounds_
- ? current_layout_.host_size.height()
- : target_layout_manager()->GetPreferredHeightForWidth(host, width);
+ if (bounds_animation_mode_ == BoundsAnimationMode::kAnimateBothAxes ||
+ (bounds_animation_mode_ == BoundsAnimationMode::kAnimateMainAxis &&
+ orientation() == LayoutOrientation::kVertical)) {
+ return current_layout_.host_size.height();
+ }
+ return target_layout_manager()->GetPreferredHeightForWidth(host, width);
}
std::vector<View*> AnimatingLayoutManager::GetChildViewsInPaintOrder(
@@ -445,31 +472,48 @@ void AnimatingLayoutManager::LayoutImpl() {
// than an invalidation. This should reset the layout (but see the note in
// RecalculateTarget() below).
const gfx::Size host_size = host_view()->size();
- if (should_animate_bounds_) {
- // Reset the layout immediately if the current or target layout exceeds the
- // host size or the available space.
+
+ if (bounds_animation_mode_ == BoundsAnimationMode::kUseHostBounds) {
+ if (!cached_layout_size() || host_size != *cached_layout_size()) {
+ // Host size changed, so reset the layout.
+ ResetLayoutToTargetSize();
+ }
+
+ } else {
const SizeBounds available_size = GetAvailableHostSize();
- const base::Optional<int> bounds_main =
- GetMainAxis(orientation(), available_size);
- const int host_main = GetMainAxis(orientation(), host_size);
- const int current_main =
- GetMainAxis(orientation(), current_layout_.host_size);
- if (current_main > host_main ||
- (bounds_main && current_main > *bounds_main)) {
+
+ if (bounds_animation_mode_ == BoundsAnimationMode::kAnimateMainAxis &&
+ (!cached_layout_size() ||
+ GetCrossAxis(orientation(), host_size) !=
+ GetCrossAxis(orientation(), *cached_layout_size()))) {
+ // If we're fixed to the cross-axis size of the host and that size
+ // changes, we need to reset the layout.
last_available_host_size_ = available_size;
ResetLayoutToSize(host_size);
- } else if (available_size != last_available_host_size_) {
- // May need to re-trigger animation if our bounds were relaxed; let us
- // expand into the new available space.
- RecalculateTarget();
+ } else {
+ // Either both axes are animating or only the main axis is animating or
+ // the cross axis hasn't changed (because otherwise the previous condition
+ // would have executed instead).
+ const base::Optional<int> bounds_main =
+ GetMainAxis(orientation(), available_size);
+ const int host_main = GetMainAxis(orientation(), host_size);
+ const int current_main =
+ GetMainAxis(orientation(), current_layout_.host_size);
+ if (current_main > host_main ||
+ (bounds_main && current_main > *bounds_main)) {
+ // Reset the layout immediately if the current or target layout exceeds
+ // the host size or the available space.
+ last_available_host_size_ = available_size;
+ ResetLayoutToSize(host_size);
+ } else if (available_size != last_available_host_size_) {
+ // May need to re-trigger animation if our bounds were relaxed; let us
+ // expand into the new available space.
+ RecalculateTarget();
+ }
}
// Verify that the last available size has been updated.
DCHECK_EQ(available_size, last_available_host_size_);
-
- } else if (!cached_layout_size() || host_size != *cached_layout_size()) {
- // Host size changed, so reset the layout.
- ResetLayoutToTargetSize();
}
ApplyLayout(current_layout_);
@@ -529,7 +573,8 @@ bool AnimatingLayoutManager::RecalculateTarget() {
// space as adjacent child views appear/disappear. This will be useful in
// animating tab titles, which currently slide over when the favicon
// disappears.
- if (!should_animate_bounds_ && *cached_layout_size() != target_size) {
+ if (bounds_animation_mode_ == BoundsAnimationMode::kUseHostBounds &&
+ *cached_layout_size() != target_size) {
ResetLayoutToSize(target_size);
return true;
}
@@ -982,25 +1027,39 @@ ChildLayout AnimatingLayoutManager::CalculateSlideFade(
// Returns the space in which to calculate the target layout.
gfx::Size AnimatingLayoutManager::GetAvailableTargetLayoutSize() {
- if (!should_animate_bounds_)
+ if (bounds_animation_mode_ == BoundsAnimationMode::kUseHostBounds)
return host_view()->size();
const SizeBounds bounds = GetAvailableHostSize();
last_available_host_size_ = bounds;
const gfx::Size preferred_size =
target_layout_manager()->GetPreferredSize(host_view());
- if (!bounds.width() || *bounds.width() > preferred_size.width()) {
- return gfx::Size(preferred_size.width(),
- bounds.height()
- ? std::min(preferred_size.height(), *bounds.height())
- : preferred_size.height());
+
+ int width = preferred_size.width();
+
+ if (orientation() == LayoutOrientation::kVertical &&
+ bounds_animation_mode_ == BoundsAnimationMode::kAnimateMainAxis) {
+ width = host_view()->width();
+ } else if (bounds.width()) {
+ width = std::min(width, *bounds.width());
+ }
+
+ int height;
+
+ if (orientation() == LayoutOrientation::kHorizontal &&
+ bounds_animation_mode_ == BoundsAnimationMode::kAnimateMainAxis) {
+ height = host_view()->height();
+ } else {
+ height = width < preferred_size.width()
+ ? target_layout_manager()->GetPreferredHeightForWidth(
+ host_view(), width)
+ : preferred_size.height();
+ if (bounds.height()) {
+ height = std::min(height, *bounds.height());
+ }
}
- const int height = target_layout_manager()->GetPreferredHeightForWidth(
- host_view(), *bounds.width());
- return gfx::Size(*bounds.width(), bounds.height()
- ? std::min(height, *bounds.height())
- : height);
+ return gfx::Size(width, height);
}
// static
diff --git a/chromium/ui/views/layout/animating_layout_manager.h b/chromium/ui/views/layout/animating_layout_manager.h
index 207c1edef77..70561ebe5c7 100644
--- a/chromium/ui/views/layout/animating_layout_manager.h
+++ b/chromium/ui/views/layout/animating_layout_manager.h
@@ -44,7 +44,8 @@ namespace views {
//
// auto* animating_layout = button_container->SetLayoutManager(
// std::make_unique<AnimatingLayoutManager>());
-// animating_layout->SetShouldAnimateBounds(true);
+// animating_layout->SetBoundsAnimationMode(
+// AnimatingLayoutManager::BoundsAnimationMode::kAnimateMainAxis);
// auto* flex_layout = animating_layout->SetTargetLayoutManager(
// std::make_unique<FlexLayout>());
// flex_layout->SetOrientation(LayoutOrientation::kHorizontal)
@@ -71,6 +72,26 @@ class VIEWS_EXPORT AnimatingLayoutManager : public LayoutManagerBase {
bool is_animating) = 0;
};
+ // Describes if and how the bounds of the host view can be animated as part of
+ // layout animations, if the preferred size of the layout changes.
+ enum BoundsAnimationMode {
+ // Default behavior: the host view will always take the space given to it by
+ // its parent view and child views will animate within those bounds. Useful
+ // for cases where the layout is in a fixed-size container or dialog, but
+ // we want child views to be able to animate.
+ kUseHostBounds,
+ // The host view will request more or less space within the available space
+ // offered by its parent view, allowing its main axis size to animate, but
+ // will use exactly the cross-axis space provided, as it would with
+ // kUseHostBounds. Useful if the host view is in a toolbar or a dialog with
+ // fixed width but variable height or vice-versa.
+ kAnimateMainAxis,
+ // The host view will request more space or less space in both axes within
+ // the available space offered by its parent view. Useful if the host view
+ // is in e.g. a dialog that can vary in size.
+ kAnimateBothAxes
+ };
+
// Describes how a view which is appearing or disappearing during an animation
// behaves. Child views which are removed from the parent view always simply
// disappear; use one of the Fade methods below to cause a view to fade out.
@@ -96,8 +117,11 @@ class VIEWS_EXPORT AnimatingLayoutManager : public LayoutManagerBase {
AnimatingLayoutManager();
~AnimatingLayoutManager() override;
- bool should_animate_bounds() const { return should_animate_bounds_; }
- AnimatingLayoutManager& SetShouldAnimateBounds(bool should_animate_bounds);
+ BoundsAnimationMode bounds_animation_mode() const {
+ return bounds_animation_mode_;
+ }
+ AnimatingLayoutManager& SetBoundsAnimationMode(
+ BoundsAnimationMode bounds_animation_mode);
base::TimeDelta animation_duration() const { return animation_duration_; }
AnimatingLayoutManager& SetAnimationDuration(
@@ -253,11 +277,10 @@ class VIEWS_EXPORT AnimatingLayoutManager : public LayoutManagerBase {
const View* view,
const SizeBounds& size_bounds);
- // Whether or not to animate the bounds of the host view when the preferred
- // size of the layout changes. If false, the size will have to be set
- // explicitly by the host view's owner. Bounds animation is done by changing
- // the preferred size and invalidating the layout.
- bool should_animate_bounds_ = false;
+ // How to animate bounds of the host view when the preferred size of the
+ // layout changes.
+ BoundsAnimationMode bounds_animation_mode_ =
+ BoundsAnimationMode::kUseHostBounds;
// How long each animation takes. Depending on how far along an animation is,
// a new target layout will either cause the animation to restart or redirect.
diff --git a/chromium/ui/views/layout/animating_layout_manager_unittest.cc b/chromium/ui/views/layout/animating_layout_manager_unittest.cc
index 896ce78b5f5..8fc53d36838 100644
--- a/chromium/ui/views/layout/animating_layout_manager_unittest.cc
+++ b/chromium/ui/views/layout/animating_layout_manager_unittest.cc
@@ -15,6 +15,7 @@
#include "ui/gfx/animation/animation_test_api.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/normalized_geometry.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/view_class_properties.h"
@@ -251,7 +252,8 @@ const FlexSpecification AnimatingLayoutManagerTest::kFlex =
TEST_F(AnimatingLayoutManagerTest, SetLayoutManager_NoAnimation) {
auto test_layout = std::make_unique<TestLayoutManager>();
test_layout->SetLayout(layout1());
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetTargetLayoutManager(std::move(test_layout));
SizeAndLayout();
@@ -261,7 +263,8 @@ TEST_F(AnimatingLayoutManagerTest, SetLayoutManager_NoAnimation) {
}
TEST_F(AnimatingLayoutManagerTest, ResetLayout_NoAnimation) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -274,7 +277,8 @@ TEST_F(AnimatingLayoutManagerTest, ResetLayout_NoAnimation) {
}
TEST_F(AnimatingLayoutManagerTest, HostInvalidate_TriggersAnimation) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -293,7 +297,8 @@ TEST_F(AnimatingLayoutManagerTest, HostInvalidate_TriggersAnimation) {
TEST_F(AnimatingLayoutManagerTest,
HostInvalidate_AnimateBounds_AnimationProgresses) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -330,7 +335,8 @@ TEST_F(AnimatingLayoutManagerTest,
}
TEST_F(AnimatingLayoutManagerTest, HostInvalidate_NoAnimateBounds_NoAnimation) {
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -351,7 +357,8 @@ TEST_F(AnimatingLayoutManagerTest, HostInvalidate_NoAnimateBounds_NoAnimation) {
}
TEST_F(AnimatingLayoutManagerTest, HostResize_NoAnimateBounds_NoAnimation) {
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -375,7 +382,8 @@ TEST_F(AnimatingLayoutManagerTest, HostResize_NoAnimateBounds_NoAnimation) {
TEST_F(AnimatingLayoutManagerTest,
HostInvalidate_NoAnimateBounds_NewLayoutTriggersAnimation) {
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -400,7 +408,8 @@ TEST_F(AnimatingLayoutManagerTest,
TEST_F(AnimatingLayoutManagerTest,
HostInvalidate_NoAnimateBounds_AnimationProgresses) {
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -449,7 +458,8 @@ TEST_F(AnimatingLayoutManagerTest, FadeInOutMode_MiddleView_ScaleFromZero) {
{{child(0), true, {5, 5, 10, 10}},
{child(1), true, {20, 5, 10, 10}},
{child(2), true, {35, 5, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -528,7 +538,8 @@ TEST_F(AnimatingLayoutManagerTest, FadeInOutMode_MiddleView_ScaleFromMinimum) {
{{child(0), true, {5, 5, 10, 10}},
{child(1), true, {20, 5, 10, 10}},
{child(2), true, {35, 5, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromMinimum);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -591,7 +602,8 @@ TEST_F(AnimatingLayoutManagerTest, FadeInOutMode_LeadingView_ScaleFromMinimum) {
{{child(0), true, {5, 5, 10, 10}},
{child(1), true, {20, 5, 10, 10}},
{child(2), true, {35, 5, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromMinimum);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -654,7 +666,8 @@ TEST_F(AnimatingLayoutManagerTest,
{child(1), true, {20, 5, 10, 10}},
{child(2), false}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromMinimum);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -718,7 +731,8 @@ TEST_F(AnimatingLayoutManagerTest,
{{child(0), true, {5, 5, 10, 10}},
{child(1), true, {20, 5, 10, 10}},
{child(2), true, {35, 5, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromMinimum);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -782,7 +796,8 @@ TEST_F(AnimatingLayoutManagerTest,
{{child(0), true, {5, 5, 10, 10}},
{child(1), true, {5, 20, 10, 10}},
{child(2), true, {5, 35, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromMinimum);
layout()->SetOrientation(LayoutOrientation::kVertical);
@@ -839,7 +854,8 @@ TEST_F(AnimatingLayoutManagerTest,
TEST_F(AnimatingLayoutManagerTest,
FadeInOutMode_Hide_HidesViewDuringAnimation) {
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetDefaultFadeMode(AnimatingLayoutManager::FadeInOutMode::kHide);
layout()->SetOrientation(LayoutOrientation::kVertical);
FlexLayout* const flex_layout =
@@ -881,7 +897,8 @@ TEST_F(AnimatingLayoutManagerTest,
TEST_F(AnimatingLayoutManagerTest,
FadeInOutMode_Hide_HidesViewDuringAnimation_OneFrame) {
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetDefaultFadeMode(AnimatingLayoutManager::FadeInOutMode::kHide);
layout()->SetOrientation(LayoutOrientation::kVertical);
FlexLayout* const flex_layout =
@@ -916,7 +933,8 @@ TEST_F(AnimatingLayoutManagerTest,
TEST_F(AnimatingLayoutManagerTest,
FadeInOutMode_Hide_AnimationResetDuringHide) {
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetDefaultFadeMode(AnimatingLayoutManager::FadeInOutMode::kHide);
layout()->SetOrientation(LayoutOrientation::kVertical);
FlexLayout* const flex_layout =
@@ -957,7 +975,8 @@ TEST_F(AnimatingLayoutManagerTest, FadeInOutMode_SlideFromLeading_LastView) {
{child(1), true, {20, 5, 10, 10}},
{child(2), true, {35, 5, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kSlideFromLeadingEdge);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -1004,7 +1023,8 @@ TEST_F(AnimatingLayoutManagerTest, FadeInOutMode_SlideFromLeading_Vertical) {
{child(1), true, {5, 20, 10, 10}},
{child(2), true, {5, 35, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kSlideFromLeadingEdge);
layout()->SetOrientation(LayoutOrientation::kVertical);
@@ -1052,7 +1072,8 @@ TEST_F(AnimatingLayoutManagerTest, FadeInOutMode_SlideFromLeading_MiddleView) {
{child(1), false},
{child(2), true, {20, 5, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kSlideFromLeadingEdge);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -1102,7 +1123,8 @@ TEST_F(AnimatingLayoutManagerTest,
{child(1), true, {5, 5, 5, 10}},
{child(2), true, {20, 5, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kSlideFromLeadingEdge);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -1151,7 +1173,8 @@ TEST_F(AnimatingLayoutManagerTest, FadeInOutMode_SlideFromTrailing_MiddleView) {
{child(1), false},
{child(2), true, {20, 5, 10, 10}}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kSlideFromTrailingEdge);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -1191,7 +1214,8 @@ TEST_F(AnimatingLayoutManagerTest, FadeInOutMode_SlideFromTrailing_MiddleView) {
TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeOutOnVisibilitySet) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -1247,7 +1271,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeOutOnVisibilitySet) {
TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeInOnVisibilitySet) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -1306,7 +1331,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeInOnVisibilitySet) {
TEST_F(AnimatingLayoutManagerTest,
FlexLayout_AnimateOutOnDescendentVisbilitySet) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -1368,7 +1394,8 @@ TEST_F(AnimatingLayoutManagerTest,
TEST_F(AnimatingLayoutManagerTest,
FlexLayout_AnimateInOnDescendentVisbilitySet) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -1430,7 +1457,8 @@ TEST_F(AnimatingLayoutManagerTest,
// Regression test for crbug.com/1037625: crash in SetViewVisibility() (1/2)
TEST_F(AnimatingLayoutManagerTest, FlexLayout_RemoveFadingViewDoesNotCrash) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -1473,7 +1501,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_RemoveFadingViewDoesNotCrash) {
// Regression test for crbug.com/1037625: crash in SetViewVisibility() (2/2)
TEST_F(AnimatingLayoutManagerTest, FlexLayout_RemoveShowingViewDoesNotCrash) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
child(1)->SetVisible(false);
auto* const flex_layout =
@@ -1509,7 +1538,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_RemoveShowingViewDoesNotCrash) {
// Regression test for crbug.com/1037947 (1/2)
TEST_F(AnimatingLayoutManagerTest, FlexLayout_DoubleSlide) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kSlideFromTrailingEdge);
@@ -1596,7 +1626,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_DoubleSlide) {
// [A] [B]
//
TEST_F(AnimatingLayoutManagerTest, FlexLayout_RedirectAfterExchangePlaces) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kSlideFromLeadingEdge);
@@ -1647,7 +1678,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_RedirectAfterExchangePlaces) {
TEST_F(AnimatingLayoutManagerTest,
FlexLayout_PostDelayedActionAfterFadeIn_AnimateNewViewIn) {
child(0)->SetVisible(false);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -1686,7 +1718,8 @@ TEST_F(AnimatingLayoutManagerTest,
TEST_F(AnimatingLayoutManagerTest,
FlexLayout_PostDelayedActionAfterFadeIn_SwapTwoViews) {
child(0)->SetVisible(false);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -1726,7 +1759,8 @@ TEST_F(AnimatingLayoutManagerTest,
// change and FadeIn() was called.
TEST_F(AnimatingLayoutManagerTest,
FlexLayout_PostDelayedActionAfterFadeIn_FadeInHiddenView) {
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -1779,7 +1813,8 @@ TEST_F(AnimatingLayoutManagerTest, RemoveDuringAnimationDoesntCrash) {
const ProposedLayout final_layout{
{20, 20},
{{child(0), true, {5, 5, 10, 10}}, {child(1), false}, {child(2), false}}};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kSlideFromLeadingEdge);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
@@ -1809,7 +1844,8 @@ TEST_F(AnimatingLayoutManagerTest, RemoveDuringAnimationDoesntCrash) {
TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeInOnAdded) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -1869,7 +1905,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeInOnAdded) {
TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeIn) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -1926,7 +1963,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeIn) {
TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeOut) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -1982,7 +2020,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeOut) {
TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeOut_NoCrashOnRemove) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -2040,7 +2079,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeOut_NoCrashOnRemove) {
TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeOut_IgnoreChildView) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetOrientation(LayoutOrientation::kHorizontal);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
@@ -2094,7 +2134,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_FadeOut_IgnoreChildView) {
// which is hidden, and that such a layout change triggers animation.
TEST_F(AnimatingLayoutManagerTest, FlexLayout_SlideAfterViewHidden) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -2146,7 +2187,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_SlideAfterViewHidden) {
// which is removed, and that such a layout change triggers animation.
TEST_F(AnimatingLayoutManagerTest, FlexLayout_SlideAfterViewRemoved) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -2198,7 +2240,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_SlideAfterViewRemoved) {
// the animation redirects.
TEST_F(AnimatingLayoutManagerTest, FlexLayout_RedirectAnimation) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -2257,7 +2300,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_RedirectAnimation) {
// of the animation, the animation resets.
TEST_F(AnimatingLayoutManagerTest, FlexLayout_ResetAnimation) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -2317,7 +2361,8 @@ TEST_F(AnimatingLayoutManagerTest, FlexLayout_ResetAnimation) {
}
TEST_F(AnimatingLayoutManagerTest, TestEvents) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2348,7 +2393,8 @@ TEST_F(AnimatingLayoutManagerTest, TestEvents) {
}
TEST_F(AnimatingLayoutManagerTest, PostOrQueueAction) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2400,7 +2446,8 @@ TEST_F(AnimatingLayoutManagerTest, PostOrQueueAction) {
}
TEST_F(AnimatingLayoutManagerTest, PostOrQueueAction_ContinueAnimation) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2462,7 +2509,8 @@ TEST_F(AnimatingLayoutManagerTest, PostOrQueueAction_ContinueAnimation) {
}
TEST_F(AnimatingLayoutManagerTest, PostOrQueueAction_NeverFinishes) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2505,7 +2553,8 @@ TEST_F(AnimatingLayoutManagerTest, PostOrQueueAction_NeverFinishes) {
}
TEST_F(AnimatingLayoutManagerTest, PostOrQueueAction_MayPostImmediately) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2563,7 +2612,8 @@ TEST_F(AnimatingLayoutManagerTest, ZOrder_UnchangedWhenNotAnimating) {
}
TEST_F(AnimatingLayoutManagerTest, ZOrder_UnchangedWhenNotFading) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2603,7 +2653,8 @@ TEST_F(AnimatingLayoutManagerTest, ZOrder_FadingOutViewMovedToBack) {
const std::vector<View*> expected_order{child(1), child(0), child(2)};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
auto* const test_layout =
@@ -2642,7 +2693,8 @@ TEST_F(AnimatingLayoutManagerTest, ZOrder_FadingInViewMovedToBack) {
const std::vector<View*> expected_order{child(1), child(0), child(2)};
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetDefaultFadeMode(
AnimatingLayoutManager::FadeInOutMode::kScaleFromZero);
auto* const test_layout =
@@ -2669,7 +2721,8 @@ TEST_F(AnimatingLayoutManagerTest, ZOrder_FadingInViewMovedToBack) {
}
TEST_F(AnimatingLayoutManagerTest, ConstrainedSpace_StopsAnimation) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2689,7 +2742,8 @@ TEST_F(AnimatingLayoutManagerTest, ConstrainedSpace_StopsAnimation) {
}
TEST_F(AnimatingLayoutManagerTest, ConstrainedSpace_TriggersDelayedAction) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2717,7 +2771,8 @@ TEST_F(AnimatingLayoutManagerTest, ConstrainedSpace_TriggersDelayedAction) {
}
TEST_F(AnimatingLayoutManagerTest, ConstrainedSpace_SubsequentAnimation) {
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const test_layout =
layout()->SetTargetLayoutManager(std::make_unique<TestLayoutManager>());
test_layout->SetLayout(layout1());
@@ -2753,12 +2808,18 @@ constexpr base::TimeDelta kMinimumAnimationTime =
// invalidated.
class ImmediateLayoutManager : public LayoutManagerBase {
public:
- explicit ImmediateLayoutManager(bool use_preferred_size,
- SizeBounds size_bounds = SizeBounds())
- : use_preferred_size_(use_preferred_size),
- size_bounds_(std::move(size_bounds)) {
- DCHECK(use_preferred_size_ || size_bounds == SizeBounds());
- }
+ ImmediateLayoutManager()
+ : ImmediateLayoutManager(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes,
+ LayoutOrientation::kHorizontal) {}
+
+ ImmediateLayoutManager(
+ AnimatingLayoutManager::BoundsAnimationMode bounds_animation_mode,
+ LayoutOrientation orientation,
+ SizeBounds size_bounds = SizeBounds())
+ : bounds_animation_mode_(bounds_animation_mode),
+ orientation_(orientation),
+ size_bounds_(std::move(size_bounds)) {}
// LayoutManager:
@@ -2777,11 +2838,23 @@ class ImmediateLayoutManager : public LayoutManagerBase {
child_layout.child_view = child;
child_layout.visible = child->GetVisible();
child_layout.available_size = size_bounds_;
- if (use_preferred_size_) {
- child_layout.bounds = gfx::Rect(
- ConstrainSizeToBounds(child->GetPreferredSize(), size_bounds_));
- } else {
- child_layout.bounds = child->bounds();
+ switch (bounds_animation_mode_) {
+ case AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes:
+ child_layout.bounds = gfx::Rect(
+ ConstrainSizeToBounds(child->GetPreferredSize(), size_bounds_));
+ break;
+ case AnimatingLayoutManager::BoundsAnimationMode::kAnimateMainAxis: {
+ // Start with the preferred size constrained to the bounds, then force
+ // the cross axis.
+ gfx::Size size =
+ ConstrainSizeToBounds(child->GetPreferredSize(), size_bounds_);
+ SetCrossAxis(&size, orientation_,
+ GetCrossAxis(orientation_, child->bounds().size()));
+ child_layout.bounds = gfx::Rect(size);
+ } break;
+ case AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds:
+ child_layout.bounds = child->bounds();
+ break;
}
layout.host_size.SetToMax(child_layout.bounds.size());
layout.child_layouts.push_back(child_layout);
@@ -2796,7 +2869,8 @@ class ImmediateLayoutManager : public LayoutManagerBase {
}
private:
- const bool use_preferred_size_;
+ const AnimatingLayoutManager::BoundsAnimationMode bounds_animation_mode_;
+ const LayoutOrientation orientation_;
SizeBounds size_bounds_;
};
@@ -2865,7 +2939,7 @@ class AnimatingLayoutManagerAvailableSizeTest
void InitRootView() {
root_layout_ =
root_view()->SetLayoutManager(std::make_unique<ImmediateLayoutManager>(
- layout()->should_animate_bounds()));
+ layout()->bounds_animation_mode(), layout()->orientation()));
}
ImmediateLayoutManager* root_layout() { return root_layout_; }
@@ -2876,7 +2950,8 @@ class AnimatingLayoutManagerAvailableSizeTest
TEST_F(AnimatingLayoutManagerAvailableSizeTest, AvailableSize_LimitsExpansion) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -2924,7 +2999,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest, AvailableSize_LimitsExpansion) {
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_RestartsAnimation) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -2966,7 +3042,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_RestartsAnimation_Vertical) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kVertical);
@@ -3019,7 +3096,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_RedirectsAnimation) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3064,7 +3142,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest, AvailableSize_StopsAnimation) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3103,7 +3182,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest, AvailableSize_StopsAnimation) {
TEST_F(AnimatingLayoutManagerAvailableSizeTest, AvailableSize_ImmediateResize) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3131,7 +3211,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest, AvailableSize_ImmediateResize) {
TEST_F(AnimatingLayoutManagerAvailableSizeTest, AvailableSize_StepDownStepUp) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3173,7 +3254,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest, AvailableSize_StepDownStepUp) {
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_ConstraintRemovedStartsAnimation) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3213,7 +3295,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_LimitsExpansion_WithFlex) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3263,7 +3346,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_RestartsAnimation_WithFlex) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3306,7 +3390,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_RedirectsAnimation_WithFlex) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3354,7 +3439,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_StopsAnimation_WithFlex) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3395,7 +3481,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_ImmediateResize_WithFlex) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3425,7 +3512,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_StepDownStepUp_WithFlex) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3467,7 +3555,8 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
TEST_F(AnimatingLayoutManagerAvailableSizeTest,
AvailableSize_ConstraintRemovedStartsAnimation_WithFlex) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
flex_layout->SetOrientation(LayoutOrientation::kHorizontal);
@@ -3506,6 +3595,330 @@ TEST_F(AnimatingLayoutManagerAvailableSizeTest,
EXPECT_EQ(expected_events, logger.events());
}
+TEST_F(AnimatingLayoutManagerAvailableSizeTest,
+ AnimateMainAxis_Horizontal_MainAxisAnimates) {
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateMainAxis);
+ auto* const flex_layout =
+ layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
+ flex_layout->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart)
+ .SetDefault(kFlexBehaviorKey,
+ FlexSpecification(LayoutOrientation::kHorizontal,
+ MinimumFlexSizeRule::kPreferred,
+ MaximumFlexSizeRule::kPreferred, false,
+ MinimumFlexSizeRule::kScaleToZero));
+ view()->SetBoundsRect(gfx::Rect(0, 0, 5, 5));
+ InitRootView();
+ layout()->ResetLayout();
+ root_view()->Layout();
+
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(30, 5), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 5), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 0, 10, 5), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(20, 0, 10, 5), child(2)->bounds());
+
+ child(1)->SetVisible(false);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Advance the animation halfway.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(500));
+ EXPECT_TRUE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(25, 5), view()->size());
+
+ // Finish the animation.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(500));
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(20, 5), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 5), child(0)->bounds());
+ EXPECT_FALSE(child(1)->GetVisible());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 0, 10, 5), child(2)->bounds());
+}
+
+TEST_F(AnimatingLayoutManagerAvailableSizeTest,
+ AnimateMainAxis_Vertical_MainAxisAnimates) {
+ layout()
+ ->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateMainAxis)
+ .SetOrientation(LayoutOrientation::kVertical);
+ auto* const flex_layout =
+ layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
+ flex_layout->SetOrientation(LayoutOrientation::kVertical)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart)
+ .SetDefault(kFlexBehaviorKey,
+ FlexSpecification(LayoutOrientation::kVertical,
+ MinimumFlexSizeRule::kPreferred,
+ MaximumFlexSizeRule::kPreferred, false,
+ MinimumFlexSizeRule::kScaleToZero));
+ view()->SetBoundsRect(gfx::Rect(0, 0, 5, 5));
+ InitRootView();
+ layout()->ResetLayout();
+ root_view()->Layout();
+
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(5, 30), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 5, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 10, 5, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 20, 5, 10), child(2)->bounds());
+
+ child(1)->SetVisible(false);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Advance the animation halfway.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(500));
+ EXPECT_TRUE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(5, 25), view()->size());
+
+ // Finish the animation.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(500));
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(5, 20), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 5, 10), child(0)->bounds());
+ EXPECT_FALSE(child(1)->GetVisible());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 10, 5, 10), child(2)->bounds());
+}
+
+TEST_F(AnimatingLayoutManagerAvailableSizeTest,
+ AnimateMainAxis_Horizontal_CrossAxisSizeChangeResetsLayout) {
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateMainAxis);
+ auto* const flex_layout =
+ layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
+ flex_layout->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart)
+ .SetDefault(kFlexBehaviorKey,
+ FlexSpecification(LayoutOrientation::kHorizontal,
+ MinimumFlexSizeRule::kPreferred,
+ MaximumFlexSizeRule::kPreferred, false,
+ MinimumFlexSizeRule::kScaleToZero));
+ view()->SetBoundsRect(gfx::Rect(0, 0, 5, 5));
+ InitRootView();
+ layout()->ResetLayout();
+ root_view()->Layout();
+
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(30, 5), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 5), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 0, 10, 5), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(20, 0, 10, 5), child(2)->bounds());
+
+ child(1)->SetVisible(false);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Advance the animation halfway.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(500));
+ EXPECT_TRUE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(25, 5), view()->size());
+
+ // Change the cross-axis size.
+ view()->SetSize(gfx::Size(25, 7));
+ view()->InvalidateLayout();
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(20, 7), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 7), child(0)->bounds());
+ EXPECT_FALSE(child(1)->GetVisible());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 0, 10, 7), child(2)->bounds());
+}
+
+TEST_F(AnimatingLayoutManagerAvailableSizeTest,
+ AnimateMainAxis_Vertical_CrossAxisSizeChangeResetsLayout) {
+ layout()
+ ->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateMainAxis)
+ .SetOrientation(LayoutOrientation::kVertical);
+ auto* const flex_layout =
+ layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
+ flex_layout->SetOrientation(LayoutOrientation::kVertical)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart)
+ .SetDefault(kFlexBehaviorKey,
+ FlexSpecification(LayoutOrientation::kVertical,
+ MinimumFlexSizeRule::kPreferred,
+ MaximumFlexSizeRule::kPreferred, false,
+ MinimumFlexSizeRule::kScaleToZero));
+ view()->SetBoundsRect(gfx::Rect(0, 0, 5, 5));
+ InitRootView();
+ layout()->ResetLayout();
+ root_view()->Layout();
+
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(5, 30), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 5, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 10, 5, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 20, 5, 10), child(2)->bounds());
+
+ child(1)->SetVisible(false);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Advance the animation halfway.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(500));
+ EXPECT_TRUE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(5, 25), view()->size());
+
+ // Change the cross-axis size.
+ view()->SetSize(gfx::Size(7, 25));
+ view()->InvalidateLayout();
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(7, 20), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 7, 10), child(0)->bounds());
+ EXPECT_FALSE(child(1)->GetVisible());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 10, 7, 10), child(2)->bounds());
+}
+
+TEST_F(AnimatingLayoutManagerAvailableSizeTest,
+ AnimateMainAxis_Horizontal_CrossAxisAlignmentWorks) {
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateMainAxis);
+ auto* const flex_layout =
+ layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
+ flex_layout->SetOrientation(LayoutOrientation::kHorizontal)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart);
+ // Pick an arbitrary (wrong) main-axis size.
+ view()->SetBoundsRect(gfx::Rect(0, 0, 20, 20));
+ InitRootView();
+ layout()->ResetLayout();
+ root_view()->Layout();
+
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(30, 20), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 0, 10, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(20, 0, 10, 10), child(2)->bounds());
+
+ flex_layout->SetCrossAxisAlignment(LayoutAlignment::kCenter);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Finish the animation.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(30, 20), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 5, 10, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 5, 10, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(20, 5, 10, 10), child(2)->bounds());
+
+ flex_layout->SetCrossAxisAlignment(LayoutAlignment::kEnd);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Finish the animation.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(30, 20), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 10, 10, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 10, 10, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(20, 10, 10, 10), child(2)->bounds());
+
+ flex_layout->SetCrossAxisAlignment(LayoutAlignment::kStretch);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Finish the animation.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(30, 20), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 20), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 0, 10, 20), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(20, 0, 10, 20), child(2)->bounds());
+}
+
+TEST_F(AnimatingLayoutManagerAvailableSizeTest,
+ AnimateMainAxis_Vertical_CrossAxisAlignmentWorks) {
+ layout()
+ ->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateMainAxis)
+ .SetOrientation(LayoutOrientation::kVertical);
+ auto* const flex_layout =
+ layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
+ flex_layout->SetOrientation(LayoutOrientation::kVertical)
+ .SetCrossAxisAlignment(LayoutAlignment::kStart);
+ // Pick an arbitrary (wrong) main-axis size.
+ view()->SetBoundsRect(gfx::Rect(0, 0, 20, 20));
+ InitRootView();
+ layout()->ResetLayout();
+ root_view()->Layout();
+
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(20, 30), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 10, 10, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 20, 10, 10), child(2)->bounds());
+
+ flex_layout->SetCrossAxisAlignment(LayoutAlignment::kCenter);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Finish the animation.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(20, 30), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(5, 0, 10, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(5, 10, 10, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(5, 20, 10, 10), child(2)->bounds());
+
+ flex_layout->SetCrossAxisAlignment(LayoutAlignment::kEnd);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Finish the animation.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(20, 30), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 0, 10, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 10, 10, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(10, 20, 10, 10), child(2)->bounds());
+
+ flex_layout->SetCrossAxisAlignment(LayoutAlignment::kStretch);
+ EXPECT_TRUE(layout()->is_animating());
+
+ // Finish the animation.
+ animation_api()->IncrementTime(base::TimeDelta::FromMilliseconds(1000));
+ EXPECT_FALSE(layout()->is_animating());
+ EXPECT_EQ(gfx::Size(20, 30), view()->size());
+ EXPECT_TRUE(child(0)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 0, 20, 10), child(0)->bounds());
+ EXPECT_TRUE(child(1)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 10, 20, 10), child(1)->bounds());
+ EXPECT_TRUE(child(2)->GetVisible());
+ EXPECT_EQ(gfx::Rect(0, 20, 20, 10), child(2)->bounds());
+}
+
// Flex Rule Tests -------------------------------------------------------------
class AnimatingLayoutManagerFlexRuleTest : public AnimatingLayoutManagerTest {
@@ -3699,7 +4112,8 @@ class AnimatingLayoutManagerInFlexLayoutTest
protected:
void SetUp() override {
AnimatingLayoutManagerRootViewTest::SetUp();
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
root_layout_ =
root_view()->SetLayoutManager(std::make_unique<FlexLayout>());
root_layout_->SetOrientation(LayoutOrientation::kHorizontal)
@@ -4137,7 +4551,8 @@ class AnimatingLayoutManagerRealtimeTest
protected:
void InitRootView(SizeBounds bounds = SizeBounds()) {
root_view()->SetLayoutManager(std::make_unique<ImmediateLayoutManager>(
- layout()->should_animate_bounds(), std::move(bounds)));
+ layout()->bounds_animation_mode(), layout()->orientation(),
+ std::move(bounds)));
layout()->EnableAnimationForTesting();
}
@@ -4149,7 +4564,8 @@ class AnimatingLayoutManagerRealtimeTest
TEST_F(AnimatingLayoutManagerRealtimeTest, TestAnimateSlide) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetAnimationDuration(kMinimumAnimationTime);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -4187,7 +4603,8 @@ TEST_F(AnimatingLayoutManagerRealtimeTest, TestAnimateSlide) {
TEST_F(AnimatingLayoutManagerRealtimeTest, TestAnimateStretch) {
constexpr gfx::Insets kChildMargins(5);
- layout()->SetShouldAnimateBounds(false);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kUseHostBounds);
layout()->SetAnimationDuration(kMinimumAnimationTime);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -4227,7 +4644,8 @@ TEST_F(AnimatingLayoutManagerRealtimeTest, TestAnimateStretch) {
TEST_F(AnimatingLayoutManagerRealtimeTest, TestConstrainedSpaceStopsAnimation) {
constexpr gfx::Insets kChildMargins(5);
constexpr SizeBounds kSizeBounds(45, base::nullopt);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetAnimationDuration(kMinimumAnimationTime);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -4271,7 +4689,8 @@ TEST_F(AnimatingLayoutManagerRealtimeTest, TestConstrainedSpaceStopsAnimation) {
TEST_F(AnimatingLayoutManagerRealtimeTest, TestConstrainedSpaceDoesNotRestart) {
constexpr gfx::Insets kChildMargins(5);
constexpr SizeBounds kSizeBounds(45, base::nullopt);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetAnimationDuration(kMinimumAnimationTime);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -4319,7 +4738,8 @@ TEST_F(AnimatingLayoutManagerRealtimeTest,
TestConstrainedSpaceRestartedAnimationSucceeds) {
constexpr gfx::Insets kChildMargins(5);
constexpr SizeBounds kSizeBounds(45, base::nullopt);
- layout()->SetShouldAnimateBounds(true);
+ layout()->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
layout()->SetAnimationDuration(kMinimumAnimationTime);
auto* const flex_layout =
layout()->SetTargetLayoutManager(std::make_unique<FlexLayout>());
@@ -4392,7 +4812,7 @@ class AnimatingLayoutManagerSequenceTest : public ViewsTestBase {
parent_view_ptr_ = std::make_unique<View>();
parent_view_ptr_->SetLayoutManager(
- std::make_unique<ImmediateLayoutManager>(true));
+ std::make_unique<ImmediateLayoutManager>());
parent_view_ = parent_view_ptr_.get();
layout_view_ptr_ = std::make_unique<View>();
@@ -4416,7 +4836,8 @@ class AnimatingLayoutManagerSequenceTest : public ViewsTestBase {
flex_layout->SetCollapseMargins(true);
flex_layout->SetCrossAxisAlignment(LayoutAlignment::kStart);
flex_layout->SetDefault(kMarginsKey, gfx::Insets(5));
- layout_manager_->SetShouldAnimateBounds(true);
+ layout_manager_->SetBoundsAnimationMode(
+ AnimatingLayoutManager::BoundsAnimationMode::kAnimateBothAxes);
}
void AddViewToParent() {
diff --git a/chromium/ui/views/layout/box_layout.cc b/chromium/ui/views/layout/box_layout.cc
index 255ca1c2f97..6dec3c98612 100644
--- a/chromium/ui/views/layout/box_layout.cc
+++ b/chromium/ui/views/layout/box_layout.cc
@@ -16,14 +16,14 @@ namespace {
// Returns the maximum of the given insets along the given |axis|.
// NOTE: |axis| is different from |orientation_|; it specifies the actual
// desired axis.
-enum Axis { HORIZONTAL_AXIS, VERTICAL_AXIS };
+enum class Axis { kHorizontal, kVertical };
gfx::Insets MaxAxisInsets(Axis axis,
const gfx::Insets& leading1,
const gfx::Insets& leading2,
const gfx::Insets& trailing1,
const gfx::Insets& trailing2) {
- if (axis == HORIZONTAL_AXIS) {
+ if (axis == Axis::kHorizontal) {
return gfx::Insets(0, std::max(leading1.left(), leading2.left()), 0,
std::max(trailing1.right(), trailing2.right()));
}
@@ -201,11 +201,11 @@ void BoxLayout::Layout(View* host) {
gfx::Rect min_child_area(child_area);
gfx::Insets child_margins;
if (collapse_margins_spacing_) {
- child_margins =
- MaxAxisInsets(orientation_ == Orientation::kVertical ? HORIZONTAL_AXIS
- : VERTICAL_AXIS,
- child.margins(), inside_border_insets_, child.margins(),
- inside_border_insets_);
+ child_margins = MaxAxisInsets(orientation_ == Orientation::kVertical
+ ? Axis::kHorizontal
+ : Axis::kVertical,
+ child.margins(), inside_border_insets_,
+ child.margins(), inside_border_insets_);
} else {
child_margins = child.margins();
}
@@ -307,7 +307,7 @@ gfx::Size BoxLayout::GetPreferredSize(const View* host) const {
gfx::Size child_size = child.view()->GetPreferredSize();
gfx::Insets child_margins;
if (collapse_margins_spacing_) {
- child_margins = MaxAxisInsets(HORIZONTAL_AXIS, child.margins(),
+ child_margins = MaxAxisInsets(Axis::kHorizontal, child.margins(),
inside_border_insets_, child.margins(),
inside_border_insets_);
} else {
@@ -474,14 +474,14 @@ gfx::Insets BoxLayout::MainAxisOuterMargin() const {
const ViewWrapper first(this, FirstVisibleView());
const ViewWrapper last(this, LastVisibleView());
return MaxAxisInsets(orientation_ == Orientation::kHorizontal
- ? HORIZONTAL_AXIS
- : VERTICAL_AXIS,
+ ? Axis::kHorizontal
+ : Axis::kVertical,
inside_border_insets_, first.margins(),
inside_border_insets_, last.margins());
}
return MaxAxisInsets(orientation_ == Orientation::kHorizontal
- ? HORIZONTAL_AXIS
- : VERTICAL_AXIS,
+ ? Axis::kHorizontal
+ : Axis::kVertical,
inside_border_insets_, gfx::Insets(),
inside_border_insets_, gfx::Insets());
}
@@ -569,9 +569,9 @@ gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host,
size.height());
gfx::Insets child_margins;
if (collapse_margins_spacing_)
- child_margins =
- MaxAxisInsets(VERTICAL_AXIS, child.margins(), inside_border_insets_,
- child.margins(), inside_border_insets_);
+ child_margins = MaxAxisInsets(Axis::kVertical, child.margins(),
+ inside_border_insets_, child.margins(),
+ inside_border_insets_);
else
child_margins = child.margins();
diff --git a/chromium/ui/views/layout/flex_layout.cc b/chromium/ui/views/layout/flex_layout.cc
index dee1daf861f..18131f8c984 100644
--- a/chromium/ui/views/layout/flex_layout.cc
+++ b/chromium/ui/views/layout/flex_layout.cc
@@ -13,7 +13,8 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/logging.h"
+#include "base/check_op.h"
+#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
#include "ui/events/event_target.h"
diff --git a/chromium/ui/views/layout/grid_layout.cc b/chromium/ui/views/layout/grid_layout.cc
index aa028983659..58004fb9ee0 100644
--- a/chromium/ui/views/layout/grid_layout.cc
+++ b/chromium/ui/views/layout/grid_layout.cc
@@ -158,7 +158,7 @@ class Column : public LayoutElement {
Column(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
- GridLayout::SizeType size_type,
+ GridLayout::ColumnSize size_type,
int fixed_width,
int min_width,
bool is_padding)
@@ -194,7 +194,7 @@ class Column : public LayoutElement {
const GridLayout::Alignment h_align_;
const GridLayout::Alignment v_align_;
- const GridLayout::SizeType size_type_;
+ const GridLayout::ColumnSize size_type_;
int same_size_column_;
const int fixed_width_;
const int min_width_;
@@ -216,7 +216,7 @@ class Column : public LayoutElement {
};
void Column::ResetSize() {
- if (size_type_ == GridLayout::FIXED) {
+ if (size_type_ == GridLayout::ColumnSize::kFixed) {
SetSize(fixed_width_);
} else {
SetSize(min_width_);
@@ -249,7 +249,7 @@ void Column::UnifyLinkedColumnSizes(int size_limit) {
}
void Column::AdjustSize(int size) {
- if (size_type_ == GridLayout::USE_PREF)
+ if (size_type_ == GridLayout::ColumnSize::kUsePreferred)
LayoutElement::AdjustSize(size);
}
@@ -382,13 +382,13 @@ ColumnSet::~ColumnSet() = default;
void ColumnSet::AddPaddingColumn(float resize_percent, int width) {
AddColumn(GridLayout::FILL, GridLayout::FILL, resize_percent,
- GridLayout::FIXED, width, width, true);
+ GridLayout::ColumnSize::kFixed, width, width, true);
}
void ColumnSet::AddColumn(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
- GridLayout::SizeType size_type,
+ GridLayout::ColumnSize size_type,
int fixed_width,
int min_width) {
AddColumn(h_align, v_align, resize_percent, size_type, fixed_width, min_width,
@@ -411,7 +411,7 @@ void ColumnSet::LinkColumnSizes(const std::vector<int>& columns) {
void ColumnSet::AddColumn(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
- GridLayout::SizeType size_type,
+ GridLayout::ColumnSize size_type,
int fixed_width,
int min_width,
bool is_padding) {
@@ -533,7 +533,8 @@ void ColumnSet::DistributeRemainingWidth(ViewState* view_state) {
if (columns_[i]->IsResizable()) {
total_resize += columns_[i]->ResizePercent();
resizable_columns++;
- } else if (columns_[i]->size_type_ == GridLayout::USE_PREF) {
+ } else if (columns_[i]->size_type_ ==
+ GridLayout::ColumnSize::kUsePreferred) {
pref_size_columns++;
}
}
@@ -559,7 +560,7 @@ void ColumnSet::DistributeRemainingWidth(ViewState* view_state) {
// that use the preferred size.
int to_distribute = width / pref_size_columns;
for (int i = start_col; i < max_col; ++i) {
- if (columns_[i]->size_type_ == GridLayout::USE_PREF) {
+ if (columns_[i]->size_type_ == GridLayout::ColumnSize::kUsePreferred) {
width -= to_distribute;
if (width < to_distribute)
to_distribute += width;
@@ -740,7 +741,8 @@ void ColumnSet::ResizeUsingMin(int total_delta) {
bool ColumnSet::CanUseMinimum(const ViewState& view_state) const {
const auto resizable = [](const auto& col) {
- return col->ResizePercent() > 0 && col->size_type_ != GridLayout::FIXED;
+ return col->ResizePercent() > 0 &&
+ col->size_type_ != GridLayout::ColumnSize::kFixed;
};
return std::all_of(
columns_.cbegin() + view_state.start_col,
diff --git a/chromium/ui/views/layout/grid_layout.h b/chromium/ui/views/layout/grid_layout.h
index 118431d13d5..5e64d647a62 100644
--- a/chromium/ui/views/layout/grid_layout.h
+++ b/chromium/ui/views/layout/grid_layout.h
@@ -26,12 +26,14 @@
// FILL, // Views starting in this column are vertically
// // resized.
// 1.0, // This column has a resize weight of 1.
-// USE_PREF, // Use the preferred size of the view.
-// 0, // Ignored for USE_PREF.
+// ColumnSize::kUsePreferred, // Use the preferred size of
+// the
+// // view.
+// 0, // Ignored for kUsePref.
// 0); // A minimum width of 0.
// columns->AddPaddingColumn(kFixedSize, // The padding column is not resizable.
// 10); // And has a width of 10 pixels.
-// columns->AddColumn(FILL, FILL, kFixedSize, USE_PREF, 0, 0);
+// columns->AddColumn(FILL, FILL, kFixedSize, ColumnSize::kUsePreferred, 0, 0);
// Now add the views:
// // First start a row.
// layout->StartRow(kFixedSize, // This row isn't vertically resizable.
@@ -104,12 +106,12 @@ class VIEWS_EXPORT GridLayout : public LayoutManager {
};
// An enumeration of the possible ways the size of a column may be obtained.
- enum SizeType {
+ enum class ColumnSize {
// The column size is fixed.
- FIXED,
+ kFixed,
// The preferred size of the view is used to determine the column size.
- USE_PREF
+ kUsePreferred
};
GridLayout();
@@ -129,7 +131,7 @@ class VIEWS_EXPORT GridLayout : public LayoutManager {
// Returns the column set for the specified id, or NULL if one doesn't exist.
ColumnSet* GetColumnSet(int id);
- // Adds a padding row. Padding rows typically don't have any views, and
+ // Adds a padding row. Padding rows typically don't have any views,
// but are used to provide vertical white space between views.
// Size specifies the height of the row.
void AddPaddingRow(float vertical_resize, int size);
@@ -330,7 +332,7 @@ class VIEWS_EXPORT ColumnSet {
void AddColumn(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
- GridLayout::SizeType size_type,
+ GridLayout::ColumnSize size_type,
int fixed_width,
int min_width);
@@ -358,7 +360,7 @@ class VIEWS_EXPORT ColumnSet {
void AddColumn(GridLayout::Alignment h_align,
GridLayout::Alignment v_align,
float resize_percent,
- GridLayout::SizeType size_type,
+ GridLayout::ColumnSize size_type,
int fixed_width,
int min_width,
bool is_padding);
diff --git a/chromium/ui/views/layout/grid_layout_unittest.cc b/chromium/ui/views/layout/grid_layout_unittest.cc
index d93dc7ec67d..76a94e7d169 100644
--- a/chromium/ui/views/layout/grid_layout_unittest.cc
+++ b/chromium/ui/views/layout/grid_layout_unittest.cc
@@ -126,7 +126,8 @@ class GridLayoutAlignmentTest : public testing::Test {
auto v1 = std::make_unique<View>();
v1->SetPreferredSize(gfx::Size(10, 20));
ColumnSet* c1 = layout_->AddColumnSet(0);
- c1->AddColumn(alignment, alignment, 1, GridLayout::USE_PREF, 0, 0);
+ c1->AddColumn(alignment, alignment, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout_->StartRow(1, 0);
auto* v1_ptr = layout_->AddView(std::move(v1));
gfx::Size pref = layout_->GetPreferredSize(host_.get());
@@ -173,9 +174,9 @@ TEST_F(GridLayoutTest, TwoColumns) {
auto v2 = CreateSizedView(gfx::Size(20, 20));
ColumnSet* c1 = layout()->AddColumnSet(0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1_ptr = layout()->AddView(std::move(v1));
auto* v2_ptr = layout()->AddView(std::move(v2));
@@ -194,12 +195,12 @@ TEST_F(GridLayoutTest, LinkedSizes) {
ColumnSet* c1 = layout()->AddColumnSet(0);
// Fill widths.
- c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, GridLayout::USE_PREF,
- 0, 0);
- c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, GridLayout::USE_PREF,
- 0, 0);
- c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0, GridLayout::USE_PREF,
- 0, 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(10, 20)));
@@ -257,9 +258,9 @@ TEST_F(GridLayoutTest, LinkedSizes) {
TEST_F(GridLayoutTest, ColSpan1) {
ColumnSet* c1 = layout()->AddColumnSet(0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(100, 20)), 2, 1);
layout()->StartRow(0, 0);
@@ -277,9 +278,9 @@ TEST_F(GridLayoutTest, ColSpan1) {
TEST_F(GridLayoutTest, ColSpan2) {
ColumnSet* c1 = layout()->AddColumnSet(0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(100, 20)), 2, 1);
layout()->StartRow(0, 0);
@@ -298,9 +299,9 @@ TEST_F(GridLayoutTest, ColSpan2) {
TEST_F(GridLayoutTest, ColSpan3) {
ColumnSet* c1 = layout()->AddColumnSet(0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(100, 20)), 2, 1);
layout()->StartRow(0, 0);
@@ -321,9 +322,9 @@ TEST_F(GridLayoutTest, ColSpan4) {
ColumnSet* set = layout()->AddColumnSet(0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(10, 10)));
@@ -346,12 +347,12 @@ TEST_F(GridLayoutTest, ColSpan4) {
TEST_F(GridLayoutTest, ColSpanStartSecondColumn) {
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, GridLayout::USE_PREF, 0,
- 0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, GridLayout::USE_PREF, 0,
- 0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, GridLayout::FIXED, 10,
- 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::ColumnSize::kFixed, 10, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(10, 10)));
@@ -369,9 +370,9 @@ TEST_F(GridLayoutTest, ColSpanStartSecondColumn) {
TEST_F(GridLayoutTest, SameSizeColumns) {
ColumnSet* c1 = layout()->AddColumnSet(0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->LinkColumnSizes({0, 1});
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(50, 20)));
@@ -388,10 +389,10 @@ TEST_F(GridLayoutTest, SameSizeColumns) {
TEST_F(GridLayoutTest, HorizontalResizeTest1) {
ColumnSet* c1 = layout()->AddColumnSet(0);
- c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1, GridLayout::USE_PREF,
- 0, 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(50, 20)));
auto* v2 = layout()->AddView(CreateSizedView(gfx::Size(10, 10)));
@@ -404,10 +405,10 @@ TEST_F(GridLayoutTest, HorizontalResizeTest1) {
TEST_F(GridLayoutTest, HorizontalResizeTest2) {
ColumnSet* c1 = layout()->AddColumnSet(0);
- c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1, GridLayout::USE_PREF,
- 0, 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 1,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(50, 20)));
auto* v2 = layout()->AddView(CreateSizedView(gfx::Size(10, 10)));
@@ -422,12 +423,12 @@ TEST_F(GridLayoutTest, HorizontalResizeTest2) {
// resizable column.
TEST_F(GridLayoutTest, HorizontalResizeTest3) {
ColumnSet* c1 = layout()->AddColumnSet(0);
- c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1, GridLayout::USE_PREF,
- 0, 0);
- c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1, GridLayout::USE_PREF,
- 0, 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
c1->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(10, 10)));
auto* v2 = layout()->AddView(CreateSizedView(gfx::Size(10, 10)));
@@ -442,8 +443,8 @@ TEST_F(GridLayoutTest, HorizontalResizeTest3) {
TEST_F(GridLayoutTest, TestVerticalResize1) {
ColumnSet* c1 = layout()->AddColumnSet(0);
- c1->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0,
- 0);
+ c1->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(1, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(50, 20)));
layout()->StartRow(0, 0);
@@ -462,7 +463,7 @@ TEST_F(GridLayoutTest, Border) {
host()->SetBorder(CreateEmptyBorder(1, 2, 3, 4));
ColumnSet* c1 = layout()->AddColumnSet(0);
c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* v1 = layout()->AddView(CreateSizedView(gfx::Size(10, 20)));
@@ -486,8 +487,8 @@ TEST_F(GridLayoutTest, FixedSize) {
constexpr int kPrefHeight = 20;
for (size_t i = 0; i < kColumnCount; ++i) {
- set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::FIXED,
- kTitleWidth, kTitleWidth);
+ set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
+ GridLayout::ColumnSize::kFixed, kTitleWidth, kTitleWidth);
}
for (size_t row = 0; row < kRowCount; ++row) {
@@ -515,8 +516,8 @@ TEST_F(GridLayoutTest, FixedSize) {
TEST_F(GridLayoutTest, RowSpanWithPaddingRow) {
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::FIXED,
- 10, 10);
+ set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
+ GridLayout::ColumnSize::kFixed, 10, 10);
layout()->StartRow(0, 0);
layout()->AddView(CreateSizedView(gfx::Size(10, 10)), 1, 2);
@@ -527,9 +528,9 @@ TEST_F(GridLayoutTest, RowSpan) {
ColumnSet* set = layout()->AddColumnSet(0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
layout()->AddView(CreateSizedView(gfx::Size(20, 10)));
@@ -549,9 +550,9 @@ TEST_F(GridLayoutTest, RowSpan2) {
ColumnSet* set = layout()->AddColumnSet(0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
layout()->AddView(CreateSizedView(gfx::Size(20, 20)));
@@ -574,9 +575,9 @@ TEST_F(GridLayoutTest, FixedViewWidth) {
ColumnSet* set = layout()->AddColumnSet(0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* view =
@@ -596,9 +597,9 @@ TEST_F(GridLayoutTest, FixedViewHeight) {
ColumnSet* set = layout()->AddColumnSet(0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto* view =
@@ -619,10 +620,10 @@ TEST_F(GridLayoutTest, FixedViewHeight) {
TEST_F(GridLayoutTest, ColumnSpanResizing) {
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 2, GridLayout::USE_PREF,
- 0, 0);
- set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 4, GridLayout::USE_PREF,
- 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 2,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 4,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
// span_view spans two columns and is twice as big the views added below.
@@ -653,16 +654,16 @@ TEST_F(GridLayoutTest, ColumnSpanResizing) {
// preferred sizes.
TEST_F(GridLayoutTest, ColumnResizingOnGetPreferredSize) {
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, GridLayout::USE_PREF,
- 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
set = layout()->AddColumnSet(1);
- set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, GridLayout::USE_PREF,
- 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
set = layout()->AddColumnSet(2);
- set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, GridLayout::USE_PREF,
- 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
// Make a row containing a flexible view that trades width for height.
layout()->StartRow(0, 0);
@@ -689,8 +690,8 @@ TEST_F(GridLayoutTest, ColumnResizingOnGetPreferredSize) {
TEST_F(GridLayoutTest, MinimumPreferredSize) {
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, GridLayout::USE_PREF, 0,
- 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
layout()->AddView(CreateSizedView(gfx::Size(10, 20)));
@@ -707,8 +708,8 @@ TEST_F(GridLayoutTest, MinimumPreferredSize) {
// structures it uses to calculate Layout, so will give bogus results.
TEST_F(GridLayoutTest, LayoutOnAddDeath) {
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, GridLayout::USE_PREF, 0,
- 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
auto view = std::make_unique<LayoutOnAddView>();
EXPECT_DCHECK_DEATH(layout()->AddView(std::move(view)));
@@ -725,8 +726,8 @@ TEST_F(GridLayoutTest, ColumnMinForcesPreferredWidth) {
// Column's min width is greater than views preferred/min width. This should
// force the preferred width to the min width of the column.
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
- 100);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5,
+ GridLayout::ColumnSize::kUsePreferred, 0, 100);
layout()->StartRow(0, 0);
layout()->AddView(CreateSizedView(gfx::Size(20, 10)));
@@ -739,10 +740,10 @@ TEST_F(GridLayoutTest, HonorsColumnMin) {
// Verifies that a column with a min width is never shrunk smaller than the
// minw width.
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
- 100);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
- 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5,
+ GridLayout::ColumnSize::kUsePreferred, 0, 100);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
View* view1 = layout()->AddView(
CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(125, 10)));
@@ -772,10 +773,10 @@ TEST_F(GridLayoutTest, TwoViewsOneSizeSmallerThanMinimum) {
// Two columns, equally resizable with two views. Only the first view is
// resizable.
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
- 0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
- 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
View* view1 = layout()->AddView(
CreateViewWithMinAndPref(gfx::Size(20, 10), gfx::Size(100, 10)));
@@ -793,10 +794,10 @@ TEST_F(GridLayoutTest, TwoViewsBothSmallerThanMinimumDifferentResizeWeights) {
// Two columns, equally resizable with two views. Only the first view is
// resizable.
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 8, GridLayout::USE_PREF, 0,
- 0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 2, GridLayout::USE_PREF, 0,
- 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 8,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 2,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
View* view1 = layout()->AddView(
CreateViewWithMinAndPref(gfx::Size(91, 10), gfx::Size(100, 10)));
@@ -842,10 +843,10 @@ TEST_F(GridLayoutTest, TwoViewsBothSmallerThanMinimumDifferentResizeWeights) {
TEST_F(GridLayoutTest, TwoViewsOneColumnUsePrefOtherFixed) {
layout()->set_honors_min_width(true);
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 8, GridLayout::USE_PREF, 0,
- 0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 2, GridLayout::FIXED, 100,
- 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 8,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 2,
+ GridLayout::ColumnSize::kFixed, 100, 0);
layout()->StartRow(0, 0);
View* view1 = layout()->AddView(
CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(100, 10)));
@@ -867,10 +868,10 @@ TEST_F(GridLayoutTest, TwoViewsOneColumnUsePrefOtherFixed) {
TEST_F(GridLayoutTest, TwoViewsBothColumnsResizableOneViewFixedWidthMin) {
layout()->set_honors_min_width(true);
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0,
- 0);
- set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0,
- 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
+ set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
View* view1 = layout()->AddView(
CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(100, 10)));
@@ -910,8 +911,8 @@ class SettablePreferredHeightView : public View {
TEST_F(GridLayoutTest, HeightForWidthCalledWhenNotGivenPreferredWidth) {
ColumnSet* set = layout()->AddColumnSet(0);
- set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, GridLayout::USE_PREF,
- 0, 0);
+ set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout()->StartRow(0, 0);
const int pref_height = 100;
auto view = std::make_unique<SettablePreferredHeightView>(pref_height);
diff --git a/chromium/ui/views/layout/layout_manager_base.cc b/chromium/ui/views/layout/layout_manager_base.cc
index 13622be1d09..5bc27081215 100644
--- a/chromium/ui/views/layout/layout_manager_base.cc
+++ b/chromium/ui/views/layout/layout_manager_base.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/auto_reset.h"
-#include "base/logging.h"
+#include "base/check_op.h"
#include "ui/views/view.h"
namespace views {
diff --git a/chromium/ui/views/layout/layout_manager_base.h b/chromium/ui/views/layout/layout_manager_base.h
index cec6a2e6366..8812cb5a17b 100644
--- a/chromium/ui/views/layout/layout_manager_base.h
+++ b/chromium/ui/views/layout/layout_manager_base.h
@@ -11,6 +11,7 @@
#include <utility>
#include <vector>
+#include "base/macros.h"
#include "base/optional.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
diff --git a/chromium/ui/views/layout/proposed_layout.cc b/chromium/ui/views/layout/proposed_layout.cc
index 6a2373cfcc5..6f8f502647e 100644
--- a/chromium/ui/views/layout/proposed_layout.cc
+++ b/chromium/ui/views/layout/proposed_layout.cc
@@ -5,6 +5,7 @@
#include "ui/views/layout/proposed_layout.h"
#include <map>
+#include <sstream>
#include <string>
#include "ui/gfx/animation/tween.h"
diff --git a/chromium/ui/views/metadata/metadata_cache.cc b/chromium/ui/views/metadata/metadata_cache.cc
index 5a2f10ab864..d37abba27de 100644
--- a/chromium/ui/views/metadata/metadata_cache.cc
+++ b/chromium/ui/views/metadata/metadata_cache.cc
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/no_destructor.h"
#include "ui/views/metadata/metadata_types.h"
diff --git a/chromium/ui/views/metadata/metadata_types.cc b/chromium/ui/views/metadata/metadata_types.cc
index 0dc3a0185fe..ef38d3a8ae3 100644
--- a/chromium/ui/views/metadata/metadata_types.cc
+++ b/chromium/ui/views/metadata/metadata_types.cc
@@ -6,6 +6,8 @@
#include <utility>
+#include "base/check_op.h"
+#include "base/notreached.h"
#include "base/strings/string_util.h"
#include "ui/views/metadata/type_conversion.h"
diff --git a/chromium/ui/views/metadata/type_conversion.cc b/chromium/ui/views/metadata/type_conversion.cc
index 1ca8954dd20..d953161eff3 100644
--- a/chromium/ui/views/metadata/type_conversion.cc
+++ b/chromium/ui/views/metadata/type_conversion.cc
@@ -312,6 +312,8 @@ DEFINE_ENUM_CONVERTERS(ui::TextInputType,
base::ASCIIToUTF16("TEXT_INPUT_TYPE_CONTENT_EDITABLE")},
{ui::TextInputType::TEXT_INPUT_TYPE_DATE_TIME_FIELD,
base::ASCIIToUTF16("TEXT_INPUT_TYPE_DATE_TIME_FIELD")},
+ {ui::TextInputType::TEXT_INPUT_TYPE_NULL,
+ base::ASCIIToUTF16("TEXT_INPUT_TYPE_NULL")},
{ui::TextInputType::TEXT_INPUT_TYPE_MAX,
base::ASCIIToUTF16("TEXT_INPUT_TYPE_MAX")})
diff --git a/chromium/ui/views/native_cursor_aura.cc b/chromium/ui/views/native_cursor_aura.cc
index 2ab60bc5cd1..bd346bba61b 100644
--- a/chromium/ui/views/native_cursor_aura.cc
+++ b/chromium/ui/views/native_cursor_aura.cc
@@ -5,7 +5,7 @@
#include "ui/views/native_cursor.h"
#include "ui/base/cursor/cursor.h"
-#include "ui/base/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
namespace views {
diff --git a/chromium/ui/views/painter.cc b/chromium/ui/views/painter.cc
index 561a6653756..b0ca7de96fc 100644
--- a/chromium/ui/views/painter.cc
+++ b/chromium/ui/views/painter.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/compositor/layer_owner.h"
diff --git a/chromium/ui/views/style/typography.cc b/chromium/ui/views/style/typography.cc
index 0fc46aa6489..e269daff59a 100644
--- a/chromium/ui/views/style/typography.cc
+++ b/chromium/ui/views/style/typography.cc
@@ -4,7 +4,7 @@
#include "ui/views/style/typography.h"
-#include "base/logging.h"
+#include "base/check_op.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/style/typography_provider.h"
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
index 92a729807de..a2da9320fb2 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -7,8 +7,9 @@
#include <set>
#include <utility>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/metrics/histogram_macros.h"
+#include "base/notreached.h"
#include "base/time/time.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
@@ -520,6 +521,13 @@ void TouchSelectionControllerImpl::HideHandles(bool quick) {
cursor_handle_->SetWidgetVisible(false, quick);
}
+void TouchSelectionControllerImpl::ShowQuickMenuImmediatelyForTesting() {
+ if (quick_menu_timer_.IsRunning()) {
+ quick_menu_timer_.Stop();
+ QuickMenuTimerFired();
+ }
+}
+
void TouchSelectionControllerImpl::SetDraggingHandle(
EditingHandleView* handle) {
dragging_handle_ = handle;
@@ -636,7 +644,7 @@ void TouchSelectionControllerImpl::OnEvent(const ui::Event& event) {
// from touch as this can clear an active selection generated by the pen.
if ((event.flags() & (ui::EF_IS_SYNTHESIZED | ui::EF_FROM_TOUCH)) ||
event.AsMouseEvent()->pointer_details().pointer_type ==
- ui::EventPointerType::POINTER_TYPE_PEN) {
+ ui::EventPointerType::kPen) {
return;
}
}
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.h b/chromium/ui/views/touchui/touch_selection_controller_impl.h
index e748afcdbdd..af43216b179 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.h
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.h
@@ -21,10 +21,6 @@
namespace views {
class WidgetDelegateView;
-namespace test {
-class WidgetTestInteractive;
-}
-
// Touch specific implementation of TouchEditingControllerDeprecated.
// Responsible for displaying selection handles and menu elements relevant in a
// touch interface.
@@ -45,9 +41,10 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
bool IsHandleDragInProgress() override;
void HideHandles(bool quick) override;
+ void ShowQuickMenuImmediatelyForTesting();
+
private:
friend class TouchSelectionControllerImplTest;
- friend class test::WidgetTestInteractive;
void SetDraggingHandle(EditingHandleView* handle);
diff --git a/chromium/ui/views/touchui/touch_selection_menu_views.cc b/chromium/ui/views/touchui/touch_selection_menu_views.cc
index ca02bef42d8..8b014f1386d 100644
--- a/chromium/ui/views/touchui/touch_selection_menu_views.cc
+++ b/chromium/ui/views/touchui/touch_selection_menu_views.cc
@@ -10,6 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/pointer/touch_editing_controller.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/canvas.h"
@@ -25,7 +26,15 @@
namespace views {
namespace {
-constexpr int kMenuCommands[] = {IDS_APP_CUT, IDS_APP_COPY, IDS_APP_PASTE};
+struct MenuCommand {
+ int command_id;
+ int message_id;
+} kMenuCommands[] = {
+ {ui::TouchEditable::kCut, IDS_APP_CUT},
+ {ui::TouchEditable::kCopy, IDS_APP_COPY},
+ {ui::TouchEditable::kPaste, IDS_APP_PASTE},
+};
+
constexpr int kSpacingBetweenButtons = 2;
constexpr int kEllipsesButtonTag = -1;
@@ -95,8 +104,8 @@ bool TouchSelectionMenuViews::IsMenuAvailable(
const ui::TouchSelectionMenuClient* client) {
DCHECK(client);
- const auto is_enabled = [client](int command) {
- return client->IsCommandIdEnabled(command);
+ const auto is_enabled = [client](MenuCommand command) {
+ return client->IsCommandIdEnabled(command.command_id);
};
return std::any_of(std::cbegin(kMenuCommands), std::cend(kMenuCommands),
is_enabled);
@@ -113,12 +122,12 @@ void TouchSelectionMenuViews::CloseMenu() {
TouchSelectionMenuViews::~TouchSelectionMenuViews() = default;
void TouchSelectionMenuViews::CreateButtons() {
- for (int command_id : kMenuCommands) {
- if (!client_->IsCommandIdEnabled(command_id))
+ for (const auto& command : kMenuCommands) {
+ if (!client_->IsCommandIdEnabled(command.command_id))
continue;
- Button* button =
- CreateButton(l10n_util::GetStringUTF16(command_id), command_id);
+ Button* button = CreateButton(l10n_util::GetStringUTF16(command.message_id),
+ command.command_id);
AddChildView(button);
}
diff --git a/chromium/ui/views/vector_icons/linux_shutdown.icon b/chromium/ui/views/vector_icons/linux_shutdown.icon
deleted file mode 100644
index 7feb96f2e3f..00000000000
--- a/chromium/ui/views/vector_icons/linux_shutdown.icon
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 14.24f, 5.76f,
-R_ARC_TO, 1, 1, 0, 1, 1, 1.41f, -1.41f,
-R_ARC_TO, 8, 8, 0, 1, 1, -11.31f, 0,
-R_ARC_TO, 1, 1, 0, 1, 1, 1.41f, 1.41f,
-R_ARC_TO, 6, 6, 0, 1, 0, 8.49f, 0,
-CLOSE,
-MOVE_TO, 9, 3,
-R_ARC_TO, 1, 1, 0, 0, 1, 2, 0,
-R_V_LINE_TO, 8,
-R_ARC_TO, 1, 1, 0, 1, 1, -2, 0,
-CLOSE
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index 4cb98c1ee34..00b654c8e4f 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -8,11 +8,12 @@
#include <memory>
#include <utility>
+#include "base/check_op.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
#include "base/feature_list.h"
-#include "base/logging.h"
#include "base/macros.h"
+#include "base/notreached.h"
#include "base/scoped_observer.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
@@ -49,6 +50,7 @@
#include "ui/views/border.h"
#include "ui/views/buildflags.h"
#include "ui/views/context_menu_controller.h"
+#include "ui/views/controls/scroll_view.h"
#include "ui/views/drag_controller.h"
#include "ui/views/layout/layout_manager.h"
#include "ui/views/metadata/metadata_impl_macros.h"
@@ -1517,11 +1519,6 @@ void View::ShowContextMenu(const gfx::Point& p,
context_menu_controller_->ShowContextMenuForView(this, p, source_type);
}
-// static
-bool View::ShouldShowContextMenuOnMousePress() {
- return kContextMenuOnMousePress;
-}
-
gfx::Point View::GetKeyboardContextMenuLocation() {
gfx::Rect vis_bounds = GetVisibleBounds();
gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2,
@@ -1800,7 +1797,8 @@ void View::UpdateChildLayerVisibility(bool ancestor_visible) {
layer()->SetVisible(layers_visible);
for (ui::Layer* layer_beneath : layers_beneath_)
layer_beneath->SetVisible(layers_visible);
- } else {
+ }
+ {
internal::ScopedChildrenLock lock(this);
for (auto* child : children_)
child->UpdateChildLayerVisibility(layers_visible);
@@ -1870,6 +1868,11 @@ void View::OnPaintLayer(const ui::PaintContext& context) {
PaintFromPaintRoot(context);
}
+void View::OnLayerTransformed(const gfx::Transform& old_transform,
+ ui::PropertyChangeReason reason) {
+ NotifyAccessibilityEvent(ax::mojom::Event::kLocationChanged, false);
+}
+
void View::OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) {
snap_layer_to_pixel_boundary_ =
@@ -1977,7 +1980,14 @@ void View::OnBlur() {}
void View::Focus() {
OnFocus();
- ScrollViewToVisible();
+
+ // If this is the contents root of a |ScrollView|, focus should bring the
+ // |ScrollView| to visible rather than resetting its content scroll position.
+ ScrollView* scroll_view = ScrollView::GetScrollViewForContents(this);
+ if (scroll_view)
+ scroll_view->ScrollViewToVisible();
+ else
+ ScrollViewToVisible();
for (ViewObserver& observer : observers_)
observer.OnViewFocused(this);
diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h
index b1dfe17e2b2..1f4f1eb78fe 100644
--- a/chromium/ui/views/view.h
+++ b/chromium/ui/views/view.h
@@ -1222,10 +1222,6 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
virtual void ShowContextMenu(const gfx::Point& p,
ui::MenuSourceType source_type);
- // On some platforms, we show context menu on mouse press instead of release.
- // This method returns true for those platforms.
- static bool ShouldShowContextMenuOnMousePress();
-
// Returns the location, in screen coordinates, to show the context menu at
// when the context menu is shown from the keyboard. This implementation
// returns the middle of the visible region of this view.
@@ -1503,6 +1499,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Overridden from ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override;
+ void OnLayerTransformed(const gfx::Transform& old_transform,
+ ui::PropertyChangeReason reason) override;
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override;
diff --git a/chromium/ui/views/view_model.cc b/chromium/ui/views/view_model.cc
index 4768545b6f2..e3ba79f8cc6 100644
--- a/chromium/ui/views/view_model.cc
+++ b/chromium/ui/views/view_model.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "ui/views/view.h"
namespace views {
diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc
index 16294076ab4..dd69ffe1c53 100644
--- a/chromium/ui/views/view_unittest.cc
+++ b/chromium/ui/views/view_unittest.cc
@@ -379,6 +379,22 @@ TEST_F(ViewTest, OnBoundsChanged) {
EXPECT_EQ(v.bounds(), new_rect);
}
+TEST_F(ViewTest, TransformFiresA11yEvent) {
+ TestView v;
+ v.SetPaintToLayer();
+
+ gfx::Rect bounds(0, 0, 200, 200);
+ v.last_a11y_event_ = ax::mojom::Event::kNone;
+ v.SetBoundsRect(bounds);
+ EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kLocationChanged);
+
+ gfx::Transform transform;
+ transform.Translate(gfx::Vector2dF(10, 10));
+ v.last_a11y_event_ = ax::mojom::Event::kNone;
+ v.layer()->SetTransform(transform);
+ EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kLocationChanged);
+}
+
////////////////////////////////////////////////////////////////////////////////
// OnStateChanged
////////////////////////////////////////////////////////////////////////////////
@@ -2012,21 +2028,21 @@ TEST_F(ViewTest, TextfieldCutCopyPaste) {
//
normal->SelectAll(false);
- normal->ExecuteCommand(IDS_APP_CUT, 0);
+ normal->ExecuteCommand(Textfield::kCut, 0);
base::string16 result;
clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
EXPECT_EQ(kNormalText, result);
normal->SetText(kNormalText); // Let's revert to the original content.
read_only->SelectAll(false);
- read_only->ExecuteCommand(IDS_APP_CUT, 0);
+ read_only->ExecuteCommand(Textfield::kCut, 0);
result.clear();
clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
// Cut should have failed, so the clipboard content should not have changed.
EXPECT_EQ(kNormalText, result);
password->SelectAll(false);
- password->ExecuteCommand(IDS_APP_CUT, 0);
+ password->ExecuteCommand(Textfield::kCut, 0);
result.clear();
clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
// Cut should have failed, so the clipboard content should not have changed.
@@ -2038,19 +2054,19 @@ TEST_F(ViewTest, TextfieldCutCopyPaste) {
// Start with |read_only| to observe a change in clipboard text.
read_only->SelectAll(false);
- read_only->ExecuteCommand(IDS_APP_COPY, 0);
+ read_only->ExecuteCommand(Textfield::kCopy, 0);
result.clear();
clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
EXPECT_EQ(kReadOnlyText, result);
normal->SelectAll(false);
- normal->ExecuteCommand(IDS_APP_COPY, 0);
+ normal->ExecuteCommand(Textfield::kCopy, 0);
result.clear();
clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
EXPECT_EQ(kNormalText, result);
password->SelectAll(false);
- password->ExecuteCommand(IDS_APP_COPY, 0);
+ password->ExecuteCommand(Textfield::kCopy, 0);
result.clear();
clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
// Text cannot be copied from an obscured field; the clipboard won't change.
@@ -2062,18 +2078,18 @@ TEST_F(ViewTest, TextfieldCutCopyPaste) {
// Attempting to paste kNormalText in a read-only text-field should fail.
read_only->SelectAll(false);
- read_only->ExecuteCommand(IDS_APP_PASTE, 0);
+ read_only->ExecuteCommand(Textfield::kPaste, 0);
EXPECT_EQ(kReadOnlyText, read_only->GetText());
password->SelectAll(false);
- password->ExecuteCommand(IDS_APP_PASTE, 0);
+ password->ExecuteCommand(Textfield::kPaste, 0);
EXPECT_EQ(kNormalText, password->GetText());
// Copy from |read_only| to observe a change in the normal textfield text.
read_only->SelectAll(false);
- read_only->ExecuteCommand(IDS_APP_COPY, 0);
+ read_only->ExecuteCommand(Textfield::kCopy, 0);
normal->SelectAll(false);
- normal->ExecuteCommand(IDS_APP_PASTE, 0);
+ normal->ExecuteCommand(Textfield::kPaste, 0);
EXPECT_EQ(kReadOnlyText, normal->GetText());
widget->CloseNow();
}
@@ -2224,16 +2240,16 @@ TEST_F(ViewTest, HandleAccelerator) {
EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]);
// Add a child view associated with a child widget.
- TestView* child_view = new TestView();
- child_view->Reset();
- child_view->AddAccelerator(return_accelerator);
- EXPECT_EQ(child_view->accelerator_count_map_[return_accelerator], 0);
Widget* child_widget = new Widget;
Widget::InitParams child_params =
CreateParams(Widget::InitParams::TYPE_CONTROL);
child_params.parent = widget->GetNativeView();
child_widget->Init(std::move(child_params));
- child_widget->SetContentsView(child_view);
+ TestView* child_view =
+ child_widget->SetContentsView(std::make_unique<TestView>());
+ child_view->Reset();
+ child_view->AddAccelerator(return_accelerator);
+ EXPECT_EQ(child_view->accelerator_count_map_[return_accelerator], 0);
FocusManager* child_focus_manager = child_widget->GetFocusManager();
ASSERT_TRUE(child_focus_manager);
@@ -2526,10 +2542,11 @@ TEST_F(ViewTest, NativeViewHierarchyChanged) {
child_params.parent = toplevel1->GetNativeView();
child->Init(std::move(child_params));
- ToplevelWidgetObserverView* observer_view = new ToplevelWidgetObserverView();
- EXPECT_EQ(nullptr, observer_view->toplevel());
+ auto owning_observer_view = std::make_unique<ToplevelWidgetObserverView>();
+ EXPECT_EQ(nullptr, owning_observer_view->toplevel());
- child->SetContentsView(observer_view);
+ ToplevelWidgetObserverView* observer_view =
+ child->SetContentsView(std::move(owning_observer_view));
EXPECT_EQ(toplevel1.get(), observer_view->toplevel());
Widget::ReparentNativeView(child->GetNativeView(),
@@ -2760,15 +2777,12 @@ TEST_F(ViewTest, TransformVisibleBound) {
widget->Init(std::move(params));
widget->GetRootView()->SetBoundsRect(viewport_bounds);
- View* viewport = new View;
- widget->SetContentsView(viewport);
- View* contents = new View;
- viewport->AddChildView(contents);
+ View* viewport = widget->SetContentsView(std::make_unique<View>());
+ View* contents = viewport->AddChildView(std::make_unique<View>());
viewport->SetBoundsRect(viewport_bounds);
contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200));
- View* child = new View;
- contents->AddChildView(child);
+ View* child = contents->AddChildView(std::make_unique<View>());
child->SetBoundsRect(gfx::Rect(10, 90, 50, 50));
EXPECT_EQ(gfx::Rect(0, 0, 50, 10), child->GetVisibleBounds());
@@ -2817,17 +2831,15 @@ TEST_F(ViewTest, OnVisibleBoundsChanged) {
widget->Init(std::move(params));
widget->GetRootView()->SetBoundsRect(viewport_bounds);
- View* viewport = new View;
- widget->SetContentsView(viewport);
- View* contents = new View;
- viewport->AddChildView(contents);
+ View* viewport = widget->SetContentsView(std::make_unique<View>());
+ View* contents = viewport->AddChildView(std::make_unique<View>());
viewport->SetBoundsRect(viewport_bounds);
contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200));
// Create a view that cares about visible bounds notifications, and position
// it just outside the visible bounds of the viewport.
- VisibleBoundsView* child = new VisibleBoundsView;
- contents->AddChildView(child);
+ VisibleBoundsView* child =
+ contents->AddChildView(std::make_unique<VisibleBoundsView>());
child->SetBoundsRect(gfx::Rect(10, 110, 50, 50));
// The child bound should be fully clipped.
@@ -2919,14 +2931,13 @@ TEST_F(ViewTest, AddAndRemoveSchedulePaints) {
widget->Init(std::move(params));
widget->GetRootView()->SetBoundsRect(viewport_bounds);
- TestView* parent_view = new TestView;
- widget->SetContentsView(parent_view);
+ TestView* parent_view = widget->SetContentsView(std::make_unique<TestView>());
parent_view->SetBoundsRect(viewport_bounds);
parent_view->scheduled_paint_rects_.clear();
- View* child_view = new View;
- child_view->SetBoundsRect(gfx::Rect(0, 0, 20, 20));
- parent_view->AddChildView(child_view);
+ auto owning_child_view = std::make_unique<View>();
+ owning_child_view->SetBoundsRect(gfx::Rect(0, 0, 20, 20));
+ View* child_view = parent_view->AddChildView(std::move(owning_child_view));
ASSERT_EQ(1U, parent_view->scheduled_paint_rects_.size());
EXPECT_EQ(child_view->bounds(), parent_view->scheduled_paint_rects_.front());
@@ -3982,8 +3993,7 @@ TEST_F(ViewLayerTest, LayerToggling) {
// Because we lazily create textures the calls to DrawTree are necessary to
// ensure we trigger creation of textures.
ui::Layer* root_layer = widget()->GetLayer();
- View* content_view = new View;
- widget()->SetContentsView(content_view);
+ View* content_view = widget()->SetContentsView(std::make_unique<View>());
// Create v1, give it a bounds and verify everything is set up correctly.
View* v1 = new View;
@@ -4038,8 +4048,7 @@ TEST_F(ViewLayerTest, LayerToggling) {
// Verifies turning on a layer wires up children correctly.
TEST_F(ViewLayerTest, NestedLayerToggling) {
- View* content_view = new View;
- widget()->SetContentsView(content_view);
+ View* content_view = widget()->SetContentsView(std::make_unique<View>());
// Create v1, give it a bounds and verify everything is set up correctly.
View* v1 = content_view->AddChildView(std::make_unique<View>());
@@ -4063,8 +4072,7 @@ TEST_F(ViewLayerTest, NestedLayerToggling) {
}
TEST_F(ViewLayerTest, LayerAnimator) {
- View* content_view = new View;
- widget()->SetContentsView(content_view);
+ View* content_view = widget()->SetContentsView(std::make_unique<View>());
View* v1 = content_view->AddChildView(std::make_unique<View>());
v1->SetPaintToLayer();
@@ -4083,8 +4091,7 @@ TEST_F(ViewLayerTest, LayerAnimator) {
// Verifies the bounds of a layer are updated if the bounds of ancestor that
// doesn't have a layer change.
TEST_F(ViewLayerTest, BoundsChangeWithLayer) {
- View* content_view = new View;
- widget()->SetContentsView(content_view);
+ View* content_view = widget()->SetContentsView(std::make_unique<View>());
View* v1 = content_view->AddChildView(std::make_unique<View>());
v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
@@ -4120,8 +4127,7 @@ TEST_F(ViewLayerTest, BoundsChangeWithLayer) {
// Make sure layers are positioned correctly in RTL.
TEST_F(ViewLayerTest, BoundInRTL) {
base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
- View* view = new View;
- widget()->SetContentsView(view);
+ View* view = widget()->SetContentsView(std::make_unique<View>());
int content_width = view->width();
@@ -4171,8 +4177,7 @@ TEST_F(ViewLayerTest, BoundInRTL) {
// Make sure that resizing a parent in RTL correctly repositions its children.
TEST_F(ViewLayerTest, ResizeParentInRTL) {
base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
- View* view = new View;
- widget()->SetContentsView(view);
+ View* view = widget()->SetContentsView(std::make_unique<View>());
int content_width = view->width();
@@ -4218,11 +4223,10 @@ TEST_F(ViewLayerTest, ResizeParentInRTL) {
// Makes sure a transform persists after toggling the visibility.
TEST_F(ViewLayerTest, ToggleVisibilityWithTransform) {
- View* view = new View;
+ View* view = widget()->SetContentsView(std::make_unique<View>());
gfx::Transform transform;
transform.Scale(2.0, 2.0);
view->SetTransform(transform);
- widget()->SetContentsView(view);
EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
view->SetVisible(false);
@@ -4234,11 +4238,10 @@ TEST_F(ViewLayerTest, ToggleVisibilityWithTransform) {
// Verifies a transform persists after removing/adding a view with a transform.
TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) {
- View* view = new View;
+ View* view = widget()->SetContentsView(std::make_unique<View>());
gfx::Transform transform;
transform.Scale(2.0, 2.0);
view->SetTransform(transform);
- widget()->SetContentsView(view);
EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
ASSERT_TRUE(view->layer() != nullptr);
EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0));
@@ -4254,8 +4257,7 @@ TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) {
// Makes sure that layer visibility is correct after toggling View visibility.
TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) {
- View* content_view = new View;
- widget()->SetContentsView(content_view);
+ View* content_view = widget()->SetContentsView(std::make_unique<View>());
// The view isn't attached to a widget or a parent view yet. But it should
// still have a layer, but the layer should not be attached to the root
@@ -4289,8 +4291,7 @@ TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) {
// Tests that the layers in the subtree are orphaned after a View is removed
// from the parent.
TEST_F(ViewLayerTest, OrphanLayerAfterViewRemove) {
- View* content_view = new View;
- widget()->SetContentsView(content_view);
+ View* content_view = widget()->SetContentsView(std::make_unique<View>());
View* v1 = new View;
content_view->AddChildView(v1);
@@ -4335,8 +4336,8 @@ class PaintTrackingView : public View {
// Makes sure child views with layers aren't painted when paint starts at an
// ancestor.
TEST_F(ViewLayerTest, DontPaintChildrenWithLayers) {
- PaintTrackingView* content_view = new PaintTrackingView;
- widget()->SetContentsView(content_view);
+ PaintTrackingView* content_view =
+ widget()->SetContentsView(std::make_unique<PaintTrackingView>());
content_view->SetPaintToLayer();
GetRootLayer()->GetCompositor()->ScheduleDraw();
ui::DrawWaiterForTest::WaitForCompositingEnded(
@@ -4403,9 +4404,8 @@ TEST_F(ViewLayerTest, NoParentPaintWhenSwitchingPaintToLayerFromTrueToTrue) {
// Tests that the visibility of child layers are updated correctly when a View's
// visibility changes.
TEST_F(ViewLayerTest, VisibilityChildLayers) {
- View* v1 = new View;
+ View* v1 = widget()->SetContentsView(std::make_unique<View>());
v1->SetPaintToLayer();
- widget()->SetContentsView(v1);
View* v2 = v1->AddChildView(std::make_unique<View>());
@@ -4448,9 +4448,8 @@ TEST_F(ViewLayerTest, VisibilityChildLayers) {
// reparents views etc. Unrelated changes can appear to break this test. So
// marking this as FLAKY.
TEST_F(ViewLayerTest, DISABLED_ViewLayerTreesInSync) {
- View* content = new View;
+ View* content = widget()->SetContentsView(std::make_unique<View>());
content->SetPaintToLayer();
- widget()->SetContentsView(content);
widget()->Show();
ConstructTree(content, 5);
@@ -4469,8 +4468,7 @@ TEST_F(ViewLayerTest, DISABLED_ViewLayerTreesInSync) {
// Verifies when views are reordered the layer is also reordered. The widget is
// providing the parent layer.
TEST_F(ViewLayerTest, ReorderUnderWidget) {
- View* content = new View;
- widget()->SetContentsView(content);
+ View* content = widget()->SetContentsView(std::make_unique<View>());
View* c1 = content->AddChildView(std::make_unique<View>());
c1->SetPaintToLayer();
View* c2 = content->AddChildView(std::make_unique<View>());
@@ -4490,8 +4488,7 @@ TEST_F(ViewLayerTest, ReorderUnderWidget) {
// Verifies that the layer of a view can be acquired properly.
TEST_F(ViewLayerTest, AcquireLayer) {
- View* content = new View;
- widget()->SetContentsView(content);
+ View* content = widget()->SetContentsView(std::make_unique<View>());
std::unique_ptr<View> c1(new View);
c1->SetPaintToLayer();
EXPECT_TRUE(c1->layer());
@@ -4537,8 +4534,7 @@ TEST_F(ViewLayerTest, RecreateLayerZOrder) {
// Verify the z-order of the layers as a result of calling RecreateLayer when
// the widget is the parent with the layer.
TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) {
- View* v = new View();
- widget()->SetContentsView(v);
+ View* v = widget()->SetContentsView(std::make_unique<View>());
View* v1 = v->AddChildView(std::make_unique<View>());
v1->SetPaintToLayer();
@@ -4606,12 +4602,10 @@ std::string ToString(const gfx::Vector2dF& vector) {
TEST_F(ViewLayerTest, SnapLayerToPixel) {
viz::ParentLocalSurfaceIdAllocator allocator;
allocator.GenerateId();
- View* v1 = new View;
+ View* v1 = widget()->SetContentsView(std::make_unique<View>());
View* v11 = v1->AddChildView(std::make_unique<View>());
- widget()->SetContentsView(v1);
-
const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
GetRootLayer()->GetCompositor()->SetScaleAndSize(
1.25f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
@@ -4699,8 +4693,7 @@ TEST_F(ViewLayerTest, LayerBeneathAtFractionalScale) {
GetRootLayer()->GetCompositor()->SetScaleAndSize(
device_scale, size, allocator.GetCurrentLocalSurfaceIdAllocation());
- View* view = new View;
- widget()->SetContentsView(view);
+ View* view = widget()->SetContentsView(std::make_unique<View>());
ui::Layer layer;
view->AddLayerBeneathView(&layer);
@@ -4828,6 +4821,31 @@ TEST_F(ViewLayerTest, LayerBeneathTransformed) {
EXPECT_TRUE(layer.transform().IsIdentity());
}
+TEST_F(ViewLayerTest, UpdateChildLayerVisibilityEvenIfLayer) {
+ View root;
+ root.SetPaintToLayer();
+
+ View* view = root.AddChildView(std::make_unique<View>());
+ view->SetPaintToLayer();
+ View* child = view->AddChildView(std::make_unique<View>());
+ child->SetPaintToLayer();
+ EXPECT_TRUE(child->layer()->GetAnimator()->GetTargetVisibility());
+
+ // Makes the view invisible then destroy the layer.
+ view->SetVisible(false);
+ view->DestroyLayer();
+ EXPECT_FALSE(child->layer()->GetAnimator()->GetTargetVisibility());
+
+ view->SetVisible(true);
+ view->SetPaintToLayer();
+ EXPECT_TRUE(child->layer()->GetAnimator()->GetTargetVisibility());
+
+ // Destroys the layer then make the view invisible.
+ view->DestroyLayer();
+ view->SetVisible(false);
+ EXPECT_FALSE(child->layer()->GetAnimator()->GetTargetVisibility());
+}
+
TEST_F(ViewLayerTest, LayerBeneathStackedCorrectly) {
using ui::test::ChildLayerNamesAsString;
@@ -4962,12 +4980,10 @@ class ViewLayerPixelCanvasTest : public ViewLayerTest {
TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
viz::ParentLocalSurfaceIdAllocator allocator;
allocator.GenerateId();
- View* v1 = new View;
+ View* v1 = widget()->SetContentsView(std::make_unique<View>());
View* v2 = v1->AddChildView(std::make_unique<View>());
PaintLayerView* v3 = v2->AddChildView(std::make_unique<PaintLayerView>());
- widget()->SetContentsView(v1);
-
const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
GetRootLayer()->GetCompositor()->SetScaleAndSize(
1.6f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
@@ -5034,8 +5050,7 @@ TEST_F(ViewLayerPixelCanvasTest, LayerBeneathOnPixelCanvas) {
GetRootLayer()->GetCompositor()->SetScaleAndSize(
device_scale, size, allocator.GetCurrentLocalSurfaceIdAllocation());
- View* view = new View;
- widget()->SetContentsView(view);
+ View* view = widget()->SetContentsView(std::make_unique<View>());
ui::Layer layer;
view->AddLayerBeneathView(&layer);
diff --git a/chromium/ui/views/views_features.cc b/chromium/ui/views/views_features.cc
index 210657bae32..13bf1c9f0e2 100644
--- a/chromium/ui/views/views_features.cc
+++ b/chromium/ui/views/views_features.cc
@@ -28,5 +28,11 @@ const base::Feature kEnablePlatformHighContrastInkDrop{
const base::Feature kEnableViewPaintOptimization{
"EnableViewPaintOptimization", base::FEATURE_DISABLED_BY_DEFAULT};
+// Change views::Textfield to take focus on a completed tap, rather than
+// immediately on tap down. This only affects touch input. See
+// https://crbug.com/1069634.
+const base::Feature kTextfieldFocusOnTapUp{"TextfieldFocusOnTapUp",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace features
} // namespace views
diff --git a/chromium/ui/views/views_features.h b/chromium/ui/views/views_features.h
index 1daff6da79c..e4340bbb13a 100644
--- a/chromium/ui/views/views_features.h
+++ b/chromium/ui/views/views_features.h
@@ -17,6 +17,7 @@ namespace features {
VIEWS_EXPORT extern const base::Feature kEnableMDRoundedCornersOnDialogs;
VIEWS_EXPORT extern const base::Feature kEnablePlatformHighContrastInkDrop;
VIEWS_EXPORT extern const base::Feature kEnableViewPaintOptimization;
+VIEWS_EXPORT extern const base::Feature kTextfieldFocusOnTapUp;
} // namespace features
} // namespace views
diff --git a/chromium/ui/views/widget/any_widget_observer_unittest.cc b/chromium/ui/views/widget/any_widget_observer_unittest.cc
index 4a1bf692f57..344fd0943bd 100644
--- a/chromium/ui/views/widget/any_widget_observer_unittest.cc
+++ b/chromium/ui/views/widget/any_widget_observer_unittest.cc
@@ -83,7 +83,7 @@ class NamedWidgetShownWaiterTest : public views::test::WidgetTest {
Widget* widget = new Widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.native_widget = views::test::CreatePlatformNativeWidgetImpl(
- params, widget, views::test::kStubCapture, nullptr);
+ widget, views::test::kStubCapture, nullptr);
params.name = name;
widget->Init(std::move(params));
return widget;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index 707f2b4aa33..3ee330f3598 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -18,23 +18,23 @@
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_x11.h"
#include "ui/base/layout.h"
-#include "ui/base/mojom/cursor_type.mojom-shared.h"
#include "ui/base/x/selection_utils.h"
#include "ui/base/x/x11_drag_context.h"
#include "ui/base/x/x11_util.h"
+#include "ui/base/x/x11_whole_screen_move_loop.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/x/x11.h"
+#include "ui/platform_window/x11/x11_topmost_window_finder.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
-#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
-#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
#include "ui/views/widget/widget.h"
using aura::client::DragDropDelegate;
@@ -171,8 +171,11 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
// Windows has a specific method, DoDragDrop(), which performs the entire
// drag. We have to emulate this, so we spin off a nested runloop which will
// track all cursor movement and reroute events to a specific handler.
- move_loop_->RunMoveLoop(source_window, cursor_manager_->GetInitializedCursor(
- ui::mojom::CursorType::kGrabbing));
+ move_loop_->RunMoveLoop(
+ !source_window->HasCapture(),
+ source_window->GetHost()->last_cursor().platform(),
+ cursor_manager_->GetInitializedCursor(ui::mojom::CursorType::kGrabbing)
+ .platform());
if (alive) {
auto resulting_operation = negotiated_operation();
@@ -248,9 +251,9 @@ void DesktopDragDropClientAuraX11::OnMoveLoopEnded() {
XDragDropClient::HandleMoveLoopEnded();
}
-std::unique_ptr<X11MoveLoop> DesktopDragDropClientAuraX11::CreateMoveLoop(
+std::unique_ptr<ui::X11MoveLoop> DesktopDragDropClientAuraX11::CreateMoveLoop(
X11MoveLoopDelegate* delegate) {
- return base::WrapUnique(new X11WholeScreenMoveLoop(this));
+ return base::WrapUnique(new ui::X11WholeScreenMoveLoop(this));
}
void DesktopDragDropClientAuraX11::DragTranslate(
@@ -280,7 +283,7 @@ void DesktopDragDropClientAuraX11::DragTranslate(
DCHECK(target_current_context());
*data = std::make_unique<OSExchangeData>(
- std::make_unique<ui::OSExchangeDataProviderAuraX11>(
+ std::make_unique<ui::OSExchangeDataProviderX11>(
xwindow(), target_current_context()->fetched_targets()));
gfx::Point location = root_location;
aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
@@ -326,7 +329,7 @@ void DesktopDragDropClientAuraX11::NotifyDragLeave() {
std::unique_ptr<ui::XTopmostWindowFinder>
DesktopDragDropClientAuraX11::CreateWindowFinder() {
- return std::make_unique<X11TopmostWindowFinder>();
+ return std::make_unique<ui::X11TopmostWindowFinder>();
}
int DesktopDragDropClientAuraX11::UpdateDrag(const gfx::Point& screen_point) {
@@ -362,7 +365,8 @@ void DesktopDragDropClientAuraX11::UpdateCursor(
cursor_type = ui::mojom::CursorType::kDndLink;
break;
}
- move_loop_->UpdateCursor(cursor_manager_->GetInitializedCursor(cursor_type));
+ move_loop_->UpdateCursor(
+ cursor_manager_->GetInitializedCursor(cursor_type).platform());
}
void DesktopDragDropClientAuraX11::OnBeginForeignDrag(XID window) {
@@ -394,7 +398,7 @@ int DesktopDragDropClientAuraX11::PerformDrop() {
aura::client::GetDragDropDelegate(target_window_);
if (delegate) {
auto data(std::make_unique<ui::OSExchangeData>(
- std::make_unique<ui::OSExchangeDataProviderAuraX11>(
+ std::make_unique<ui::OSExchangeDataProviderX11>(
xwindow(), target_current_context()->fetched_targets())));
ui::DropTargetEvent drop_event(
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
index 7ae53151b9e..a06220b1864 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h
@@ -16,6 +16,7 @@
#include "ui/base/cursor/cursor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/x/x11_drag_drop_client.h"
+#include "ui/base/x/x11_move_loop_delegate.h"
#include "ui/events/event_constants.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/events/x/x11_window_event_manager.h"
@@ -23,7 +24,6 @@
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/x/x11.h"
#include "ui/views/views_export.h"
-#include "ui/views/widget/desktop_aura/x11_move_loop_delegate.h"
namespace aura {
namespace client {
@@ -40,12 +40,12 @@ namespace ui {
class DropTargetEvent;
class OSExchangeData;
class XTopmostWindowFinder;
+class X11MoveLoop;
} // namespace ui
namespace views {
class DesktopNativeCursorManager;
class Widget;
-class X11MoveLoop;
// Implements drag and drop on X11 for aura. On one side, this class takes raw
// X11 events forwarded from DesktopWindowTreeHostLinux, while on the other, it
@@ -56,7 +56,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
public aura::client::DragDropClient,
public ui::XEventDispatcher,
public aura::WindowObserver,
- public X11MoveLoopDelegate {
+ public ui::X11MoveLoopDelegate {
public:
DesktopDragDropClientAuraX11(
aura::Window* root_window,
@@ -85,7 +85,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
// aura::WindowObserver:
void OnWindowDestroyed(aura::Window* window) override;
- // X11MoveLoopDelegate:
+ // ui::X11MoveLoopDelegate:
void OnMouseMovement(const gfx::Point& screen_point,
int flags,
base::TimeTicks event_time) override;
@@ -97,7 +97,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
Widget* drag_widget() { return drag_widget_.get(); }
// Creates a move loop. Virtual for testing.
- virtual std::unique_ptr<X11MoveLoop> CreateMoveLoop(
+ virtual std::unique_ptr<ui::X11MoveLoop> CreateMoveLoop(
X11MoveLoopDelegate* delegate);
private:
@@ -125,8 +125,8 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11
void EndMoveLoop() override;
// A nested run loop that notifies this object of events through the
- // X11MoveLoopDelegate interface.
- std::unique_ptr<X11MoveLoop> move_loop_;
+ // ui::X11MoveLoopDelegate interface.
+ std::unique_ptr<ui::X11MoveLoop> move_loop_;
aura::Window* root_window_;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
index b188e6c9a40..68c1ba2c47d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
@@ -20,6 +20,7 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/x/x11_move_loop.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/x/x11.h"
@@ -29,7 +30,6 @@
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/desktop_aura/x11_move_loop.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -66,24 +66,26 @@ class ClientMessageEventCollector {
DISALLOW_COPY_AND_ASSIGN(ClientMessageEventCollector);
};
-// An implementation of X11MoveLoop where RunMoveLoop() always starts the move
-// loop.
-class TestMoveLoop : public X11MoveLoop {
+// An implementation of ui::X11MoveLoop where RunMoveLoop() always starts the
+// move loop.
+class TestMoveLoop : public ui::X11MoveLoop {
public:
- explicit TestMoveLoop(X11MoveLoopDelegate* delegate);
+ explicit TestMoveLoop(ui::X11MoveLoopDelegate* delegate);
~TestMoveLoop() override;
// Returns true if the move loop is running.
bool IsRunning() const;
- // X11MoveLoop:
- bool RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor) override;
- void UpdateCursor(gfx::NativeCursor cursor) override;
+ // ui::X11MoveLoop:
+ bool RunMoveLoop(bool can_grab_pointer,
+ ::Cursor old_cursor,
+ ::Cursor new_cursor) override;
+ void UpdateCursor(::Cursor cursor) override;
void EndMoveLoop() override;
private:
// Not owned.
- X11MoveLoopDelegate* delegate_;
+ ui::X11MoveLoopDelegate* delegate_;
// Ends the move loop.
base::OnceClosure quit_closure_;
@@ -109,8 +111,8 @@ class SimpleTestDragDropClient : public DesktopDragDropClientAuraX11 {
private:
// DesktopDragDropClientAuraX11:
- std::unique_ptr<X11MoveLoop> CreateMoveLoop(
- X11MoveLoopDelegate* delegate) override;
+ std::unique_ptr<ui::X11MoveLoop> CreateMoveLoop(
+ ui::X11MoveLoopDelegate* delegate) override;
XID FindWindowFor(const gfx::Point& screen_point) override;
// The XID of the window which is simulated to be the topmost window.
@@ -207,7 +209,7 @@ void ClientMessageEventCollector::RecordEvent(
///////////////////////////////////////////////////////////////////////////////
// TestMoveLoop
-TestMoveLoop::TestMoveLoop(X11MoveLoopDelegate* delegate)
+TestMoveLoop::TestMoveLoop(ui::X11MoveLoopDelegate* delegate)
: delegate_(delegate) {}
TestMoveLoop::~TestMoveLoop() = default;
@@ -216,7 +218,9 @@ bool TestMoveLoop::IsRunning() const {
return is_running_;
}
-bool TestMoveLoop::RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor) {
+bool TestMoveLoop::RunMoveLoop(bool can_grab_pointer,
+ ::Cursor old_cursor,
+ ::Cursor new_cursor) {
is_running_ = true;
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
@@ -224,7 +228,7 @@ bool TestMoveLoop::RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor) {
return true;
}
-void TestMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {}
+void TestMoveLoop::UpdateCursor(::Cursor cursor) {}
void TestMoveLoop::EndMoveLoop() {
if (is_running_) {
@@ -255,8 +259,8 @@ bool SimpleTestDragDropClient::IsMoveLoopRunning() {
return loop_->IsRunning();
}
-std::unique_ptr<X11MoveLoop> SimpleTestDragDropClient::CreateMoveLoop(
- X11MoveLoopDelegate* delegate) {
+std::unique_ptr<ui::X11MoveLoop> SimpleTestDragDropClient::CreateMoveLoop(
+ ui::X11MoveLoopDelegate* delegate) {
loop_ = new TestMoveLoop(delegate);
return base::WrapUnique(loop_);
}
@@ -306,7 +310,7 @@ void TestDragDropClient::OnStatus(XID target_window,
event.data.l[2] = 0;
event.data.l[3] = 0;
event.data.l[4] = accepted_action;
- OnXdndStatus(event);
+ HandleXdndEvent(event);
}
void TestDragDropClient::OnFinished(XID target_window,
@@ -321,7 +325,7 @@ void TestDragDropClient::OnFinished(XID target_window,
event.data.l[2] = performed_action;
event.data.l[3] = 0;
event.data.l[4] = 0;
- OnXdndFinished(event);
+ HandleXdndEvent(event);
}
void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid) {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
index 1ed740d20ce..24a959b321d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
@@ -18,10 +18,10 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data_provider_aura.h"
-#include "ui/base/mojom/cursor_type.mojom-shared.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
@@ -239,6 +239,7 @@ void DesktopDragDropClientOzone::PerformDrop() {
drag_operation_ = drag_drop_delegate_->OnPerformDrop(
*event, std::move(os_exchange_data_));
DragDropSessionCompleted();
+ ResetDragDropTarget();
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
index 478b16bc606..ab7213a3889 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -6,10 +6,11 @@
#include <utility>
+#include "base/trace_event/trace_event.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/cursor/cursor_loader.h"
-#include "ui/base/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
namespace views {
@@ -59,6 +60,8 @@ void DesktopNativeCursorManager::SetCursor(
void DesktopNativeCursorManager::SetVisibility(
bool visible,
wm::NativeCursorManagerDelegate* delegate) {
+ TRACE_EVENT1("ui,input", "DesktopNativeCursorManager::SetVisibility",
+ "visible", visible);
delegate->CommitVisibility(visible);
if (visible) {
@@ -83,6 +86,7 @@ void DesktopNativeCursorManager::SetCursorSize(
void DesktopNativeCursorManager::SetMouseEventsEnabled(
bool enabled,
wm::NativeCursorManagerDelegate* delegate) {
+ TRACE_EVENT0("ui,input", "DesktopNativeCursorManager::SetMouseEventsEnabled");
delegate->CommitMouseEventsEnabled(enabled);
// TODO(erg): In the ash version, we set the last mouse location on Env. I'm
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
index fdb5d86b797..d926393dd7f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
@@ -10,7 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "ui/base/mojom/cursor_type.mojom-forward.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
#include "ui/views/views_export.h"
#include "ui/wm/core/native_cursor_manager.h"
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
index a28f778d4a5..71e7bbc378b 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
@@ -22,7 +22,7 @@
#include "ui/aura/test/window_occlusion_tracker_test_api.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
-#include "ui/base/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/display/screen.h"
#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
@@ -286,8 +286,8 @@ std::unique_ptr<Widget> CreateAndShowControlWidget(aura::Window* parent) {
Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.parent = parent;
- params.native_widget = CreatePlatformNativeWidgetImpl(params, widget.get(),
- kStubCapture, nullptr);
+ params.native_widget =
+ CreatePlatformNativeWidgetImpl(widget.get(), kStubCapture, nullptr);
widget->Init(std::move(params));
widget->Show();
return widget;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
index a8d86fd87fc..6f9d29fbcbb 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
@@ -2,13 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/views/widget/desktop_aura/desktop_screen_ozone.h"
+
#include "ui/aura/screen_ozone.h"
#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
namespace views {
+DesktopScreenOzone::DesktopScreenOzone() = default;
+
+DesktopScreenOzone::~DesktopScreenOzone() = default;
+
+gfx::NativeWindow DesktopScreenOzone::GetNativeWindowFromAcceleratedWidget(
+ gfx::AcceleratedWidget widget) const {
+ if (!widget)
+ return nullptr;
+ return views::DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ widget);
+}
+
display::Screen* CreateDesktopScreen() {
- return new aura::ScreenOzone();
+ return new DesktopScreenOzone();
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.h
new file mode 100644
index 00000000000..e45fe4c9df0
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_OZONE_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_OZONE_H_
+
+#include "ui/aura/screen_ozone.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class VIEWS_EXPORT DesktopScreenOzone : public aura::ScreenOzone {
+ public:
+ DesktopScreenOzone();
+ DesktopScreenOzone(const DesktopScreenOzone&) = delete;
+ DesktopScreenOzone& operator=(const DesktopScreenOzone&) = delete;
+ ~DesktopScreenOzone() override;
+
+ private:
+ // ui::aura::ScreenOzone:
+ gfx::NativeWindow GetNativeWindowFromAcceleratedWidget(
+ gfx::AcceleratedWidget widget) const override;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_OZONE_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
index 70553b153c4..963e7053e7a 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc
@@ -4,40 +4,26 @@
#include "ui/views/widget/desktop_aura/desktop_screen_win.h"
-#include "base/logging.h"
#include "ui/aura/window.h"
-#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
-#include "ui/display/display.h"
#include "ui/views/widget/desktop_aura/desktop_screen.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
namespace views {
-////////////////////////////////////////////////////////////////////////////////
-// DesktopScreenWin, public:
-
DesktopScreenWin::DesktopScreenWin() = default;
DesktopScreenWin::~DesktopScreenWin() = default;
-////////////////////////////////////////////////////////////////////////////////
-// DesktopScreenWin, display::win::ScreenWin implementation:
-
-display::Display DesktopScreenWin::GetDisplayMatching(
- const gfx::Rect& match_rect) const {
- return GetDisplayNearestPoint(match_rect.CenterPoint());
-}
-
-HWND DesktopScreenWin::GetHWNDFromNativeView(gfx::NativeView window) const {
+HWND DesktopScreenWin::GetHWNDFromNativeWindow(gfx::NativeWindow window) const {
aura::WindowTreeHost* host = window->GetHost();
return host ? host->GetAcceleratedWidget() : nullptr;
}
gfx::NativeWindow DesktopScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
- return (::IsWindow(hwnd))
+ return ::IsWindow(hwnd)
? DesktopWindowTreeHostWin::GetContentWindowForHWND(hwnd)
- : nullptr;
+ : gfx::kNullNativeWindow;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
index e17fe7611d7..97442c424d8 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h
@@ -5,7 +5,6 @@
#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_WIN_H_
#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_SCREEN_WIN_H_
-#include "base/macros.h"
#include "ui/display/win/screen_win.h"
#include "ui/views/views_export.h"
@@ -14,16 +13,14 @@ namespace views {
class VIEWS_EXPORT DesktopScreenWin : public display::win::ScreenWin {
public:
DesktopScreenWin();
+ DesktopScreenWin(const DesktopScreenWin&) = delete;
+ DesktopScreenWin& operator=(const DesktopScreenWin&) = delete;
~DesktopScreenWin() override;
private:
- // Overridden from display::win::ScreenWin:
- display::Display GetDisplayMatching(
- const gfx::Rect& match_rect) const override;
- HWND GetHWNDFromNativeView(gfx::NativeView window) const override;
+ // display::win::ScreenWin:
+ HWND GetHWNDFromNativeWindow(gfx::NativeWindow window) const override;
gfx::NativeWindow GetNativeWindowFromHWND(HWND hwnd) const override;
-
- DISALLOW_COPY_AND_ASSIGN(DesktopScreenWin);
};
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index 0ffdc450043..4f4a5d1c395 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -21,9 +21,9 @@
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/switches.h"
+#include "ui/platform_window/x11/x11_topmost_window_finder.h"
#include "ui/views/widget/desktop_aura/desktop_screen.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
-#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
namespace views {
@@ -60,8 +60,29 @@ bool DesktopScreenX11::IsWindowUnderCursor(gfx::NativeWindow window) {
gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint(
const gfx::Point& point) {
- return X11TopmostWindowFinder().FindLocalProcessWindowAt(
- gfx::ConvertPointToPixel(GetXDisplayScaleFactor(), point), {});
+ auto accelerated_widget =
+ ui::X11TopmostWindowFinder().FindLocalProcessWindowAt(
+ gfx::ConvertPointToPixel(GetXDisplayScaleFactor(), point), {});
+ return accelerated_widget
+ ? views::DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ static_cast<gfx::AcceleratedWidget>(accelerated_widget))
+ : nullptr;
+}
+
+gfx::NativeWindow DesktopScreenX11::GetLocalProcessWindowAtPoint(
+ const gfx::Point& point,
+ const std::set<gfx::NativeWindow>& ignore) {
+ std::set<gfx::AcceleratedWidget> ignore_widgets;
+ for (auto* const window : ignore)
+ ignore_widgets.emplace(window->GetHost()->GetAcceleratedWidget());
+ auto accelerated_widget =
+ ui::X11TopmostWindowFinder().FindLocalProcessWindowAt(
+ gfx::ConvertPointToPixel(GetXDisplayScaleFactor(), point),
+ ignore_widgets);
+ return accelerated_widget
+ ? views::DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ static_cast<gfx::AcceleratedWidget>(accelerated_widget))
+ : nullptr;
}
int DesktopScreenX11::GetNumDisplays() const {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
index dcf3e0f725e..b391f41caf2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -40,6 +40,9 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
gfx::Point GetCursorScreenPoint() override;
bool IsWindowUnderCursor(gfx::NativeWindow window) override;
gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override;
+ gfx::NativeWindow GetLocalProcessWindowAtPoint(
+ const gfx::Point& point,
+ const std::set<gfx::NativeWindow>& ignore) override;
int GetNumDisplays() const override;
const std::vector<display::Display>& GetAllDisplays() const override;
display::Display GetDisplayNearestWindow(
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
index 91cfaf77bb3..4168fa1a51f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
@@ -29,17 +29,11 @@
#include "ui/accessibility/platform/atk_util_auralinux.h"
#endif
-DEFINE_UI_CLASS_PROPERTY_TYPE(views::DesktopWindowTreeHostLinux*)
-
namespace views {
std::list<gfx::AcceleratedWidget>* DesktopWindowTreeHostLinux::open_windows_ =
nullptr;
-DEFINE_UI_CLASS_PROPERTY_KEY(DesktopWindowTreeHostLinux*,
- kHostForRootWindow,
- nullptr)
-
namespace {
class SwapWithNewSizeObserverHelper : public ui::CompositorObserver {
@@ -82,30 +76,13 @@ DesktopWindowTreeHostLinux::DesktopWindowTreeHostLinux(
: DesktopWindowTreeHostPlatform(native_widget_delegate,
desktop_native_widget_aura) {}
-DesktopWindowTreeHostLinux::~DesktopWindowTreeHostLinux() {
- window()->ClearProperty(kHostForRootWindow);
-}
-
-// static
-aura::Window* DesktopWindowTreeHostLinux::GetContentWindowForWidget(
- gfx::AcceleratedWidget widget) {
- auto* host = DesktopWindowTreeHostLinux::GetHostForWidget(widget);
- return host ? host->GetContentWindow() : nullptr;
-}
-
-// static
-DesktopWindowTreeHostLinux* DesktopWindowTreeHostLinux::GetHostForWidget(
- gfx::AcceleratedWidget widget) {
- aura::WindowTreeHost* host =
- aura::WindowTreeHost::GetForAcceleratedWidget(widget);
- return host ? host->window()->GetProperty(kHostForRootWindow) : nullptr;
-}
+DesktopWindowTreeHostLinux::~DesktopWindowTreeHostLinux() = default;
// static
std::vector<aura::Window*> DesktopWindowTreeHostLinux::GetAllOpenWindows() {
std::vector<aura::Window*> windows(open_windows().size());
std::transform(open_windows().begin(), open_windows().end(), windows.begin(),
- GetContentWindowForWidget);
+ DesktopWindowTreeHostPlatform::GetContentWindowForWidget);
return windows;
}
@@ -116,7 +93,7 @@ void DesktopWindowTreeHostLinux::CleanUpWindowList(
return;
while (!open_windows_->empty()) {
gfx::AcceleratedWidget widget = open_windows_->front();
- func(GetContentWindowForWidget(widget));
+ func(DesktopWindowTreeHostPlatform::GetContentWindowForWidget(widget));
if (!open_windows_->empty() && open_windows_->front() == widget)
open_windows_->erase(open_windows_->begin());
}
@@ -175,8 +152,6 @@ void DesktopWindowTreeHostLinux::Init(const Widget::InitParams& params) {
void DesktopWindowTreeHostLinux::OnNativeWidgetCreated(
const Widget::InitParams& params) {
- window()->SetProperty(kHostForRootWindow, this);
-
CreateNonClientEventFilter();
DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(params);
}
@@ -200,6 +175,15 @@ void DesktopWindowTreeHostLinux::InitModalType(ui::ModalType modal_type) {
}
}
+Widget::MoveLoopResult DesktopWindowTreeHostLinux::RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) {
+ GetContentWindow()->SetCapture();
+ return DesktopWindowTreeHostPlatform::RunMoveLoop(drag_offset, source,
+ escape_behavior);
+}
+
void DesktopWindowTreeHostLinux::OnDisplayMetricsChanged(
const display::Display& display,
uint32_t changed_metrics) {
@@ -310,7 +294,7 @@ bool DesktopWindowTreeHostLinux::OnAtkKeyEvent(AtkKeyEventStruct* atk_event) {
}
#endif
-bool DesktopWindowTreeHostLinux::IsOverrideRedirect() const {
+bool DesktopWindowTreeHostLinux::IsOverrideRedirect(bool is_tiling_wm) const {
// BrowserDesktopWindowTreeHostLinux implements this for browser windows.
return false;
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
index 1351c2a66c4..79bef5fe949 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
@@ -43,14 +43,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux
DesktopNativeWidgetAura* desktop_native_widget_aura);
~DesktopWindowTreeHostLinux() override;
- // A way of converting a |widget| into the content_window()
- // of the associated DesktopNativeWidgetAura.
- static aura::Window* GetContentWindowForWidget(gfx::AcceleratedWidget widget);
-
- // A way of converting a |widget| into this object.
- static DesktopWindowTreeHostLinux* GetHostForWidget(
- gfx::AcceleratedWidget widget);
-
// Get all open top-level windows. This includes windows that may not be
// visible. This list is sorted in their stacking order, i.e. the first window
// is the topmost window.
@@ -82,6 +74,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
base::flat_map<std::string, std::string> GetKeyboardLayoutMap() override;
void InitModalType(ui::ModalType modal_type) override;
+ Widget::MoveLoopResult RunMoveLoop(
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) override;
// PlatformWindowDelegate:
void DispatchEvent(ui::Event* event) override;
@@ -117,7 +113,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux
#if BUILDFLAG(USE_ATK)
bool OnAtkKeyEvent(AtkKeyEventStruct* atk_key_event) override;
#endif
- bool IsOverrideRedirect() const override;
+ bool IsOverrideRedirect(bool is_tiling_wm) const override;
// Enables event listening after closing |dialog|.
void EnableEventListening();
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc
index 0b2ab7e4538..cb61f3c0b4d 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_linux_interactive_uitest.cc
@@ -9,7 +9,7 @@
#include "ui/base/hit_test.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
-#include "ui/views/test/views_interactive_ui_test_base.h"
+#include "ui/views/test/widget_test.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/desktop_aura/window_event_filter_linux.h"
#include "ui/views/widget/widget_delegate.h"
@@ -180,7 +180,8 @@ class TestDesktopWindowTreeHostLinux : public DesktopWindowTreeHostLinux {
} // namespace
-class DesktopWindowTreeHostLinuxTest : public ViewsInteractiveUITestBase {
+class DesktopWindowTreeHostLinuxTest
+ : public test::DesktopWidgetTestInteractive {
public:
DesktopWindowTreeHostLinuxTest() = default;
~DesktopWindowTreeHostLinuxTest() override = default;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index f3a3175c6c3..aaf1b482f71 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -21,6 +21,7 @@
#include "ui/gfx/geometry/dip_util.h"
#include "ui/platform_window/extensions/workspace_extension.h"
#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_handler/wm_move_loop_handler.h"
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/views/corewm/tooltip_aura.h"
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h"
@@ -28,9 +29,16 @@
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/window/native_frame_view.h"
#include "ui/wm/core/window_util.h"
+#include "ui/wm/public/window_move_client.h"
+
+DEFINE_UI_CLASS_PROPERTY_TYPE(views::DesktopWindowTreeHostPlatform*)
namespace views {
+DEFINE_UI_CLASS_PROPERTY_KEY(DesktopWindowTreeHostPlatform*,
+ kHostForRootWindow,
+ nullptr)
+
namespace {
bool DetermineInactivity(ui::WindowShowState show_state) {
@@ -108,14 +116,31 @@ DesktopWindowTreeHostPlatform::DesktopWindowTreeHostPlatform(
internal::NativeWidgetDelegate* native_widget_delegate,
DesktopNativeWidgetAura* desktop_native_widget_aura)
: native_widget_delegate_(native_widget_delegate),
- desktop_native_widget_aura_(desktop_native_widget_aura) {}
+ desktop_native_widget_aura_(desktop_native_widget_aura),
+ window_move_client_(this) {}
DesktopWindowTreeHostPlatform::~DesktopWindowTreeHostPlatform() {
+ window()->ClearProperty(kHostForRootWindow);
DCHECK(!platform_window()) << "The host must be closed before destroying it.";
desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
DestroyDispatcher();
}
+// static
+aura::Window* DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ gfx::AcceleratedWidget widget) {
+ auto* host = DesktopWindowTreeHostPlatform::GetHostForWidget(widget);
+ return host ? host->GetContentWindow() : nullptr;
+}
+
+// static
+DesktopWindowTreeHostPlatform* DesktopWindowTreeHostPlatform::GetHostForWidget(
+ gfx::AcceleratedWidget widget) {
+ aura::WindowTreeHost* host =
+ aura::WindowTreeHost::GetForAcceleratedWidget(widget);
+ return host ? host->window()->GetProperty(kHostForRootWindow) : nullptr;
+}
+
aura::Window* DesktopWindowTreeHostPlatform::GetContentWindow() {
return desktop_native_widget_aura_->content_window();
}
@@ -160,6 +185,11 @@ void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
const Widget::InitParams& params) {
+ window()->SetProperty(kHostForRootWindow, this);
+ // This reroutes RunMoveLoop requests to the DesktopWindowTreeHostPlatform.
+ // The availability of this feature depends on a platform (PlatformWindow)
+ // that implements RunMoveLoop.
+ wm::SetWindowMoveClient(window(), &window_move_client_);
platform_window()->SetUseNativeFrame(params.type ==
Widget::InitParams::TYPE_WINDOW &&
!params.remove_standard_frame);
@@ -504,14 +534,16 @@ Widget::MoveLoopResult DesktopWindowTreeHostPlatform::RunMoveLoop(
const gfx::Vector2d& drag_offset,
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) {
- // TODO(crbug.com/896640): needs PlatformWindow support.
- NOTIMPLEMENTED_LOG_ONCE();
+ auto* move_loop_handler = ui::GetWmMoveLoopHandler(*platform_window());
+ if (move_loop_handler && move_loop_handler->RunMoveLoop(drag_offset))
+ return Widget::MOVE_LOOP_SUCCESSFUL;
return Widget::MOVE_LOOP_CANCELED;
}
void DesktopWindowTreeHostPlatform::EndMoveLoop() {
- // TODO(crbug.com/896640): needs PlatformWindow support.
- NOTIMPLEMENTED_LOG_ONCE();
+ auto* move_loop_handler = ui::GetWmMoveLoopHandler(*platform_window());
+ if (move_loop_handler)
+ move_loop_handler->EndMoveLoop();
}
void DesktopWindowTreeHostPlatform::SetVisibilityChangedAnimationsEnabled(
@@ -646,6 +678,7 @@ void DesktopWindowTreeHostPlatform::HideImpl() {
}
void DesktopWindowTreeHostPlatform::OnClosed() {
+ wm::SetWindowMoveClient(window(), nullptr);
SetPlatformWindow(nullptr);
desktop_native_widget_aura_->OnHostClosed();
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index 24a5fa974dd..75860eaabf1 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -16,6 +16,7 @@
#include "ui/platform_window/extensions/workspace_extension_delegate.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
+#include "ui/views/widget/desktop_aura/window_move_client_platform.h"
namespace views {
@@ -29,6 +30,14 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
DesktopNativeWidgetAura* desktop_native_widget_aura);
~DesktopWindowTreeHostPlatform() override;
+ // A way of converting a |widget| into the content_window()
+ // of the associated DesktopNativeWidgetAura.
+ static aura::Window* GetContentWindowForWidget(gfx::AcceleratedWidget widget);
+
+ // A way of converting a |widget| into this object.
+ static DesktopWindowTreeHostPlatform* GetHostForWidget(
+ gfx::AcceleratedWidget widget);
+
// Accessor for DesktopNativeWidgetAura::content_window().
aura::Window* GetContentWindow();
const aura::Window* GetContentWindow() const;
@@ -161,6 +170,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
// normal state.
ui::PlatformWindowState old_state_ = ui::PlatformWindowState::kUnknown;
+ // Used for tab dragging in move loop requests.
+ WindowMoveClientPlatform window_move_client_;
+
base::WeakPtrFactory<DesktopWindowTreeHostPlatform> close_widget_factory_{
this};
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index 6f576d95707..6051aadee62 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -12,6 +12,7 @@
#include "base/containers/flat_set.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "third_party/skia/include/core/SkPath.h"
@@ -622,6 +623,8 @@ DesktopWindowTreeHostWin::GetKeyboardLayoutMap() {
}
void DesktopWindowTreeHostWin::SetCursorNative(gfx::NativeCursor cursor) {
+ TRACE_EVENT1("ui,input", "DesktopWindowTreeHostWin::SetCursorNative",
+ "cursor", cursor.type());
ui::CursorLoaderWin cursor_loader;
cursor_loader.SetPlatformCursor(&cursor);
@@ -922,8 +925,20 @@ bool DesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) {
// marked occluded, or getting stuck in the occluded state. Event can cause
// this object to be deleted so check occlusion state before we do anything
// with the event.
- if (GetNativeWindowOcclusionState() == aura::Window::OcclusionState::OCCLUDED)
- UMA_HISTOGRAM_BOOLEAN("OccludedWindowMouseEvents", true);
+ // This stat tries to detect the user moving the mouse over a window falsely
+ // determined to be occluded, so ignore mouse events that have the same
+ // location as the first event, and exit events.
+ if (GetNativeWindowOcclusionState() ==
+ aura::Window::OcclusionState::OCCLUDED) {
+ if (occluded_window_mouse_event_loc_ != gfx::Point() &&
+ event->location() != occluded_window_mouse_event_loc_ &&
+ event->type() != ui::ET_MOUSE_EXITED) {
+ UMA_HISTOGRAM_BOOLEAN("OccludedWindowMouseEvents", true);
+ }
+ occluded_window_mouse_event_loc_ = event->location();
+ } else {
+ occluded_window_mouse_event_loc_ = gfx::Point();
+ }
SendEventToSink(event);
return event->handled();
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
index 4b217541512..75ca9e99f2c 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -307,6 +307,11 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
// become activated.
bool wants_mouse_events_when_inactive_ = false;
+ // The location of the most recent mouse event on an occluded window. This is
+ // used to generate the OccludedWindowMouseEvents stat and can be removed
+ // when that stat is no longer tracked.
+ gfx::Point occluded_window_mouse_event_loc_;
+
// The z-order level of the window; the window exhibits "always on top"
// behavior if > 0.
ui::ZOrderLevel z_order_ = ui::ZOrderLevel::kNormal;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 2c94941cf27..44e9eef3492 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -31,7 +31,7 @@
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/buildflags.h"
#include "ui/base/class_property.h"
-#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_x11.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/layout.h"
@@ -57,7 +57,6 @@
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
#include "ui/views/window/native_frame_view.h"
#include "ui/wm/core/compound_event_filter.h"
#include "ui/wm/core/window_util.h"
@@ -72,12 +71,7 @@ DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
: DesktopWindowTreeHostLinux(native_widget_delegate,
desktop_native_widget_aura) {}
-DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
- wm::SetWindowMoveClient(window(), nullptr);
-
- // ~DWTHPlatform notifies the DestkopNativeWidgetAura about destruction and
- // also destroyes the dispatcher.
-}
+DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() = default;
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
@@ -94,14 +88,6 @@ void DesktopWindowTreeHostX11::Init(const Widget::InitParams& params) {
static_cast<ui::X11Window*>(platform_window())->SetXEventDelegate(this);
}
-void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
- const Widget::InitParams& params) {
- x11_window_move_client_ = std::make_unique<X11DesktopWindowMoveClient>();
- wm::SetWindowMoveClient(window(), x11_window_move_client_.get());
-
- DesktopWindowTreeHostLinux::OnNativeWidgetCreated(params);
-}
-
std::unique_ptr<aura::client::DragDropClient>
DesktopWindowTreeHostX11::CreateDragDropClient(
DesktopNativeCursorManager* cursor_manager) {
@@ -112,25 +98,6 @@ DesktopWindowTreeHostX11::CreateDragDropClient(
return base::WrapUnique(drag_drop_client_);
}
-Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) {
- wm::WindowMoveSource window_move_source =
- source == Widget::MoveLoopSource::kMouse ? wm::WINDOW_MOVE_SOURCE_MOUSE
- : wm::WINDOW_MOVE_SOURCE_TOUCH;
- if (x11_window_move_client_->RunMoveLoop(GetContentWindow(), drag_offset,
- window_move_source) ==
- wm::MOVE_SUCCESSFUL)
- return Widget::MOVE_LOOP_SUCCESSFUL;
-
- return Widget::MOVE_LOOP_CANCELED;
-}
-
-void DesktopWindowTreeHostX11::EndMoveLoop() {
- x11_window_move_client_->EndMoveLoop();
-}
-
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostX11 implementation:
@@ -143,21 +110,7 @@ void DesktopWindowTreeHostX11::OnXWindowSelectionEvent(XEvent* xev) {
void DesktopWindowTreeHostX11::OnXWindowDragDropEvent(XEvent* xev) {
DCHECK(xev);
DCHECK(drag_drop_client_);
-
- ::Atom message_type = xev->xclient.message_type;
- if (message_type == gfx::GetAtom("XdndEnter")) {
- drag_drop_client_->OnXdndEnter(xev->xclient);
- } else if (message_type == gfx::GetAtom("XdndLeave")) {
- drag_drop_client_->OnXdndLeave(xev->xclient);
- } else if (message_type == gfx::GetAtom("XdndPosition")) {
- drag_drop_client_->OnXdndPosition(xev->xclient);
- } else if (message_type == gfx::GetAtom("XdndStatus")) {
- drag_drop_client_->OnXdndStatus(xev->xclient);
- } else if (message_type == gfx::GetAtom("XdndFinished")) {
- drag_drop_client_->OnXdndFinished(xev->xclient);
- } else if (message_type == gfx::GetAtom("XdndDrop")) {
- drag_drop_client_->OnXdndDrop(xev->xclient);
- }
+ drag_drop_client_->HandleXdndEvent(xev->xclient);
}
const ui::XWindow* DesktopWindowTreeHostX11::GetXWindow() const {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index 53da309c14d..8cd6b80ee1e 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -21,7 +21,6 @@ class X11Window;
namespace views {
class DesktopDragDropClientAuraX11;
-class X11DesktopWindowMoveClient;
class VIEWS_EXPORT DesktopWindowTreeHostX11 : public DesktopWindowTreeHostLinux,
public ui::XEventDelegate {
@@ -34,14 +33,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 : public DesktopWindowTreeHostLinux,
protected:
// Overridden from DesktopWindowTreeHost:
void Init(const Widget::InitParams& params) override;
- void OnNativeWidgetCreated(const Widget::InitParams& params) override;
std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient(
DesktopNativeCursorManager* cursor_manager) override;
- Widget::MoveLoopResult RunMoveLoop(
- const gfx::Vector2d& drag_offset,
- Widget::MoveLoopSource source,
- Widget::MoveLoopEscapeBehavior escape_behavior) override;
- void EndMoveLoop() override;
private:
friend class DesktopWindowTreeHostX11HighDPITest;
@@ -58,8 +51,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 : public DesktopWindowTreeHostLinux,
DesktopDragDropClientAuraX11* drag_drop_client_ = nullptr;
- std::unique_ptr<X11DesktopWindowMoveClient> x11_window_move_client_;
-
DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11);
};
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
index 7135ad984e3..c63bfe26350 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc
@@ -11,6 +11,7 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/input_method.h"
+#include "ui/base/x/test/x11_property_change_waiter.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/event_handler.h"
#include "ui/events/platform/x11/x11_event_source.h"
@@ -19,8 +20,7 @@
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/test/views_interactive_ui_test_base.h"
-#include "ui/views/test/x11_property_change_waiter.h"
+#include "ui/views/test/widget_test.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
namespace views {
@@ -28,16 +28,17 @@ namespace views {
namespace {
// Blocks till |window| gets activated.
-class ActivationWaiter : public X11PropertyChangeWaiter {
+class ActivationWaiter : public ui::X11PropertyChangeWaiter {
public:
explicit ActivationWaiter(XID window)
- : X11PropertyChangeWaiter(ui::GetX11RootWindow(), "_NET_ACTIVE_WINDOW"),
+ : ui::X11PropertyChangeWaiter(ui::GetX11RootWindow(),
+ "_NET_ACTIVE_WINDOW"),
window_(window) {}
~ActivationWaiter() override = default;
private:
- // X11PropertyChangeWaiter:
+ // ui::X11PropertyChangeWaiter:
bool ShouldKeepOnWaiting(XEvent* event) override {
XID xid = 0;
ui::GetXIDProperty(ui::GetX11RootWindow(), "_NET_ACTIVE_WINDOW", &xid);
@@ -108,23 +109,22 @@ void DispatchMouseMotionEvent(DesktopWindowTreeHostX11* desktop_host,
} // namespace
-class DesktopWindowTreeHostX11Test : public ViewsInteractiveUITestBase {
+class DesktopWindowTreeHostX11Test : public test::DesktopWidgetTestInteractive {
public:
DesktopWindowTreeHostX11Test() = default;
~DesktopWindowTreeHostX11Test() override = default;
- // testing::Test
+ // DesktopWidgetTestInteractive
void SetUp() override {
- ViewsInteractiveUITestBase::SetUp();
-
// Make X11 synchronous for our display connection. This does not force the
// window manager to behave synchronously.
XSynchronize(gfx::GetXDisplay(), x11::True);
+ DesktopWidgetTestInteractive::SetUp();
}
void TearDown() override {
XSynchronize(gfx::GetXDisplay(), x11::False);
- ViewsInteractiveUITestBase::TearDown();
+ DesktopWidgetTestInteractive::TearDown();
}
private:
@@ -235,6 +235,12 @@ TEST_F(DesktopWindowTreeHostX11Test, CaptureEventForwarding) {
TEST_F(DesktopWindowTreeHostX11Test, InputMethodFocus) {
std::unique_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100)));
+
+ // Waiter should be created as early as possible so that PropertyNotify has
+ // time to be set before widget is activated.
+ ActivationWaiter waiter(
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+
std::unique_ptr<Textfield> textfield(new Textfield);
textfield->SetBounds(0, 0, 200, 20);
widget->GetRootView()->AddChildView(textfield.get());
@@ -247,11 +253,6 @@ TEST_F(DesktopWindowTreeHostX11Test, InputMethodFocus) {
// EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
// widget->GetInputMethod()->GetTextInputType());
- // Waiter should be created before widget->Activate is called. Otherwise,
- // there is a race, and waiter might not be able to set property changes mask
- // on time and miss the events.
- ActivationWaiter waiter(
- widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
widget->Activate();
waiter.Wait();
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
index 88b625f1b59..1f4b3a5244c 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
@@ -16,6 +16,7 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
+#include "ui/base/x/test/x11_property_change_waiter.h"
#include "ui/base/x/x11_util.h"
#include "ui/display/display_switches.h"
#include "ui/events/devices/x11/touch_factory_x11.h"
@@ -28,7 +29,6 @@
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/views/test/views_test_base.h"
-#include "ui/views/test/x11_property_change_waiter.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
#include "ui/views/widget/widget_delegate.h"
@@ -41,10 +41,10 @@ namespace {
const int kPointerDeviceId = 1;
// Blocks till the window state hint, |hint|, is set or unset.
-class WMStateWaiter : public X11PropertyChangeWaiter {
+class WMStateWaiter : public ui::X11PropertyChangeWaiter {
public:
WMStateWaiter(XID window, const char* hint, bool wait_till_set)
- : X11PropertyChangeWaiter(window, "_NET_WM_STATE"),
+ : ui::X11PropertyChangeWaiter(window, "_NET_WM_STATE"),
hint_(hint),
wait_till_set_(wait_till_set) {}
diff --git a/chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc b/chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc
index d69da05aa30..915fa77545d 100644
--- a/chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc
+++ b/chromium/ui/views/widget/desktop_aura/window_event_filter_linux.cc
@@ -112,6 +112,10 @@ void WindowEventFilterLinux::OnClickedCaption(ui::MouseEvent* event,
if (!view || !view->context_menu_controller())
break;
gfx::Point location(event->location());
+ // Controller requires locations to be in DIP, while |this| receives the
+ // location in px.
+ desktop_window_tree_host_->GetRootTransform().TransformPointReverse(
+ &location);
views::View::ConvertPointToScreen(view, &location);
view->ShowContextMenu(location, ui::MENU_SOURCE_MOUSE);
event->SetHandled();
diff --git a/chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc b/chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc
new file mode 100644
index 00000000000..d561307dbca
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/window_move_client_platform.cc
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/window_move_client_platform.h"
+
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
+
+namespace views {
+
+WindowMoveClientPlatform::WindowMoveClientPlatform(
+ DesktopWindowTreeHostPlatform* host)
+ : host_(host) {}
+
+WindowMoveClientPlatform::~WindowMoveClientPlatform() = default;
+
+wm::WindowMoveResult WindowMoveClientPlatform::RunMoveLoop(
+ aura::Window* source,
+ const gfx::Vector2d& drag_offset,
+ wm::WindowMoveSource move_source) {
+ DCHECK(host_->GetContentWindow()->Contains(source));
+ auto move_loop_result = host_->RunMoveLoop(
+ drag_offset,
+ move_source == wm::WindowMoveSource::WINDOW_MOVE_SOURCE_MOUSE
+ ? Widget::MoveLoopSource::kMouse
+ : Widget::MoveLoopSource::kTouch,
+ Widget::MoveLoopEscapeBehavior::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE);
+
+ return move_loop_result == Widget::MOVE_LOOP_SUCCESSFUL ? wm::MOVE_SUCCESSFUL
+ : wm::MOVE_CANCELED;
+}
+
+void WindowMoveClientPlatform::EndMoveLoop() {
+ host_->EndMoveLoop();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/window_move_client_platform.h b/chromium/ui/views/widget/desktop_aura/window_move_client_platform.h
new file mode 100644
index 00000000000..09d46399247
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/window_move_client_platform.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_MOVE_CLIENT_PLATFORM_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_MOVE_CLIENT_PLATFORM_H_
+
+#include "ui/views/views_export.h"
+#include "ui/wm/public/window_move_client.h"
+
+namespace views {
+
+class DesktopWindowTreeHostPlatform;
+
+// Reroutes move loop requests to DesktopWindowTreeHostPlatform.
+class VIEWS_EXPORT WindowMoveClientPlatform : public wm::WindowMoveClient {
+ public:
+ explicit WindowMoveClientPlatform(DesktopWindowTreeHostPlatform* host);
+ WindowMoveClientPlatform(const WindowMoveClientPlatform& host) = delete;
+ WindowMoveClientPlatform& operator=(const WindowMoveClientPlatform& host) =
+ delete;
+ ~WindowMoveClientPlatform() override;
+
+ // Overridden from wm::WindowMoveClient:
+ wm::WindowMoveResult RunMoveLoop(aura::Window* window,
+ const gfx::Vector2d& drag_offset,
+ wm::WindowMoveSource move_source) override;
+ void EndMoveLoop() override;
+
+ private:
+ // The RunMoveLoop request is forwarded to this host.
+ DesktopWindowTreeHostPlatform* host_ = nullptr;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_MOVE_CLIENT_PLATFORM_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
deleted file mode 100644
index 80b34d05334..00000000000
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
-
-#include "base/run_loop.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/events/event.h"
-#include "ui/gfx/x/x11.h"
-
-namespace views {
-
-X11DesktopWindowMoveClient::X11DesktopWindowMoveClient() = default;
-
-X11DesktopWindowMoveClient::~X11DesktopWindowMoveClient() = default;
-
-void X11DesktopWindowMoveClient::OnMouseMovement(const gfx::Point& screen_point,
- int flags,
- base::TimeTicks event_time) {
- gfx::Point system_loc = screen_point - window_offset_;
- host_->SetBoundsInPixels(
- gfx::Rect(system_loc, host_->GetBoundsInPixels().size()));
-}
-
-void X11DesktopWindowMoveClient::OnMouseReleased() {
- EndMoveLoop();
-}
-
-void X11DesktopWindowMoveClient::OnMoveLoopEnded() {
- host_ = nullptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopWindowTreeHostLinux, wm::WindowMoveClient implementation:
-
-wm::WindowMoveResult X11DesktopWindowMoveClient::RunMoveLoop(
- aura::Window* source,
- const gfx::Vector2d& drag_offset,
- wm::WindowMoveSource move_source) {
- window_offset_ = drag_offset;
- host_ = source->GetHost();
-
- source->SetCapture();
- bool success = move_loop_.RunMoveLoop(source, host_->last_cursor());
- return success ? wm::MOVE_SUCCESSFUL : wm::MOVE_CANCELED;
-}
-
-void X11DesktopWindowMoveClient::EndMoveLoop() {
- move_loop_.EndMoveLoop();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
deleted file mode 100644
index 3305ca520bc..00000000000
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_WINDOW_MOVE_CLIENT_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_WINDOW_MOVE_CLIENT_H_
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/x/x11.h"
-#include "ui/views/views_export.h"
-#include "ui/views/widget/desktop_aura/x11_move_loop_delegate.h"
-#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
-#include "ui/wm/public/window_move_client.h"
-
-namespace aura {
-class WindowTreeHost;
-}
-
-namespace views {
-
-// When we're dragging tabs, we need to manually position our window.
-class VIEWS_EXPORT X11DesktopWindowMoveClient
- : public views::X11MoveLoopDelegate,
- public wm::WindowMoveClient {
- public:
- X11DesktopWindowMoveClient();
- ~X11DesktopWindowMoveClient() override;
-
- // Overridden from X11WholeScreenMoveLoopDelegate:
- void OnMouseMovement(const gfx::Point& screen_point,
- int flags,
- base::TimeTicks event_time) override;
- void OnMouseReleased() override;
- void OnMoveLoopEnded() override;
-
- // Overridden from wm::WindowMoveClient:
- wm::WindowMoveResult RunMoveLoop(aura::Window* window,
- const gfx::Vector2d& drag_offset,
- wm::WindowMoveSource move_source) override;
- void EndMoveLoop() override;
-
- private:
- X11WholeScreenMoveLoop move_loop_{this};
-
- // We need to keep track of this so we can actually move it when reacting to
- // mouse events.
- aura::WindowTreeHost* host_ = nullptr;
-
- // Our cursor offset from the top left window origin when the drag
- // started. Used to calculate the window's new bounds relative to the current
- // location of the cursor.
- gfx::Vector2d window_offset_;
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_WINDOW_MOVE_CLIENT_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_move_loop.h b/chromium/ui/views/widget/desktop_aura/x11_move_loop.h
deleted file mode 100644
index b12cbecde9c..00000000000
--- a/chromium/ui/views/widget/desktop_aura/x11_move_loop.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_MOVE_LOOP_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_MOVE_LOOP_H_
-
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/x/x11_types.h"
-
-namespace views {
-
-// Runs a nested run loop and grabs the mouse. This is used to implement
-// dragging.
-class X11MoveLoop {
- public:
- virtual ~X11MoveLoop() {}
-
- // Runs the nested run loop. While the mouse is grabbed, use |cursor| as
- // the mouse cursor. Returns true if the move-loop is completed successfully.
- // If the pointer-grab fails, or the move-loop is canceled by the user (e.g.
- // by pressing escape), then returns false.
- virtual bool RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor) = 0;
-
- // Updates the cursor while the move loop is running.
- virtual void UpdateCursor(gfx::NativeCursor cursor) = 0;
-
- // Ends the move loop that's currently in progress.
- virtual void EndMoveLoop() = 0;
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_MOVE_LOOP_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_move_loop_delegate.h b/chromium/ui/views/widget/desktop_aura/x11_move_loop_delegate.h
deleted file mode 100644
index b5eee9b7257..00000000000
--- a/chromium/ui/views/widget/desktop_aura/x11_move_loop_delegate.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_MOVE_LOOP_DELEGATE_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_MOVE_LOOP_DELEGATE_H_
-
-namespace gfx {
-class Point;
-}
-
-namespace views {
-
-// Receives mouse events while the X11MoveLoop is tracking a drag.
-class X11MoveLoopDelegate {
- public:
- // Called when we receive a mouse move event.
- virtual void OnMouseMovement(const gfx::Point& screen_point,
- int flags,
- base::TimeTicks event_time) = 0;
-
- // Called when the mouse button is released.
- virtual void OnMouseReleased() = 0;
-
- // Called when the user has released the mouse button. The move loop will
- // release the grab after this has been called.
- virtual void OnMoveLoopEnded() = 0;
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_MOVE_LOOP_DELEGATE_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
deleted file mode 100644
index 9acc365e582..00000000000
--- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/window.h"
-#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
-
-namespace views {
-
-X11TopmostWindowFinder::X11TopmostWindowFinder() = default;
-
-X11TopmostWindowFinder::~X11TopmostWindowFinder() = default;
-
-aura::Window* X11TopmostWindowFinder::FindLocalProcessWindowAt(
- const gfx::Point& screen_loc_in_pixels,
- const std::set<aura::Window*>& ignore) {
- screen_loc_in_pixels_ = screen_loc_in_pixels;
- ignore_ = ignore;
-
- std::vector<aura::Window*> local_process_windows =
- DesktopWindowTreeHostLinux::GetAllOpenWindows();
- if (std::none_of(local_process_windows.cbegin(), local_process_windows.cend(),
- [this](auto* window) {
- return ShouldStopIteratingAtLocalProcessWindow(window);
- }))
- return nullptr;
-
- ui::EnumerateTopLevelWindows(this);
- return DesktopWindowTreeHostLinux::GetContentWindowForWidget(
- static_cast<gfx::AcceleratedWidget>(toplevel_));
-}
-
-XID X11TopmostWindowFinder::FindWindowAt(
- const gfx::Point& screen_loc_in_pixels) {
- screen_loc_in_pixels_ = screen_loc_in_pixels;
- ui::EnumerateTopLevelWindows(this);
- return toplevel_;
-}
-
-bool X11TopmostWindowFinder::ShouldStopIterating(XID xid) {
- if (!ui::IsWindowVisible(xid))
- return false;
-
- auto* window = DesktopWindowTreeHostLinux::GetContentWindowForWidget(
- static_cast<gfx::AcceleratedWidget>(xid));
- if (window) {
- if (ShouldStopIteratingAtLocalProcessWindow(window)) {
- toplevel_ = xid;
- return true;
- }
- return false;
- }
-
- if (ui::WindowContainsPoint(xid, screen_loc_in_pixels_)) {
- toplevel_ = xid;
- return true;
- }
- return false;
-}
-
-bool X11TopmostWindowFinder::ShouldStopIteratingAtLocalProcessWindow(
- aura::Window* window) {
- if (ignore_.find(window) != ignore_.end())
- return false;
-
- // Currently |window|->IsVisible() always returns true.
- // TODO(pkotwicz): Fix this. crbug.com/353038
- if (!window->IsVisible())
- return false;
-
- auto* host = DesktopWindowTreeHostLinux::GetHostForWidget(
- window->GetHost()->GetAcceleratedWidget());
- if (!static_cast<DesktopWindowTreeHostX11*>(host)
- ->GetXRootWindowOuterBounds()
- .Contains(screen_loc_in_pixels_))
- return false;
-
- aura::client::ScreenPositionClient* screen_position_client =
- aura::client::GetScreenPositionClient(window->GetRootWindow());
- gfx::Point window_loc(screen_loc_in_pixels_);
- screen_position_client->ConvertPointFromScreen(window, &window_loc);
- return host->ContainsPointInXRegion(window_loc);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h
deleted file mode 100644
index 0d9e535153a..00000000000
--- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_TOPMOST_WINDOW_FINDER_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_TOPMOST_WINDOW_FINDER_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "ui/base/x/x11_topmost_window_finder.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/x/x11.h"
-#include "ui/views/views_export.h"
-
-namespace aura {
-class Window;
-}
-
-namespace views {
-
-// Utility class for finding the topmost window at a given screen position.
-class VIEWS_EXPORT X11TopmostWindowFinder : public ui::EnumerateWindowsDelegate,
- public ui::XTopmostWindowFinder {
- public:
- X11TopmostWindowFinder();
- ~X11TopmostWindowFinder() override;
-
- // Returns the topmost window at |screen_loc_in_pixels|, ignoring the windows
- // in |ignore|. Returns NULL if the topmost window at |screen_loc_in_pixels|
- // does not belong to Chrome.
- aura::Window* FindLocalProcessWindowAt(const gfx::Point& screen_loc_in_pixels,
- const std::set<aura::Window*>& ignore);
-
- // Returns the topmost window at |screen_loc_in_pixels|.
- XID FindWindowAt(const gfx::Point& screen_loc_in_pixels) override;
-
- private:
- // ui::EnumerateWindowsDelegate:
- bool ShouldStopIterating(XID xid) override;
-
- // Returns true if |window| does not not belong to |ignore|, is visible and
- // contains |screen_loc_|.
- bool ShouldStopIteratingAtLocalProcessWindow(aura::Window* window);
-
- gfx::Point screen_loc_in_pixels_;
- std::set<aura::Window*> ignore_;
- XID toplevel_ = x11::None;
-
- DISALLOW_COPY_AND_ASSIGN(X11TopmostWindowFinder);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_TOPMOST_WINDOW_FINDER_H_
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
index ce5c9ef430d..aa249625d3f 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
+#include "ui/platform_window/x11/x11_topmost_window_finder.h"
#include <stddef.h>
@@ -14,13 +14,14 @@
#include "third_party/skia/include/core/SkRect.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
+#include "ui/base/x/test/x11_property_change_waiter.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_path.h"
-#include "ui/views/test/views_interactive_ui_test_base.h"
-#include "ui/views/test/x11_property_change_waiter.h"
+#include "ui/views/test/widget_test.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -28,15 +29,15 @@ namespace views {
namespace {
// Waits till |window| is minimized.
-class MinimizeWaiter : public X11PropertyChangeWaiter {
+class MinimizeWaiter : public ui::X11PropertyChangeWaiter {
public:
explicit MinimizeWaiter(XID window)
- : X11PropertyChangeWaiter(window, "_NET_WM_STATE") {}
+ : ui::X11PropertyChangeWaiter(window, "_NET_WM_STATE") {}
~MinimizeWaiter() override = default;
private:
- // X11PropertyChangeWaiter:
+ // ui::X11PropertyChangeWaiter:
bool ShouldKeepOnWaiting(XEvent* event) override {
std::vector<Atom> wm_states;
if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) {
@@ -50,11 +51,11 @@ class MinimizeWaiter : public X11PropertyChangeWaiter {
// Waits till |_NET_CLIENT_LIST_STACKING| is updated to include
// |expected_windows|.
-class StackingClientListWaiter : public X11PropertyChangeWaiter {
+class StackingClientListWaiter : public ui::X11PropertyChangeWaiter {
public:
StackingClientListWaiter(XID* expected_windows, size_t count)
- : X11PropertyChangeWaiter(ui::GetX11RootWindow(),
- "_NET_CLIENT_LIST_STACKING"),
+ : ui::X11PropertyChangeWaiter(ui::GetX11RootWindow(),
+ "_NET_CLIENT_LIST_STACKING"),
expected_windows_(expected_windows, expected_windows + count) {}
~StackingClientListWaiter() override = default;
@@ -66,11 +67,11 @@ class StackingClientListWaiter : public X11PropertyChangeWaiter {
if (!ShouldKeepOnWaiting(nullptr))
return;
- X11PropertyChangeWaiter::Wait();
+ ui::X11PropertyChangeWaiter::Wait();
}
private:
- // X11PropertyChangeWaiter:
+ // ui::X11PropertyChangeWaiter:
bool ShouldKeepOnWaiting(XEvent* event) override {
std::vector<XID> stack;
ui::GetXWindowStack(ui::GetX11RootWindow(), &stack);
@@ -86,12 +87,24 @@ class StackingClientListWaiter : public X11PropertyChangeWaiter {
} // namespace
-class X11TopmostWindowFinderTest : public ViewsInteractiveUITestBase {
+class X11TopmostWindowFinderTest : public test::DesktopWidgetTestInteractive {
public:
X11TopmostWindowFinderTest() = default;
-
~X11TopmostWindowFinderTest() override = default;
+ // DesktopWidgetTestInteractive
+ void SetUp() override {
+ // Make X11 synchronous for our display connection. This does not force the
+ // window manager to behave synchronously.
+ XSynchronize(xdisplay(), x11::True);
+ DesktopWidgetTestInteractive::SetUp();
+ }
+
+ void TearDown() override {
+ XSynchronize(xdisplay(), x11::False);
+ DesktopWidgetTestInteractive::TearDown();
+ }
+
// Creates and shows a Widget with |bounds|. The caller takes ownership of
// the returned widget.
std::unique_ptr<Widget> CreateAndShowWidget(const gfx::Rect& bounds) {
@@ -135,16 +148,19 @@ class X11TopmostWindowFinderTest : public ViewsInteractiveUITestBase {
// Returns the topmost X window at the passed in screen position.
XID FindTopmostXWindowAt(int screen_x, int screen_y) {
- X11TopmostWindowFinder finder;
+ ui::X11TopmostWindowFinder finder;
return finder.FindWindowAt(gfx::Point(screen_x, screen_y));
}
// Returns the topmost aura::Window at the passed in screen position. Returns
// NULL if the topmost window does not have an associated aura::Window.
aura::Window* FindTopmostLocalProcessWindowAt(int screen_x, int screen_y) {
- X11TopmostWindowFinder finder;
- return finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y),
- std::set<aura::Window*>());
+ ui::X11TopmostWindowFinder finder;
+ auto widget =
+ finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y), {});
+ return widget ? DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ static_cast<gfx::AcceleratedWidget>(widget))
+ : nullptr;
}
// Returns the topmost aura::Window at the passed in screen position ignoring
@@ -154,25 +170,14 @@ class X11TopmostWindowFinderTest : public ViewsInteractiveUITestBase {
int screen_x,
int screen_y,
aura::Window* ignore_window) {
- std::set<aura::Window*> ignore;
- ignore.insert(ignore_window);
- X11TopmostWindowFinder finder;
- return finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y),
- ignore);
- }
-
- // ViewsInteractiveUITestBase:
- void SetUp() override {
- ViewsInteractiveUITestBase::SetUp();
-
- // Make X11 synchronous for our display connection. This does not force the
- // window manager to behave synchronously.
- XSynchronize(xdisplay(), x11::True);
- }
-
- void TearDown() override {
- XSynchronize(xdisplay(), x11::False);
- ViewsInteractiveUITestBase::TearDown();
+ std::set<gfx::AcceleratedWidget> ignore;
+ ignore.insert(ignore_window->GetHost()->GetAcceleratedWidget());
+ ui::X11TopmostWindowFinder finder;
+ auto widget =
+ finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y), ignore);
+ return widget ? DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
+ static_cast<gfx::AcceleratedWidget>(widget))
+ : nullptr;
}
private:
diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
deleted file mode 100644
index 01509c2d677..00000000000
--- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"
-
-#include <stddef.h>
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop_current.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "ui/aura/client/capture_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_event_dispatcher.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/mojom/cursor_type.mojom-shared.h"
-#include "ui/base/x/x11_pointer_grab.h"
-#include "ui/base/x/x11_util.h"
-#include "ui/events/event.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/keyboard_code_conversion_x.h"
-#include "ui/events/platform/platform_event_source.h"
-#include "ui/events/platform/scoped_event_dispatcher.h"
-#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/events/x/events_x_utils.h"
-#include "ui/events/x/x11_window_event_manager.h"
-#include "ui/gfx/x/x11.h"
-
-namespace views {
-
-// XGrabKey requires the modifier mask to explicitly be specified.
-const unsigned int kModifiersMasks[] = {0, // No additional modifier.
- Mod2Mask, // Num lock
- LockMask, // Caps lock
- Mod5Mask, // Scroll lock
- Mod2Mask | LockMask,
- Mod2Mask | Mod5Mask,
- LockMask | Mod5Mask,
- Mod2Mask | LockMask | Mod5Mask};
-
-X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(X11MoveLoopDelegate* delegate)
- : delegate_(delegate),
- in_move_loop_(false),
- initial_cursor_(ui::mojom::CursorType::kNull),
- should_reset_mouse_flags_(false),
- grab_input_window_(x11::None),
- grabbed_pointer_(false),
- canceled_(false) {}
-
-X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() = default;
-
-void X11WholeScreenMoveLoop::DispatchMouseMovement() {
- if (!last_motion_in_screen_)
- return;
- delegate_->OnMouseMovement(last_motion_in_screen_->root_location(),
- last_motion_in_screen_->flags(),
- last_motion_in_screen_->time_stamp());
- last_motion_in_screen_.reset();
-}
-
-void X11WholeScreenMoveLoop::PostDispatchIfNeeded(const ui::MouseEvent& event) {
- bool dispatch_mouse_event = !last_motion_in_screen_;
- last_motion_in_screen_ = std::make_unique<ui::MouseEvent>(event);
- if (dispatch_mouse_event) {
- // Post a task to dispatch mouse movement event when control returns to the
- // message loop. This allows smoother dragging since the events are
- // dispatched without waiting for the drag widget updates.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&X11WholeScreenMoveLoop::DispatchMouseMovement,
- weak_factory_.GetWeakPtr()));
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DesktopWindowTreeHostLinux, ui::PlatformEventDispatcher implementation:
-
-bool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) {
- return in_move_loop_;
-}
-
-uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
- DCHECK(base::MessageLoopCurrentForUI::IsSet());
-
- // This method processes all events while the move loop is active.
- if (!in_move_loop_)
- return ui::POST_DISPATCH_PERFORM_DEFAULT;
-
- switch (event->type()) {
- case ui::ET_MOUSE_MOVED:
- case ui::ET_MOUSE_DRAGGED: {
- PostDispatchIfNeeded(*event->AsMouseEvent());
- return ui::POST_DISPATCH_NONE;
- }
- case ui::ET_MOUSE_RELEASED: {
- if (event->AsMouseEvent()->IsLeftMouseButton()) {
- // Assume that drags are being done with the left mouse button. Only
- // break the drag if the left mouse button was released.
- DispatchMouseMovement();
- delegate_->OnMouseReleased();
-
- if (!grabbed_pointer_) {
- // If the source widget had capture prior to the move loop starting,
- // it may be relying on views::Widget getting the mouse release and
- // releasing capture in Widget::OnMouseEvent().
- return ui::POST_DISPATCH_PERFORM_DEFAULT;
- }
- }
- return ui::POST_DISPATCH_NONE;
- }
- case ui::ET_KEY_PRESSED:
- if (event->AsKeyEvent()->key_code() == ui::VKEY_ESCAPE) {
- canceled_ = true;
- EndMoveLoop();
- return ui::POST_DISPATCH_NONE;
- }
- break;
- default:
- break;
- }
- return ui::POST_DISPATCH_PERFORM_DEFAULT;
-}
-
-bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
- gfx::NativeCursor cursor) {
- DCHECK(!in_move_loop_); // Can only handle one nested loop at a time.
-
- // Query the mouse cursor prior to the move loop starting so that it can be
- // restored when the move loop finishes.
- initial_cursor_ = source->GetHost()->last_cursor();
-
- CreateDragInputWindow(gfx::GetXDisplay());
-
- // Only grab mouse capture of |grab_input_window_| if |source| does not have
- // capture.
- // - The caller may intend to transfer capture to a different aura::Window
- // when the move loop ends and not release capture.
- // - Releasing capture and X window destruction are both asynchronous. We drop
- // events targeted at |grab_input_window_| in the time between the move
- // loop ends and |grab_input_window_| loses capture.
- grabbed_pointer_ = false;
- if (!source->HasCapture()) {
- aura::client::CaptureClient* capture_client =
- aura::client::GetCaptureClient(source->GetRootWindow());
- CHECK(capture_client->GetGlobalCaptureWindow() == nullptr);
- grabbed_pointer_ = GrabPointer(cursor);
- if (!grabbed_pointer_) {
- XDestroyWindow(gfx::GetXDisplay(), grab_input_window_);
- return false;
- }
- }
-
- GrabEscKey();
-
- std::unique_ptr<ui::ScopedEventDispatcher> old_dispatcher =
- std::move(nested_dispatcher_);
- nested_dispatcher_ =
- ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this);
-
- // We are handling a mouse drag outside of the aura::Window system. We must
- // manually make aura think that the mouse button is pressed so that we don't
- // draw extraneous tooltips.
- aura::Env* env = aura::Env::GetInstance();
- if (!env->IsMouseButtonDown()) {
- env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
- should_reset_mouse_flags_ = true;
- }
-
- base::WeakPtr<X11WholeScreenMoveLoop> alive(weak_factory_.GetWeakPtr());
-
- in_move_loop_ = true;
- canceled_ = false;
- base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
- quit_closure_ = run_loop.QuitClosure();
- run_loop.Run();
-
- if (!alive)
- return false;
-
- nested_dispatcher_ = std::move(old_dispatcher);
- return !canceled_;
-}
-
-void X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
- if (in_move_loop_)
- ui::ChangeActivePointerGrabCursor(cursor.platform());
-}
-
-void X11WholeScreenMoveLoop::EndMoveLoop() {
- if (!in_move_loop_)
- return;
-
- // Prevent DispatchMouseMovement from dispatching any posted motion event.
- last_motion_in_screen_.reset();
-
- // We undo our emulated mouse click from RunMoveLoop();
- if (should_reset_mouse_flags_) {
- aura::Env::GetInstance()->set_mouse_button_flags(0);
- should_reset_mouse_flags_ = false;
- }
-
- // TODO(erg): Is this ungrab the cause of having to click to give input focus
- // on drawn out windows? Not ungrabbing here screws the X server until I kill
- // the chrome process.
-
- // Ungrab before we let go of the window.
- if (grabbed_pointer_)
- ui::UngrabPointer();
- else
- UpdateCursor(initial_cursor_);
-
- XDisplay* display = gfx::GetXDisplay();
- unsigned int esc_keycode = XKeysymToKeycode(display, XK_Escape);
- for (auto mask : kModifiersMasks)
- XUngrabKey(display, esc_keycode, mask, grab_input_window_);
-
- // Restore the previous dispatcher.
- nested_dispatcher_.reset();
- delegate_->OnMoveLoopEnded();
- grab_input_window_events_.reset();
- XDestroyWindow(display, grab_input_window_);
- grab_input_window_ = x11::None;
-
- in_move_loop_ = false;
- std::move(quit_closure_).Run();
-}
-
-bool X11WholeScreenMoveLoop::GrabPointer(gfx::NativeCursor cursor) {
- XDisplay* display = gfx::GetXDisplay();
-
- // Pass "owner_events" as false so that X sends all mouse events to
- // |grab_input_window_|.
- int ret = ui::GrabPointer(grab_input_window_, false, cursor.platform());
- if (ret != GrabSuccess) {
- DLOG(ERROR) << "Grabbing pointer for dragging failed: "
- << ui::GetX11ErrorString(display, ret);
- }
- XFlush(display);
- return ret == GrabSuccess;
-}
-
-void X11WholeScreenMoveLoop::GrabEscKey() {
- XDisplay* display = gfx::GetXDisplay();
- unsigned int esc_keycode = XKeysymToKeycode(display, XK_Escape);
- for (auto mask : kModifiersMasks) {
- XGrabKey(display, esc_keycode, mask, grab_input_window_, x11::False,
- GrabModeAsync, GrabModeAsync);
- }
-}
-
-void X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
- XSetWindowAttributes swa;
- memset(&swa, 0, sizeof(swa));
- swa.override_redirect = x11::True;
- grab_input_window_ = XCreateWindow(display, DefaultRootWindow(display), -100,
- -100, 10, 10, 0, CopyFromParent, InputOnly,
- CopyFromParent, CWOverrideRedirect, &swa);
- uint32_t event_mask = ButtonPressMask | ButtonReleaseMask |
- PointerMotionMask | KeyPressMask | KeyReleaseMask |
- StructureNotifyMask;
- grab_input_window_events_ = std::make_unique<ui::XScopedEventSelector>(
- grab_input_window_, event_mask);
-
- XMapRaised(display, grab_input_window_);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
deleted file mode 100644
index 1fa5bbd5cca..00000000000
--- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/events/platform/platform_event_dispatcher.h"
-#include "ui/gfx/geometry/vector2d_f.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/x/x11_types.h"
-#include "ui/views/widget/desktop_aura/x11_move_loop.h"
-#include "ui/views/widget/desktop_aura/x11_move_loop_delegate.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ui {
-class MouseEvent;
-class ScopedEventDispatcher;
-class XScopedEventSelector;
-} // namespace ui
-
-namespace views {
-
-// Runs a nested run loop and grabs the mouse. This is used to implement
-// dragging.
-class X11WholeScreenMoveLoop : public X11MoveLoop,
- public ui::PlatformEventDispatcher {
- public:
- explicit X11WholeScreenMoveLoop(X11MoveLoopDelegate* delegate);
- ~X11WholeScreenMoveLoop() override;
-
- // ui:::PlatformEventDispatcher:
- bool CanDispatchEvent(const ui::PlatformEvent& event) override;
- uint32_t DispatchEvent(const ui::PlatformEvent& event) override;
-
- // X11MoveLoop:
- bool RunMoveLoop(aura::Window* window, gfx::NativeCursor cursor) override;
- void UpdateCursor(gfx::NativeCursor cursor) override;
- void EndMoveLoop() override;
-
- private:
- // Grabs the pointer, setting the mouse cursor to |cursor|. Returns true if
- // successful.
- bool GrabPointer(gfx::NativeCursor cursor);
-
- void GrabEscKey();
-
- // Creates an input-only window to be used during the drag.
- void CreateDragInputWindow(XDisplay* display);
-
- // Dispatch mouse movement event to |delegate_| in a posted task.
- void DispatchMouseMovement();
-
- void PostDispatchIfNeeded(const ui::MouseEvent& event);
-
- X11MoveLoopDelegate* delegate_;
-
- // Are we running a nested run loop from RunMoveLoop()?
- bool in_move_loop_;
- std::unique_ptr<ui::ScopedEventDispatcher> nested_dispatcher_;
-
- // Cursor in use prior to the move loop starting. Restored when the move loop
- // quits.
- gfx::NativeCursor initial_cursor_;
-
- bool should_reset_mouse_flags_;
-
- // An invisible InputOnly window. Keyboard grab and sometimes mouse grab
- // are set on this window.
- XID grab_input_window_;
-
- // Events selected on |grab_input_window_|.
- std::unique_ptr<ui::XScopedEventSelector> grab_input_window_events_;
-
- // Whether the pointer was grabbed on |grab_input_window_|.
- bool grabbed_pointer_;
-
- base::OnceClosure quit_closure_;
-
- // Keeps track of whether the move-loop is cancled by the user (e.g. by
- // pressing escape).
- bool canceled_;
-
- std::unique_ptr<ui::MouseEvent> last_motion_in_screen_;
- base::WeakPtrFactory<X11WholeScreenMoveLoop> weak_factory_{this};
-
- DISALLOW_COPY_AND_ASSIGN(X11WholeScreenMoveLoop);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_X11_WHOLE_SCREEN_MOVE_LOOP_H_
diff --git a/chromium/ui/views/widget/desktop_widget_unittest.cc b/chromium/ui/views/widget/desktop_widget_unittest.cc
index 6295852a6cb..7eb0473bb00 100644
--- a/chromium/ui/views/widget/desktop_widget_unittest.cc
+++ b/chromium/ui/views/widget/desktop_widget_unittest.cc
@@ -64,7 +64,7 @@ TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) {
params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params2.child = true;
params2.native_widget = test::CreatePlatformNativeWidgetImpl(
- params2, &widget2, test::kStubCapture, nullptr);
+ &widget2, test::kStubCapture, nullptr);
widget2.Init(std::move(params2));
Widget::InitParams params3 = CreateParams(Widget::InitParams::TYPE_CONTROL);
@@ -73,7 +73,7 @@ TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) {
params3.child = true;
params3.bounds = gfx::Rect(origin, gfx::Size(500, work_area.height() - 200));
params3.native_widget = test::CreatePlatformNativeWidgetImpl(
- params3, &widget3, test::kStubCapture, nullptr);
+ &widget3, test::kStubCapture, nullptr);
widget3.Init(std::move(params3));
// The origin of the 3rd window should be the sum of all parent origins.
@@ -147,7 +147,7 @@ TEST_F(DesktopScreenPositionClientTest, InitialBoundsConstrainedToParent) {
params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params2.child = true;
params2.native_widget = test::CreatePlatformNativeWidgetImpl(
- params2, &widget2, test::kStubCapture, nullptr);
+ &widget2, test::kStubCapture, nullptr);
widget2.Init(std::move(params2));
// The bounds of the child window should be fully in the parent.
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index efd53803fa4..51f57997afa 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -1072,7 +1072,7 @@ void NativeWidgetAura::SetInitialFocus(ui::WindowShowState show_state) {
// Widget, public:
namespace {
-#if BUILDFLAG(ENABLE_DESKTOP_AURA)
+#if BUILDFLAG(ENABLE_DESKTOP_AURA) && (defined(OS_WIN) || defined(OS_LINUX))
void CloseWindow(aura::Window* window) {
if (window) {
Widget* widget = Widget::GetWidgetForNativeView(window);
diff --git a/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc b/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
index 6715dff1b73..6e13e1376a9 100644
--- a/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_interactive_uitest.cc
@@ -7,7 +7,6 @@
#include "ui/aura/window.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/native_widget_factory.h"
-#include "ui/views/test/views_interactive_ui_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/wm/core/base_focus_rules.h"
#include "ui/wm/core/focus_controller.h"
@@ -41,7 +40,7 @@ class TestFocusRules : public wm::BaseFocusRules {
} // namespace
-using NativeWidgetAuraTest = ViewsInteractiveUITestBase;
+using NativeWidgetAuraTest = DesktopWidgetTestInteractive;
// When requesting view focus from a non-active top level widget, focus is not
// instantly given. Instead, the view is firstly stored and then it is attempted
@@ -58,7 +57,7 @@ TEST_F(NativeWidgetAuraTest, NonActiveWindowRequestImeFocus) {
Widget::InitParams params1(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params1.context = GetContext();
params1.native_widget =
- CreatePlatformNativeWidgetImpl(params1, widget1, kDefault, nullptr);
+ CreatePlatformNativeWidgetImpl(widget1, kDefault, nullptr);
params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget1->Init(std::move(params1));
Textfield* textfield1 = new Textfield;
@@ -68,7 +67,7 @@ TEST_F(NativeWidgetAuraTest, NonActiveWindowRequestImeFocus) {
Widget::InitParams params2(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params2.context = GetContext();
params2.native_widget =
- CreatePlatformNativeWidgetImpl(params2, widget2, kDefault, nullptr);
+ CreatePlatformNativeWidgetImpl(widget2, kDefault, nullptr);
params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget2->Init(std::move(params2));
Textfield* textfield2a = new Textfield;
diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc
index 5bd2526da57..4e9ce929364 100644
--- a/chromium/ui/views/widget/native_widget_aura_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc
@@ -413,9 +413,9 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
widget->SetContentsView(view);
widget->Show();
- ui::TouchEvent press(
- ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1));
+ ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51),
+ ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::kTouch, 1));
ui::EventDispatchDetails details = event_sink()->OnEventFromSource(&press);
ASSERT_FALSE(details.dispatcher_destroyed);
// Both views should get the press.
@@ -428,9 +428,9 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
// Release touch. Only |view| should get the release since that it consumed
// the press.
- ui::TouchEvent release(
- ui::ET_TOUCH_RELEASED, gfx::Point(250, 251), ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1));
+ ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(250, 251),
+ ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::kTouch, 1));
details = event_sink()->OnEventFromSource(&release);
ASSERT_FALSE(details.dispatcher_destroyed);
EXPECT_TRUE(view->got_gesture_event());
diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm
index 90c111179a7..9a6b9ac6e90 100644
--- a/chromium/ui/views/widget/native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm
@@ -232,30 +232,6 @@ class WidgetChangeObserver : public TestWidgetObserver {
DISALLOW_COPY_AND_ASSIGN(WidgetChangeObserver);
};
-class NativeHostHolder {
- public:
- NativeHostHolder()
- : view_([[NSView alloc] init]), host_(new NativeViewHost()) {
- host_->set_owned_by_client();
- }
-
- void AttachNativeView() {
- DCHECK(!host_->native_view());
- host_->Attach(view_.get());
- }
-
- void Detach() { host_->Detach(); }
-
- NSView* view() const { return view_.get(); }
- NativeViewHost* host() const { return host_.get(); }
-
- private:
- base::scoped_nsobject<NSView> view_;
- std::unique_ptr<NativeViewHost> host_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeHostHolder);
-};
-
// This class gives public access to the protected ctor of
// BubbleDialogDelegateView.
class SimpleBubbleView : public BubbleDialogDelegateView {
@@ -1624,8 +1600,8 @@ class ParentCloseMonitor : public WidgetObserver {
Widget::InitParams init_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
init_params.parent = parent->GetNativeView();
init_params.bounds = gfx::Rect(100, 100, 100, 100);
- init_params.native_widget = CreatePlatformNativeWidgetImpl(
- init_params, child, kStubCapture, nullptr);
+ init_params.native_widget =
+ CreatePlatformNativeWidgetImpl(child, kStubCapture, nullptr);
child->Init(std::move(init_params));
child->Show();
@@ -1814,7 +1790,7 @@ TEST_F(NativeWidgetMacTest, DISABLED_DoesHideTitle) {
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
Widget* widget = new Widget;
params.native_widget =
- CreatePlatformNativeWidgetImpl(params, widget, kStubCapture, nullptr);
+ CreatePlatformNativeWidgetImpl(widget, kStubCapture, nullptr);
CustomTitleWidgetDelegate delegate(widget);
params.delegate = &delegate;
params.bounds = gfx::Rect(0, 0, 800, 600);
@@ -2247,6 +2223,29 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
NativeWidgetMacViewsOrderTest() {}
protected:
+ class NativeHostHolder {
+ public:
+ static std::unique_ptr<NativeHostHolder> CreateAndAddToParent(
+ View* parent) {
+ std::unique_ptr<NativeHostHolder> holder(new NativeHostHolder(
+ parent->AddChildView(std::make_unique<NativeViewHost>())));
+ holder->host()->Attach(holder->view());
+ return holder;
+ }
+
+ NSView* view() const { return view_.get(); }
+ NativeViewHost* host() const { return host_; }
+
+ private:
+ NativeHostHolder(NativeViewHost* host)
+ : host_(host), view_([[NSView alloc] init]) {}
+
+ NativeViewHost* const host_;
+ base::scoped_nsobject<NSView> view_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeHostHolder);
+ };
+
// testing::Test:
void SetUp() override {
WidgetTest::SetUp();
@@ -2261,10 +2260,8 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
const size_t kNativeViewCount = 3;
for (size_t i = 0; i < kNativeViewCount; ++i) {
- auto holder = std::make_unique<NativeHostHolder>();
- native_host_parent_->AddChildView(holder->host());
- holder->AttachNativeView();
- hosts_.push_back(std::move(holder));
+ hosts_.push_back(
+ NativeHostHolder::CreateAndAddToParent(native_host_parent_));
}
EXPECT_EQ(kNativeViewCount, native_host_parent_->children().size());
EXPECT_NSEQ([widget_->GetNativeView().GetNativeNSView() subviews],
@@ -2275,6 +2272,7 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
void TearDown() override {
widget_->CloseNow();
+ hosts_.clear();
WidgetTest::TearDown();
}
@@ -2296,13 +2294,14 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
// Test that NativeViewHost::Attach()/Detach() method saves the NativeView
// z-order.
TEST_F(NativeWidgetMacViewsOrderTest, NativeViewAttached) {
- hosts_[1]->Detach();
+ NativeHostHolder* second_host = hosts_[1].get();
+ second_host->host()->Detach();
EXPECT_NSEQ([GetContentNativeView() subviews],
([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
hosts_[0]->view(), hosts_[2]->view()
]]));
- hosts_[1]->AttachNativeView();
+ second_host->host()->Attach(second_host->view());
EXPECT_NSEQ([GetContentNativeView() subviews],
([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view()
diff --git a/chromium/ui/views/widget/tooltip_manager_aura.cc b/chromium/ui/views/widget/tooltip_manager_aura.cc
index ca24a4c51b5..2aceae76419 100644
--- a/chromium/ui/views/widget/tooltip_manager_aura.cc
+++ b/chromium/ui/views/widget/tooltip_manager_aura.cc
@@ -4,7 +4,6 @@
#include "ui/views/widget/tooltip_manager_aura.h"
-#include "base/logging.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index 6472b4210a0..ecd7be9185f 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -8,9 +8,10 @@
#include <utility>
#include "base/auto_reset.h"
+#include "base/check_op.h"
#include "base/containers/adapters.h"
-#include "base/logging.h"
#include "base/macros.h"
+#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "ui/base/cursor/cursor.h"
@@ -92,19 +93,18 @@ bool Widget::g_disable_activation_change_handling_ = false;
// WidgetDelegate is supplied.
class DefaultWidgetDelegate : public WidgetDelegate {
public:
- explicit DefaultWidgetDelegate(Widget* widget) : widget_(widget) {}
+ explicit DefaultWidgetDelegate(Widget* widget) : widget_(widget) {
+ // In most situations where a Widget is used without a delegate the Widget
+ // is used as a container, so that we want focus to advance to the top-level
+ // widget. A good example of this is the find bar.
+ SetFocusTraversesOut(true);
+ }
~DefaultWidgetDelegate() override = default;
// WidgetDelegate:
void DeleteDelegate() override { delete this; }
Widget* GetWidget() override { return widget_; }
const Widget* GetWidget() const override { return widget_; }
- bool ShouldAdvanceFocusToTopLevelWidget() const override {
- // In most situations where a Widget is used without a delegate the Widget
- // is used as a container, so that we want focus to advance to the top-level
- // widget. A good example of this is the find bar.
- return true;
- }
private:
Widget* widget_;
@@ -162,10 +162,8 @@ ui::ZOrderLevel Widget::InitParams::EffectiveZOrderLevel() const {
switch (type) {
case TYPE_MENU:
return ui::ZOrderLevel::kFloatingWindow;
- break;
case TYPE_DRAG:
return ui::ZOrderLevel::kFloatingUIElement;
- break;
default:
return ui::ZOrderLevel::kNormal;
}
@@ -769,7 +767,7 @@ bool Widget::IsVisible() const {
const ui::ThemeProvider* Widget::GetThemeProvider() const {
const Widget* root_widget = GetTopLevelWidget();
return (root_widget && root_widget != this) ? root_widget->GetThemeProvider()
- : &default_theme_provider_;
+ : nullptr;
}
FocusManager* Widget::GetFocusManager() {
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index 105fc39ed5e..0cbc349dd3d 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -16,7 +16,6 @@
#include "base/optional.h"
#include "base/scoped_observer.h"
#include "build/build_config.h"
-#include "ui/base/default_theme_provider.h"
#include "ui/base/ui_base_types.h"
#include "ui/events/event_source.h"
#include "ui/gfx/geometry/rect.h"
@@ -498,7 +497,18 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Sets the specified view as the contents of this Widget. There can only
// be one contents view child of this Widget's RootView. This view is sized to
// fit the entire size of the RootView. The RootView takes ownership of this
- // View, unless it is set as not being parent-owned.
+ // View, unless it is passed in as a raw pointer and set as not being
+ // parent-owned. Prefer using SetContentsView(std::unique_ptr) over passing a
+ // raw pointer for new code.
+ template <typename T>
+ T* SetContentsView(std::unique_ptr<T> view) {
+ DCHECK(!view->owned_by_client())
+ << "This should only be called if the client is passing over the "
+ "ownership of |view|.";
+ T* raw_pointer = view.get();
+ SetContentsView(view.release());
+ return raw_pointer;
+ }
void SetContentsView(View* view);
// NOTE: This may not be the same view as WidgetDelegate::GetContentsView().
@@ -1050,9 +1060,6 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// must be destroyed AFTER root_view_. This is enforced in DestroyRootView().
std::unique_ptr<FocusManager> focus_manager_;
- // A theme provider to use when no other theme provider is specified.
- const ui::DefaultThemeProvider default_theme_provider_;
-
// Valid for the lifetime of RunShellDrag(), indicates the view the drag
// started from.
View* dragged_view_ = nullptr;
diff --git a/chromium/ui/views/widget/widget_aura_utils.cc b/chromium/ui/views/widget/widget_aura_utils.cc
index 85cedf9f62b..424460fe0ed 100644
--- a/chromium/ui/views/widget/widget_aura_utils.cc
+++ b/chromium/ui/views/widget/widget_aura_utils.cc
@@ -4,7 +4,7 @@
#include "ui/views/widget/widget_aura_utils.h"
-#include "base/logging.h"
+#include "base/notreached.h"
namespace views {
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
index 1d7c735d497..4ba80f860b3 100644
--- a/chromium/ui/views/widget/widget_delegate.cc
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -4,7 +4,7 @@
#include "ui/views/widget/widget_delegate.h"
-#include "base/logging.h"
+#include "base/check.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/display/display.h"
@@ -20,6 +20,9 @@ namespace views {
////////////////////////////////////////////////////////////////////////////////
// WidgetDelegate:
+WidgetDelegate::Params::Params() = default;
+WidgetDelegate::Params::~Params() = default;
+
WidgetDelegate::WidgetDelegate() = default;
WidgetDelegate::~WidgetDelegate() {
CHECK(can_delete_this_) << "A WidgetDelegate must outlive its Widget";
@@ -52,15 +55,15 @@ DialogDelegate* WidgetDelegate::AsDialogDelegate() {
}
bool WidgetDelegate::CanResize() const {
- return false;
+ return params_.can_resize;
}
bool WidgetDelegate::CanMaximize() const {
- return false;
+ return params_.can_maximize;
}
bool WidgetDelegate::CanMinimize() const {
- return false;
+ return params_.can_minimize;
}
bool WidgetDelegate::CanActivate() const {
@@ -80,19 +83,23 @@ base::string16 WidgetDelegate::GetAccessibleWindowTitle() const {
}
base::string16 WidgetDelegate::GetWindowTitle() const {
- return base::string16();
+ return params_.title;
}
bool WidgetDelegate::ShouldShowWindowTitle() const {
- return true;
+ return params_.show_title;
}
bool WidgetDelegate::ShouldCenterWindowTitleText() const {
+#if defined(USE_AURA)
+ return params_.center_title;
+#else
return false;
+#endif
}
bool WidgetDelegate::ShouldShowCloseButton() const {
- return true;
+ return params_.show_close_button;
}
gfx::ImageSkia WidgetDelegate::GetWindowAppIcon() {
@@ -102,11 +109,11 @@ gfx::ImageSkia WidgetDelegate::GetWindowAppIcon() {
// Returns the icon to be displayed in the window.
gfx::ImageSkia WidgetDelegate::GetWindowIcon() {
- return gfx::ImageSkia();
+ return params_.icon;
}
bool WidgetDelegate::ShouldShowWindowIcon() const {
- return false;
+ return params_.show_icon;
}
bool WidgetDelegate::ExecuteWindowsCommand(int command_id) {
@@ -145,6 +152,24 @@ bool WidgetDelegate::ShouldRestoreWindowSize() const {
return true;
}
+void WidgetDelegate::WindowWillClose() {
+ // TODO(ellyjones): For this and the other callback methods, establish whether
+ // any other code calls these methods. If not, DCHECK here and below that
+ // these methods are only called once.
+ for (auto&& callback : window_will_close_callbacks_)
+ std::move(callback).Run();
+}
+
+void WidgetDelegate::WindowClosing() {
+ for (auto&& callback : window_closing_callbacks_)
+ std::move(callback).Run();
+}
+
+void WidgetDelegate::DeleteDelegate() {
+ for (auto&& callback : delete_delegate_callbacks_)
+ std::move(callback).Run();
+}
+
View* WidgetDelegate::GetContentsView() {
if (!default_contents_view_)
default_contents_view_ = new View;
@@ -175,16 +200,72 @@ void WidgetDelegate::GetWidgetHitTestMask(SkPath* mask) const {
DCHECK(mask);
}
-bool WidgetDelegate::ShouldAdvanceFocusToTopLevelWidget() const {
- return false;
-}
-
bool WidgetDelegate::ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
const gfx::Point& location) {
return true;
}
+void WidgetDelegate::SetCanMaximize(bool can_maximize) {
+ params_.can_maximize = can_maximize;
+}
+
+void WidgetDelegate::SetCanMinimize(bool can_minimize) {
+ params_.can_minimize = can_minimize;
+}
+
+void WidgetDelegate::SetCanResize(bool can_resize) {
+ params_.can_resize = can_resize;
+}
+
+void WidgetDelegate::SetFocusTraversesOut(bool focus_traverses_out) {
+ params_.focus_traverses_out = focus_traverses_out;
+}
+
+void WidgetDelegate::SetIcon(const gfx::ImageSkia& icon) {
+ params_.icon = icon;
+}
+
+void WidgetDelegate::SetShowCloseButton(bool show_close_button) {
+ params_.show_close_button = show_close_button;
+}
+
+void WidgetDelegate::SetShowIcon(bool show_icon) {
+ params_.show_icon = show_icon;
+}
+
+void WidgetDelegate::SetShowTitle(bool show_title) {
+ params_.show_title = show_title;
+}
+
+void WidgetDelegate::SetTitle(const base::string16& title) {
+ if (params_.title == title)
+ return;
+ params_.title = title;
+ if (GetWidget())
+ GetWidget()->UpdateWindowTitle();
+}
+
+#if defined(USE_AURA)
+void WidgetDelegate::SetCenterTitle(bool center_title) {
+ params_.center_title = center_title;
+}
+#endif
+
+void WidgetDelegate::RegisterWindowWillCloseCallback(
+ base::OnceClosure callback) {
+ window_will_close_callbacks_.emplace_back(std::move(callback));
+}
+
+void WidgetDelegate::RegisterWindowClosingCallback(base::OnceClosure callback) {
+ window_closing_callbacks_.emplace_back(std::move(callback));
+}
+
+void WidgetDelegate::RegisterDeleteDelegateCallback(
+ base::OnceClosure callback) {
+ delete_delegate_callbacks_.emplace_back(std::move(callback));
+}
+
////////////////////////////////////////////////////////////////////////////////
// WidgetDelegateView:
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
index a3ec229f11c..23396ad8c3a 100644
--- a/chromium/ui/views/widget/widget_delegate.h
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -29,6 +29,44 @@ class View;
// Handles events on Widgets in context-specific ways.
class VIEWS_EXPORT WidgetDelegate {
public:
+ struct Params {
+ Params();
+ ~Params();
+
+ // Whether the window should display controls for the user to minimize,
+ // maximize, or resize it.
+ bool can_maximize = false;
+ bool can_minimize = false;
+ bool can_resize = false;
+
+#if defined(USE_AURA)
+ // Whether to center the widget's title within the frame.
+ bool center_title = false;
+#endif
+
+ // Controls focus traversal past the first/last focusable view.
+ // If true, focus moves out of this Widget and to this Widget's toplevel
+ // Widget; if false, focus cycles within this Widget.
+ bool focus_traverses_out = false;
+
+ // The widget's icon, if any.
+ gfx::ImageSkia icon;
+
+ // Whether to show a close button in the widget frame.
+ bool show_close_button = true;
+
+ // Whether to show the widget's icon.
+ // TODO(ellyjones): What if this was implied by !icon.isNull()?
+ bool show_icon = false;
+
+ // Whether to display the widget's title in the frame.
+ bool show_title = true;
+
+ // The widget's title, if any.
+ // TODO(ellyjones): Should it be illegal to have show_title && !title?
+ base::string16 title;
+ };
+
WidgetDelegate();
// Sets the return value of CanActivate(). Default is true.
@@ -90,9 +128,6 @@ class VIEWS_EXPORT WidgetDelegate {
// Returns true if the window should show a title in the title bar.
virtual bool ShouldShowWindowTitle() const;
- // Returns true if the title text should be centered. Default is false.
- virtual bool ShouldCenterWindowTitleText() const;
-
// Returns true if the window should show a close button in the title bar.
virtual bool ShouldShowCloseButton() const;
@@ -146,9 +181,12 @@ class VIEWS_EXPORT WidgetDelegate {
// Close() or CloseNow().
// Important note: for OS-initiated window closes, steps 1 and 2 don't happen
// - i.e, WindowWillClose() is never invoked.
- virtual void WindowWillClose() {}
- virtual void WindowClosing() {}
- virtual void DeleteDelegate() {}
+ //
+ // The default implementations of these methods simply call the corresponding
+ // callbacks; see Set*Callback() below. If you override these it is not
+ // necessary to call the base implementations.
+ virtual void WindowClosing();
+ virtual void DeleteDelegate();
// Called when the user begins/ends to change the bounds of the window.
virtual void OnWindowBeginUserBoundsChange() {}
@@ -187,11 +225,6 @@ class VIEWS_EXPORT WidgetDelegate {
// Provides the hit-test mask if HasHitTestMask above returns true.
virtual void GetWidgetHitTestMask(SkPath* mask) const;
- // Returns true if focus should advance to the top level widget when
- // tab/shift-tab is hit and on the last/first focusable view. Default returns
- // false, which means tab/shift-tab never advance to the top level Widget.
- virtual bool ShouldAdvanceFocusToTopLevelWidget() const;
-
// Returns true if event handling should descend into |child|.
// |location| is in terms of the Window.
virtual bool ShouldDescendIntoChildForEventHandling(
@@ -202,18 +235,52 @@ class VIEWS_EXPORT WidgetDelegate {
// be cycled through with keyboard focus.
virtual void GetAccessiblePanes(std::vector<View*>* panes) {}
+ // Setters for data parameters of the WidgetDelegate. If you use these
+ // setters, there is no need to override the corresponding virtual getters.
+ void SetCanMaximize(bool can_maximize);
+ void SetCanMinimize(bool can_minimize);
+ void SetCanResize(bool can_resize);
+ void SetFocusTraversesOut(bool focus_traverses_out);
+ void SetIcon(const gfx::ImageSkia& icon);
+ void SetShowCloseButton(bool show_close_button);
+ void SetShowIcon(bool show_icon);
+ void SetShowTitle(bool show_title);
+ void SetTitle(const base::string16& title);
+#if defined(USE_AURA)
+ void SetCenterTitle(bool center_title);
+#endif
+
+ void RegisterWindowWillCloseCallback(base::OnceClosure callback);
+ void RegisterWindowClosingCallback(base::OnceClosure callback);
+ void RegisterDeleteDelegateCallback(base::OnceClosure callback);
+
+ // Call this to notify the WidgetDelegate that its Widget is about to start
+ // closing.
+ void WindowWillClose();
+
+ // Returns true if the title text should be centered.
+ bool ShouldCenterWindowTitleText() const;
+
+ bool focus_traverses_out() const { return params_.focus_traverses_out; }
+
protected:
virtual ~WidgetDelegate();
private:
friend class Widget;
+ Params params_;
+
View* default_contents_view_ = nullptr;
bool can_activate_ = true;
// Managed by Widget. Ensures |this| outlives its Widget.
bool can_delete_this_ = true;
+ std::vector<base::OnceClosure> window_will_close_callbacks_;
+ std::vector<base::OnceClosure> window_closing_callbacks_;
+ std::vector<base::OnceClosure> delete_delegate_callbacks_;
+
DISALLOW_COPY_AND_ASSIGN(WidgetDelegate);
};
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index 0f50819e3c4..f4ba5ba6cad 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -29,12 +29,12 @@
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_test_api.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/test/focus_manager_test.h"
#include "ui/views/test/native_widget_factory.h"
-#include "ui/views/test/views_interactive_ui_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/touchui/touch_selection_controller_impl.h"
#include "ui/views/widget/root_view.h"
@@ -290,39 +290,6 @@ class WidgetTestInteractive : public WidgetTest {
SetUpForInteractiveTests();
WidgetTest::SetUp();
}
-
- protected:
-#if defined(USE_AURA)
- static void ShowQuickMenuImmediately(
- TouchSelectionControllerImpl* controller) {
- DCHECK(controller);
- if (controller->quick_menu_timer_.IsRunning()) {
- controller->quick_menu_timer_.Stop();
- controller->QuickMenuTimerFired();
- }
- }
-#endif // defined (USE_AURA)
-};
-
-class DesktopWidgetTestInteractive : public WidgetTestInteractive {
- public:
- DesktopWidgetTestInteractive() = default;
- ~DesktopWidgetTestInteractive() override = default;
-
- // WidgetTestInteractive:
- void SetUp() override {
- set_native_widget_type(NativeWidgetType::kDesktop);
- WidgetTestInteractive::SetUp();
- }
-
- protected:
- Widget* CreateWidget() {
- Widget* widget = CreateTopLevelNativeWidget();
- widget->SetBounds(gfx::Rect(0, 0, 200, 200));
- return widget;
- }
-
- DISALLOW_COPY_AND_ASSIGN(DesktopWidgetTestInteractive);
};
#if defined(OS_WIN)
@@ -340,10 +307,10 @@ TEST_F(DesktopWidgetTestInteractive,
// Create widget 1 and expect the active window to be its window.
View* focusable_view1 = new View;
focusable_view1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- Widget* widget1 = CreateWidget();
+ WidgetAutoclosePtr widget1(CreateTopLevelNativeWidget());
widget1->GetContentsView()->AddChildView(focusable_view1);
widget1->Show();
- aura::Window* root_window1 = GetRootWindow(widget1);
+ aura::Window* root_window1 = GetRootWindow(widget1.get());
focusable_view1->RequestFocus();
EXPECT_TRUE(root_window1 != nullptr);
@@ -354,12 +321,12 @@ TEST_F(DesktopWidgetTestInteractive,
// Create widget 2 and expect the active window to be its window.
View* focusable_view2 = new View;
- Widget* widget2 = CreateWidget();
+ WidgetAutoclosePtr widget2(CreateTopLevelNativeWidget());
widget1->GetContentsView()->AddChildView(focusable_view2);
widget2->Show();
- aura::Window* root_window2 = GetRootWindow(widget2);
+ aura::Window* root_window2 = GetRootWindow(widget2.get());
focusable_view2->RequestFocus();
- ActivatePlatformWindow(widget2);
+ ActivatePlatformWindow(widget2.get());
wm::ActivationClient* activation_client2 =
wm::GetActivationClient(root_window2);
@@ -371,13 +338,41 @@ TEST_F(DesktopWidgetTestInteractive,
// Now set focus back to widget 1 and expect the active window to be its
// window.
focusable_view1->RequestFocus();
- ActivatePlatformWindow(widget1);
+ ActivatePlatformWindow(widget1.get());
EXPECT_EQ(activation_client2->GetActiveWindow(),
reinterpret_cast<aura::Window*>(NULL));
EXPECT_EQ(activation_client1->GetActiveWindow(), widget1->GetNativeView());
+}
- widget2->CloseNow();
- widget1->CloseNow();
+// Verifies bubbles result in a focus lost when shown.
+TEST_F(DesktopWidgetTestInteractive, FocusChangesOnBubble) {
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+ View* focusable_view =
+ widget->GetContentsView()->AddChildView(std::make_unique<View>());
+ focusable_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+ widget->Show();
+ focusable_view->RequestFocus();
+ EXPECT_TRUE(focusable_view->HasFocus());
+
+ // Show a bubble.
+ auto owned_bubble_delegate_view =
+ std::make_unique<views::BubbleDialogDelegateView>(focusable_view,
+ BubbleBorder::NONE);
+ owned_bubble_delegate_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+ BubbleDialogDelegateView* bubble_delegate_view =
+ owned_bubble_delegate_view.get();
+ BubbleDialogDelegateView::CreateBubble(owned_bubble_delegate_view.release())
+ ->Show();
+ bubble_delegate_view->RequestFocus();
+
+ // |focusable_view| should no longer have focus.
+ EXPECT_FALSE(focusable_view->HasFocus());
+ EXPECT_TRUE(bubble_delegate_view->HasFocus());
+
+ bubble_delegate_view->GetWidget()->CloseNow();
+
+ // Closing the bubble should result in focus going back to the contents view.
+ EXPECT_TRUE(focusable_view->HasFocus());
}
class TouchEventHandler : public ui::EventHandler {
@@ -433,210 +428,23 @@ TEST_F(DesktopWidgetTestInteractive, DISABLED_TouchNoActivateWindow) {
View* focusable_view = new View;
focusable_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- Widget* widget = CreateWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
widget->GetContentsView()->AddChildView(focusable_view);
widget->Show();
{
- TouchEventHandler touch_event_handler(widget);
+ TouchEventHandler touch_event_handler(widget.get());
ASSERT_TRUE(ui_controls::SendTouchEvents(ui_controls::PRESS, 1, 100, 100));
touch_event_handler.WaitForEvents();
}
-
- widget->CloseNow();
}
#endif // defined(OS_WIN)
-TEST_F(WidgetTestInteractive, CaptureAutoReset) {
- Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
- View* container = new View;
- toplevel->SetContentsView(container);
-
- EXPECT_FALSE(toplevel->HasCapture());
- toplevel->SetCapture(nullptr);
- EXPECT_TRUE(toplevel->HasCapture());
-
- // By default, mouse release removes capture.
- gfx::Point click_location(45, 15);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON);
- toplevel->OnMouseEvent(&release);
- EXPECT_FALSE(toplevel->HasCapture());
-
- // Now a mouse release shouldn't remove capture.
- toplevel->set_auto_release_capture(false);
- toplevel->SetCapture(nullptr);
- EXPECT_TRUE(toplevel->HasCapture());
- toplevel->OnMouseEvent(&release);
- EXPECT_TRUE(toplevel->HasCapture());
- toplevel->ReleaseCapture();
- EXPECT_FALSE(toplevel->HasCapture());
-
- toplevel->Close();
- RunPendingMessages();
-}
-
-TEST_F(WidgetTestInteractive, ResetCaptureOnGestureEnd) {
- Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
- View* container = new View;
- toplevel->SetContentsView(container);
-
- View* gesture = new GestureCaptureView;
- gesture->SetBounds(0, 0, 30, 30);
- container->AddChildView(gesture);
-
- MouseView* mouse = new MouseView;
- mouse->SetBounds(30, 0, 30, 30);
- container->AddChildView(mouse);
-
- toplevel->SetSize(gfx::Size(100, 100));
- toplevel->Show();
-
- // Start a gesture on |gesture|.
- ui::GestureEvent tap_down(15, 15, 0, base::TimeTicks(),
- ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
- ui::GestureEvent end(15, 15, 0, base::TimeTicks(),
- ui::GestureEventDetails(ui::ET_GESTURE_END));
- toplevel->OnGestureEvent(&tap_down);
-
- // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
- // will not receive the event.
- gfx::Point click_location(45, 15);
-
- ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON);
- ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON);
-
- EXPECT_TRUE(toplevel->HasCapture());
-
- toplevel->OnMouseEvent(&press);
- toplevel->OnMouseEvent(&release);
- EXPECT_EQ(0, mouse->pressed());
-
- EXPECT_FALSE(toplevel->HasCapture());
-
- // The end of the gesture should release the capture, and pressing on |mouse|
- // should now reach |mouse|.
- toplevel->OnGestureEvent(&end);
- toplevel->OnMouseEvent(&press);
- toplevel->OnMouseEvent(&release);
- EXPECT_EQ(1, mouse->pressed());
-
- toplevel->Close();
- RunPendingMessages();
-}
-
-// Checks that if a mouse-press triggers a capture on a different widget (which
-// consumes the mouse-release event), then the target of the press does not have
-// capture.
-TEST_F(WidgetTestInteractive, DisableCaptureWidgetFromMousePress) {
- // The test creates two widgets: |first| and |second|.
- // The View in |first| makes |second| visible, sets capture on it, and starts
- // a nested loop (like a menu does). The View in |second| terminates the
- // nested loop and closes the widget.
- // The test sends a mouse-press event to |first|, and posts a task to send a
- // release event to |second|, to make sure that the release event is
- // dispatched after the nested loop starts.
-
- Widget* first = CreateTopLevelFramelessPlatformWidget();
- Widget* second = CreateTopLevelFramelessPlatformWidget();
-
- NestedLoopCaptureView* container = new NestedLoopCaptureView(second);
- first->SetContentsView(container);
-
- second->SetContentsView(new ExitLoopOnRelease(container->GetQuitClosure()));
-
- first->SetSize(gfx::Size(100, 100));
- first->Show();
-
- gfx::Point location(20, 20);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(
- &Widget::OnMouseEvent, base::Unretained(second),
- base::Owned(new ui::MouseEvent(
- ui::ET_MOUSE_RELEASED, location, location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON))));
- ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON);
- first->OnMouseEvent(&press);
- EXPECT_FALSE(first->HasCapture());
- first->Close();
- RunPendingMessages();
-}
-
-// Tests some grab/ungrab events.
-// TODO(estade): can this be enabled now that this is an interactive ui test?
-TEST_F(WidgetTestInteractive, DISABLED_GrabUngrab) {
- Widget* toplevel = CreateTopLevelPlatformWidget();
- Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
- Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
-
- toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
-
- child1->SetBounds(gfx::Rect(10, 10, 300, 300));
- View* view = new MouseView();
- view->SetBounds(0, 0, 300, 300);
- child1->GetRootView()->AddChildView(view);
-
- child2->SetBounds(gfx::Rect(200, 10, 200, 200));
- view = new MouseView();
- view->SetBounds(0, 0, 200, 200);
- child2->GetRootView()->AddChildView(view);
-
- toplevel->Show();
- RunPendingMessages();
-
- // Click on child1
- gfx::Point p1(45, 45);
- ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
- toplevel->OnMouseEvent(&pressed);
-
- EXPECT_TRUE(toplevel->HasCapture());
- EXPECT_TRUE(child1->HasCapture());
- EXPECT_FALSE(child2->HasCapture());
-
- ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
- toplevel->OnMouseEvent(&released);
-
- EXPECT_FALSE(toplevel->HasCapture());
- EXPECT_FALSE(child1->HasCapture());
- EXPECT_FALSE(child2->HasCapture());
-
- RunPendingMessages();
-
- // Click on child2
- gfx::Point p2(315, 45);
- ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
- toplevel->OnMouseEvent(&pressed2);
- EXPECT_TRUE(pressed2.handled());
- EXPECT_TRUE(toplevel->HasCapture());
- EXPECT_TRUE(child2->HasCapture());
- EXPECT_FALSE(child1->HasCapture());
-
- ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
- toplevel->OnMouseEvent(&released2);
- EXPECT_FALSE(toplevel->HasCapture());
- EXPECT_FALSE(child1->HasCapture());
- EXPECT_FALSE(child2->HasCapture());
-
- toplevel->CloseNow();
-}
-
// Tests mouse move outside of the window into the "resize controller" and back
// will still generate an OnMouseEntered and OnMouseExited event..
TEST_F(WidgetTestInteractive, CheckResizeControllerEvents) {
- Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
+ WidgetAutoclosePtr toplevel(CreateTopLevelFramelessPlatformWidget());
toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
@@ -678,20 +486,16 @@ TEST_F(WidgetTestInteractive, CheckResizeControllerEvents) {
toplevel->OnMouseEvent(&moved_over);
EXPECT_EQ(1, view->EnteredCalls());
EXPECT_EQ(0, view->ExitedCalls());
-
- RunPendingMessages();
-
- toplevel->CloseNow();
}
// Test view focus restoration when a widget is deactivated and re-activated.
TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) {
- Widget* widget1 = CreateTopLevelPlatformWidget();
+ WidgetAutoclosePtr widget1(CreateTopLevelPlatformWidget());
View* view1 = new View;
view1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
widget1->GetContentsView()->AddChildView(view1);
- Widget* widget2 = CreateTopLevelPlatformWidget();
+ WidgetAutoclosePtr widget2(CreateTopLevelPlatformWidget());
View* view2a = new View;
View* view2b = new View;
view2a->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -699,12 +503,12 @@ TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) {
widget2->GetContentsView()->AddChildView(view2a);
widget2->GetContentsView()->AddChildView(view2b);
- ShowSync(widget1);
+ ShowSync(widget1.get());
EXPECT_TRUE(widget1->IsActive());
view1->RequestFocus();
EXPECT_EQ(view1, widget1->GetFocusManager()->GetFocusedView());
- ShowSync(widget2);
+ ShowSync(widget2.get());
EXPECT_TRUE(widget2->IsActive());
EXPECT_FALSE(widget1->IsActive());
EXPECT_EQ(nullptr, widget1->GetFocusManager()->GetFocusedView());
@@ -713,20 +517,17 @@ TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) {
view2b->RequestFocus();
EXPECT_EQ(view2b, widget2->GetFocusManager()->GetFocusedView());
- ActivateSync(widget1);
+ ActivateSync(widget1.get());
EXPECT_TRUE(widget1->IsActive());
EXPECT_EQ(view1, widget1->GetFocusManager()->GetFocusedView());
EXPECT_FALSE(widget2->IsActive());
EXPECT_EQ(nullptr, widget2->GetFocusManager()->GetFocusedView());
- ActivateSync(widget2);
+ ActivateSync(widget2.get());
EXPECT_TRUE(widget2->IsActive());
EXPECT_EQ(view2b, widget2->GetFocusManager()->GetFocusedView());
EXPECT_FALSE(widget1->IsActive());
EXPECT_EQ(nullptr, widget1->GetFocusManager()->GetFocusedView());
-
- widget1->CloseNow();
- widget2->CloseNow();
}
// Test z-order of child widgets relative to their parent.
@@ -801,7 +602,7 @@ TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) {
// Test view focus retention when a widget's HWND is disabled and re-enabled.
TEST_F(WidgetTestInteractive, ViewFocusOnHWNDEnabledChanges) {
- Widget* widget = CreateTopLevelFramelessPlatformWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelFramelessPlatformWidget());
widget->SetContentsView(new View);
for (size_t i = 0; i < 2; ++i) {
auto child = std::make_unique<View>();
@@ -811,7 +612,7 @@ TEST_F(WidgetTestInteractive, ViewFocusOnHWNDEnabledChanges) {
widget->Show();
widget->GetNativeWindow()->GetHost()->Show();
- const HWND hwnd = HWNDForWidget(widget);
+ const HWND hwnd = HWNDForWidget(widget.get());
EXPECT_TRUE(::IsWindow(hwnd));
EXPECT_TRUE(::IsWindowEnabled(hwnd));
EXPECT_EQ(hwnd, ::GetActiveWindow());
@@ -836,8 +637,6 @@ TEST_F(WidgetTestInteractive, ViewFocusOnHWNDEnabledChanges) {
EXPECT_TRUE(widget->IsActive());
EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
}
-
- widget->CloseNow();
}
// This class subclasses the Widget class to listen for activation change
@@ -1089,61 +888,6 @@ TEST_F(DesktopWidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
}
#endif
-// Disabled on Mac. Desktop Mac doesn't have system modal windows since Carbon
-// was deprecated. It does have application modal windows, but only Ash requests
-// those.
-#if defined(OS_MACOSX)
-#define MAYBE_SystemModalWindowReleasesCapture \
- DISABLED_SystemModalWindowReleasesCapture
-#elif defined(OS_CHROMEOS)
-// Investigate enabling for Chrome OS. It probably requires help from the window
-// service.
-#define MAYBE_SystemModalWindowReleasesCapture \
- DISABLED_SystemModalWindowReleasesCapture
-#else
-#define MAYBE_SystemModalWindowReleasesCapture SystemModalWindowReleasesCapture
-#endif
-
-// Test that when opening a system-modal window, capture is released.
-TEST_F(DesktopWidgetTestInteractive, MAYBE_SystemModalWindowReleasesCapture) {
- TestWidgetFocusChangeListener focus_listener;
- WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener);
-
- // Create a top level widget.
- Widget top_level_widget;
- Widget::InitParams init_params =
- CreateParams(Widget::InitParams::TYPE_WINDOW);
- init_params.show_state = ui::SHOW_STATE_NORMAL;
- gfx::Rect initial_bounds(0, 0, 500, 500);
- init_params.bounds = initial_bounds;
- init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- top_level_widget.Init(std::move(init_params));
- ShowSync(&top_level_widget);
-
- ASSERT_FALSE(focus_listener.focus_changes().empty());
- EXPECT_EQ(top_level_widget.GetNativeView(),
- focus_listener.focus_changes().back());
-
- EXPECT_FALSE(top_level_widget.HasCapture());
- top_level_widget.SetCapture(nullptr);
- EXPECT_TRUE(top_level_widget.HasCapture());
-
- // Create a modal dialog.
- ModalDialogDelegate* dialog_delegate =
- new ModalDialogDelegate(ui::MODAL_TYPE_SYSTEM);
-
- Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
- dialog_delegate, nullptr, top_level_widget.GetNativeView());
- modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
- ShowSync(modal_dialog_widget);
-
- EXPECT_FALSE(top_level_widget.HasCapture());
-
- modal_dialog_widget->CloseNow();
- top_level_widget.CloseNow();
- WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(&focus_listener);
-}
-
TEST_F(DesktopWidgetTestInteractive, CanActivateFlagIsHonored) {
Widget widget;
Widget::InitParams init_params =
@@ -1171,7 +915,8 @@ TEST_F(DesktopWidgetTestInteractive, CanActivateFlagIsHonored) {
// Test that touch selection quick menu is not activated when opened.
TEST_F(DesktopWidgetTestInteractive,
MAYBE_TouchSelectionQuickMenuIsNotActivated) {
- Widget* widget = CreateWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+ widget->SetBounds(gfx::Rect(0, 0, 200, 200));
Textfield* textfield = new Textfield;
textfield->SetBounds(0, 0, 200, 20);
@@ -1185,16 +930,16 @@ TEST_F(DesktopWidgetTestInteractive,
RunPendingMessages();
- ui::test::EventGenerator generator(GetRootWindow(widget));
+ ui::test::EventGenerator generator(GetRootWindow(widget.get()));
generator.GestureTapAt(textfield->GetBoundsInScreen().origin() +
gfx::Vector2d(10, 10));
- ShowQuickMenuImmediately(static_cast<TouchSelectionControllerImpl*>(
- textfield_test_api.touch_selection_controller()));
+ static_cast<TouchSelectionControllerImpl*>(
+ textfield_test_api.touch_selection_controller())
+ ->ShowQuickMenuImmediatelyForTesting();
EXPECT_TRUE(textfield->HasFocus());
EXPECT_TRUE(widget->IsActive());
EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
- widget->CloseNow();
}
#endif // defined(USE_AURA)
@@ -1253,90 +998,76 @@ TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) {
} // namespace test
TEST_F(WidgetTestInteractive, ShowCreatesActiveWindow) {
- Widget* widget = CreateTopLevelPlatformWidget();
-
- ShowSync(widget);
- EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+ WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
- widget->CloseNow();
+ ShowSync(widget.get());
+ EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
}
TEST_F(WidgetTestInteractive, ShowInactive) {
WidgetTest::WaitForSystemAppActivation();
- Widget* widget = CreateTopLevelPlatformWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
- ShowInactiveSync(widget);
- EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
-
- widget->CloseNow();
+ ShowInactiveSync(widget.get());
+ EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_INACTIVE);
}
TEST_F(WidgetTestInteractive, InactiveBeforeShow) {
- Widget* widget = CreateTopLevelPlatformWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
EXPECT_FALSE(widget->IsActive());
EXPECT_FALSE(widget->IsVisible());
- ShowSync(widget);
+ ShowSync(widget.get());
EXPECT_TRUE(widget->IsActive());
EXPECT_TRUE(widget->IsVisible());
-
- widget->CloseNow();
}
TEST_F(WidgetTestInteractive, ShowInactiveAfterShow) {
// Create 2 widgets to ensure window layering does not change.
- Widget* widget = CreateTopLevelPlatformWidget();
- Widget* widget2 = CreateTopLevelPlatformWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
+ WidgetAutoclosePtr widget2(CreateTopLevelPlatformWidget());
- ShowSync(widget2);
+ ShowSync(widget2.get());
EXPECT_FALSE(widget->IsActive());
EXPECT_TRUE(widget2->IsVisible());
EXPECT_TRUE(widget2->IsActive());
- ShowSync(widget);
+ ShowSync(widget.get());
EXPECT_TRUE(widget->IsActive());
EXPECT_FALSE(widget2->IsActive());
- ShowInactiveSync(widget);
+ ShowInactiveSync(widget.get());
EXPECT_TRUE(widget->IsActive());
EXPECT_FALSE(widget2->IsActive());
- EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
-
- widget2->CloseNow();
- widget->CloseNow();
+ EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
}
TEST_F(WidgetTestInteractive, ShowAfterShowInactive) {
- Widget* widget = CreateTopLevelPlatformWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->SetBounds(gfx::Rect(100, 100, 100, 100));
- ShowInactiveSync(widget);
- ShowSync(widget);
- EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
-
- widget->CloseNow();
+ ShowInactiveSync(widget.get());
+ ShowSync(widget.get());
+ EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
}
#if BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX)
TEST_F(WidgetTestInteractive, InactiveWidgetDoesNotGrabActivation) {
- Widget* widget = CreateTopLevelPlatformWidget();
- ShowSync(widget);
- EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+ WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
+ ShowSync(widget.get());
+ EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
- Widget widget2;
+ WidgetAutoclosePtr widget2(new Widget());
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- widget2.Init(std::move(params));
- widget2.Show();
+ widget2->Init(std::move(params));
+ widget2->Show();
RunPendingMessagesForActiveStatusChange();
- EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
- EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
-
- widget->CloseNow();
- widget2.CloseNow();
+ EXPECT_EQ(GetWidgetShowState(widget2.get()), ui::SHOW_STATE_INACTIVE);
+ EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
}
#endif // BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX)
@@ -1352,37 +1083,33 @@ TEST_F(WidgetTestInteractive, InactiveWidgetDoesNotGrabActivation) {
// Test that window state is not changed after getting out of full screen.
TEST_F(WidgetTestInteractive, MAYBE_ExitFullscreenRestoreState) {
- Widget* toplevel = CreateTopLevelPlatformWidget();
+ WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
toplevel->Show();
RunPendingMessages();
// This should be a normal state window.
- EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
+ EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel.get()));
toplevel->SetFullscreen(true);
- EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
+ EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel.get()));
toplevel->SetFullscreen(false);
- EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
+ EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel.get()));
// And it should still be in normal state after getting out of full screen.
- EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
+ EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel.get()));
// Now, make it maximized.
toplevel->Maximize();
- EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
+ EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel.get()));
toplevel->SetFullscreen(true);
- EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
+ EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel.get()));
toplevel->SetFullscreen(false);
- EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
+ EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel.get()));
// And it stays maximized after getting out of full screen.
- EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
-
- // Clean up.
- toplevel->Close();
- RunPendingMessages();
+ EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel.get()));
}
// Testing initial focus is assigned properly for normal top-level widgets,
@@ -1412,23 +1139,21 @@ TEST_F(WidgetTestInteractive, InitialFocus) {
}
TEST_F(DesktopWidgetTestInteractive, RestoreAfterMinimize) {
- Widget* widget = CreateWidget();
- ShowSync(widget);
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+ ShowSync(widget.get());
ASSERT_FALSE(widget->IsMinimized());
PropertyWaiter minimize_waiter(
- base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+ base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
true);
widget->Minimize();
EXPECT_TRUE(minimize_waiter.Wait());
PropertyWaiter restore_waiter(
- base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+ base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
false);
widget->Restore();
EXPECT_TRUE(restore_waiter.Wait());
-
- widget->CloseNow();
}
#if defined(OS_WIN)
@@ -1437,14 +1162,14 @@ TEST_F(DesktopWidgetTestInteractive, RestoreAfterMinimize) {
// Tests that root window visibility toggles correctly when the desktop widget
// is minimized and maximized on Windows, and the Widget remains visible.
TEST_F(DesktopWidgetTestInteractive, RestoreAndMinimizeVisibility) {
- Widget* widget = CreateWidget();
- aura::Window* root_window = GetRootWindow(widget);
- ShowSync(widget);
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+ aura::Window* root_window = GetRootWindow(widget.get());
+ ShowSync(widget.get());
ASSERT_FALSE(widget->IsMinimized());
EXPECT_TRUE(root_window->IsVisible());
PropertyWaiter minimize_widget_waiter(
- base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+ base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
true);
widget->Minimize();
EXPECT_TRUE(minimize_widget_waiter.Wait());
@@ -1452,22 +1177,21 @@ TEST_F(DesktopWidgetTestInteractive, RestoreAndMinimizeVisibility) {
EXPECT_FALSE(root_window->IsVisible());
PropertyWaiter restore_widget_waiter(
- base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+ base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
false);
widget->Restore();
EXPECT_TRUE(restore_widget_waiter.Wait());
EXPECT_TRUE(widget->IsVisible());
EXPECT_TRUE(root_window->IsVisible());
- widget->CloseNow();
}
// Test that focus is restored to the widget after a minimized window
// is activated.
TEST_F(DesktopWidgetTestInteractive, MinimizeAndActivateFocus) {
- Widget* widget = CreateWidget();
- aura::Window* root_window = GetRootWindow(widget);
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+ aura::Window* root_window = GetRootWindow(widget.get());
auto* widget_window = widget->GetNativeWindow();
- ShowSync(widget);
+ ShowSync(widget.get());
ASSERT_FALSE(widget->IsMinimized());
EXPECT_TRUE(root_window->IsVisible());
widget_window->Focus();
@@ -1477,7 +1201,7 @@ TEST_F(DesktopWidgetTestInteractive, MinimizeAndActivateFocus) {
EXPECT_TRUE(widget->GetContentsView()->HasFocus());
PropertyWaiter minimize_widget_waiter(
- base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+ base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
true);
widget->Minimize();
EXPECT_TRUE(minimize_widget_waiter.Wait());
@@ -1485,7 +1209,7 @@ TEST_F(DesktopWidgetTestInteractive, MinimizeAndActivateFocus) {
EXPECT_FALSE(root_window->IsVisible());
PropertyWaiter restore_widget_waiter(
- base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+ base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
false);
widget->Activate();
EXPECT_TRUE(widget->GetContentsView()->HasFocus());
@@ -1493,7 +1217,6 @@ TEST_F(DesktopWidgetTestInteractive, MinimizeAndActivateFocus) {
EXPECT_TRUE(widget->IsVisible());
EXPECT_TRUE(root_window->IsVisible());
EXPECT_TRUE(widget_window->CanFocus());
- widget->CloseNow();
}
#endif // defined(OS_WIN)
@@ -1502,8 +1225,8 @@ TEST_F(DesktopWidgetTestInteractive, MinimizeAndActivateFocus) {
// Tests that minimizing a widget causes the gesture_handler
// to be cleared when the widget is minimized.
TEST_F(DesktopWidgetTestInteractive, EventHandlersClearedOnWidgetMinimize) {
- Widget* widget = CreateWidget();
- ShowSync(widget);
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+ ShowSync(widget.get());
ASSERT_FALSE(widget->IsMinimized());
View mouse_handler_view;
internal::RootView* root_view =
@@ -1515,8 +1238,6 @@ TEST_F(DesktopWidgetTestInteractive, EventHandlersClearedOnWidgetMinimize) {
widget->Minimize();
EXPECT_FALSE(GetGestureHandler(root_view));
-
- widget->CloseNow();
}
#endif
@@ -1527,16 +1248,16 @@ TEST_F(DesktopWidgetTestInteractive, EventHandlersClearedOnWidgetMinimize) {
TEST_F(DesktopWidgetTestInteractive,
DesktopNativeWidgetWithModalTransientChild) {
// Create a desktop native Widget for Widget::Deactivate().
- Widget* deactivate_widget = CreateWidget();
- ShowSync(deactivate_widget);
+ WidgetAutoclosePtr deactivate_widget(CreateTopLevelNativeWidget());
+ ShowSync(deactivate_widget.get());
// Create a top level desktop native widget.
- Widget* top_level = CreateWidget();
+ WidgetAutoclosePtr top_level(CreateTopLevelNativeWidget());
Textfield* textfield = new Textfield;
textfield->SetBounds(0, 0, 200, 20);
top_level->GetRootView()->AddChildView(textfield);
- ShowSync(top_level);
+ ShowSync(top_level.get());
textfield->RequestFocus();
EXPECT_TRUE(textfield->HasFocus());
@@ -1557,18 +1278,15 @@ TEST_F(DesktopWidgetTestInteractive,
EXPECT_TRUE(dialog_textfield->HasFocus());
EXPECT_FALSE(textfield->HasFocus());
- DeactivateSync(top_level);
+ DeactivateSync(top_level.get());
EXPECT_FALSE(dialog_textfield->HasFocus());
EXPECT_FALSE(textfield->HasFocus());
// After deactivation and activation of top level widget, only modal dialog
// should restore focused view.
- ActivateSync(top_level);
+ ActivateSync(top_level.get());
EXPECT_TRUE(dialog_textfield->HasFocus());
EXPECT_FALSE(textfield->HasFocus());
-
- top_level->CloseNow();
- deactivate_widget->CloseNow();
}
#endif // defined(OS_LINUX) && BUILDFLAG(ENABLE_DESKTOP_AURA)
@@ -1615,7 +1333,7 @@ class CaptureLostTrackingWidget : public Widget {
} // namespace
-class WidgetCaptureTest : public ViewsInteractiveUITestBase {
+class WidgetCaptureTest : public DesktopWidgetTestInteractive {
public:
WidgetCaptureTest() = default;
~WidgetCaptureTest() override = default;
@@ -1625,22 +1343,12 @@ class WidgetCaptureTest : public ViewsInteractiveUITestBase {
void TestCapture(bool use_desktop_native_widget) {
CaptureLostState capture_state1;
CaptureLostTrackingWidget widget1(&capture_state1);
- Widget::InitParams params1 =
- CreateParams(views::Widget::InitParams::TYPE_WINDOW);
- params1.native_widget =
- CreateNativeWidget(params1, use_desktop_native_widget, &widget1);
- params1.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- widget1.Init(std::move(params1));
+ InitPlatformWidget(&widget1, use_desktop_native_widget);
widget1.Show();
CaptureLostState capture_state2;
CaptureLostTrackingWidget widget2(&capture_state2);
- Widget::InitParams params2 =
- CreateParams(views::Widget::InitParams::TYPE_WINDOW);
- params2.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params2.native_widget =
- CreateNativeWidget(params2, use_desktop_native_widget, &widget2);
- widget2.Init(std::move(params2));
+ InitPlatformWidget(&widget2, use_desktop_native_widget);
widget2.Show();
// Set capture to widget2 and verity it gets it.
@@ -1665,13 +1373,16 @@ class WidgetCaptureTest : public ViewsInteractiveUITestBase {
EXPECT_FALSE(capture_state2.GetAndClearGotCaptureLost());
}
- NativeWidget* CreateNativeWidget(const Widget::InitParams& params,
- bool create_desktop_native_widget,
- Widget* widget) {
- // The test base class by default returns DesktopNativeWidgetAura.
- if (create_desktop_native_widget)
- return nullptr;
- return CreatePlatformNativeWidgetImpl(params, widget, kDefault, nullptr);
+ void InitPlatformWidget(Widget* widget, bool use_desktop_native_widget) {
+ Widget::InitParams params =
+ CreateParams(views::Widget::InitParams::TYPE_WINDOW);
+ // The test class by default returns DesktopNativeWidgetAura.
+ params.native_widget =
+ use_desktop_native_widget
+ ? nullptr
+ : CreatePlatformNativeWidgetImpl(widget, kDefault, nullptr);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(std::move(params));
}
private:
@@ -1767,6 +1478,243 @@ TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) {
EXPECT_TRUE(mouse_view2->pressed());
}
+TEST_F(WidgetCaptureTest, CaptureAutoReset) {
+ WidgetAutoclosePtr toplevel(CreateTopLevelFramelessPlatformWidget());
+ View* container = new View;
+ toplevel->SetContentsView(container);
+
+ EXPECT_FALSE(toplevel->HasCapture());
+ toplevel->SetCapture(nullptr);
+ EXPECT_TRUE(toplevel->HasCapture());
+
+ // By default, mouse release removes capture.
+ gfx::Point click_location(45, 15);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ toplevel->OnMouseEvent(&release);
+ EXPECT_FALSE(toplevel->HasCapture());
+
+ // Now a mouse release shouldn't remove capture.
+ toplevel->set_auto_release_capture(false);
+ toplevel->SetCapture(nullptr);
+ EXPECT_TRUE(toplevel->HasCapture());
+ toplevel->OnMouseEvent(&release);
+ EXPECT_TRUE(toplevel->HasCapture());
+ toplevel->ReleaseCapture();
+ EXPECT_FALSE(toplevel->HasCapture());
+}
+
+TEST_F(WidgetCaptureTest, ResetCaptureOnGestureEnd) {
+ WidgetAutoclosePtr toplevel(CreateTopLevelFramelessPlatformWidget());
+ View* container = new View;
+ toplevel->SetContentsView(container);
+
+ View* gesture = new GestureCaptureView;
+ gesture->SetBounds(0, 0, 30, 30);
+ container->AddChildView(gesture);
+
+ MouseView* mouse = new MouseView;
+ mouse->SetBounds(30, 0, 30, 30);
+ container->AddChildView(mouse);
+
+ toplevel->SetSize(gfx::Size(100, 100));
+ toplevel->Show();
+
+ // Start a gesture on |gesture|.
+ ui::GestureEvent tap_down(15, 15, 0, base::TimeTicks(),
+ ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
+ ui::GestureEvent end(15, 15, 0, base::TimeTicks(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END));
+ toplevel->OnGestureEvent(&tap_down);
+
+ // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
+ // will not receive the event.
+ gfx::Point click_location(45, 15);
+
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+
+ EXPECT_TRUE(toplevel->HasCapture());
+
+ toplevel->OnMouseEvent(&press);
+ toplevel->OnMouseEvent(&release);
+ EXPECT_EQ(0, mouse->pressed());
+
+ EXPECT_FALSE(toplevel->HasCapture());
+
+ // The end of the gesture should release the capture, and pressing on |mouse|
+ // should now reach |mouse|.
+ toplevel->OnGestureEvent(&end);
+ toplevel->OnMouseEvent(&press);
+ toplevel->OnMouseEvent(&release);
+ EXPECT_EQ(1, mouse->pressed());
+}
+
+// Checks that if a mouse-press triggers a capture on a different widget (which
+// consumes the mouse-release event), then the target of the press does not have
+// capture.
+TEST_F(WidgetCaptureTest, DisableCaptureWidgetFromMousePress) {
+ // The test creates two widgets: |first| and |second|.
+ // The View in |first| makes |second| visible, sets capture on it, and starts
+ // a nested loop (like a menu does). The View in |second| terminates the
+ // nested loop and closes the widget.
+ // The test sends a mouse-press event to |first|, and posts a task to send a
+ // release event to |second|, to make sure that the release event is
+ // dispatched after the nested loop starts.
+
+ WidgetAutoclosePtr first(CreateTopLevelFramelessPlatformWidget());
+ Widget* second = CreateTopLevelFramelessPlatformWidget();
+
+ NestedLoopCaptureView* container = new NestedLoopCaptureView(second);
+ first->SetContentsView(container);
+
+ second->SetContentsView(new ExitLoopOnRelease(container->GetQuitClosure()));
+
+ first->SetSize(gfx::Size(100, 100));
+ first->Show();
+
+ gfx::Point location(20, 20);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &Widget::OnMouseEvent, base::Unretained(second),
+ base::Owned(new ui::MouseEvent(
+ ui::ET_MOUSE_RELEASED, location, location, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON))));
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ first->OnMouseEvent(&press);
+ EXPECT_FALSE(first->HasCapture());
+}
+
+// Tests some grab/ungrab events. Only one Widget can have capture at any given
+// time.
+TEST_F(WidgetCaptureTest, GrabUngrab) {
+ auto top_level = CreateTestWidget();
+ top_level->SetContentsView(new MouseView());
+
+ Widget* child1 = new Widget;
+ Widget::InitParams params1 = CreateParams(Widget::InitParams::TYPE_CONTROL);
+ params1.parent = top_level->GetNativeView();
+ params1.bounds = gfx::Rect(10, 10, 100, 100);
+ child1->Init(std::move(params1));
+ child1->SetContentsView(new MouseView());
+
+ Widget* child2 = new Widget;
+ Widget::InitParams params2 = CreateParams(Widget::InitParams::TYPE_CONTROL);
+ params2.parent = top_level->GetNativeView();
+ params2.bounds = gfx::Rect(110, 10, 100, 100);
+ child2->Init(std::move(params2));
+ child2->SetContentsView(new MouseView());
+
+ top_level->Show();
+ RunPendingMessages();
+
+ // Click on child1.
+ ui::test::EventGenerator generator(GetRootWindow(top_level.get()),
+ child1->GetNativeWindow());
+ generator.PressLeftButton();
+
+ EXPECT_FALSE(top_level->HasCapture());
+ EXPECT_TRUE(child1->HasCapture());
+ EXPECT_FALSE(child2->HasCapture());
+
+ generator.ReleaseLeftButton();
+ EXPECT_FALSE(top_level->HasCapture());
+ EXPECT_FALSE(child1->HasCapture());
+ EXPECT_FALSE(child2->HasCapture());
+
+ // Click on child2.
+ generator.SetTargetWindow(child2->GetNativeWindow());
+ generator.set_current_screen_location(
+ generator.delegate()->CenterOfWindow(child2->GetNativeWindow()));
+ generator.PressLeftButton();
+
+ EXPECT_FALSE(top_level->HasCapture());
+ EXPECT_FALSE(child1->HasCapture());
+ EXPECT_TRUE(child2->HasCapture());
+
+ generator.ReleaseLeftButton();
+ EXPECT_FALSE(top_level->HasCapture());
+ EXPECT_FALSE(child1->HasCapture());
+ EXPECT_FALSE(child2->HasCapture());
+
+ // Click on top_level.
+ generator.SetTargetWindow(top_level->GetNativeWindow());
+ generator.set_current_screen_location(gfx::Point());
+ generator.PressLeftButton();
+
+ EXPECT_TRUE(top_level->HasCapture());
+ EXPECT_FALSE(child1->HasCapture());
+ EXPECT_FALSE(child2->HasCapture());
+
+ generator.ReleaseLeftButton();
+ EXPECT_FALSE(top_level->HasCapture());
+ EXPECT_FALSE(child1->HasCapture());
+ EXPECT_FALSE(child2->HasCapture());
+}
+
+// Disabled on Mac. Desktop Mac doesn't have system modal windows since Carbon
+// was deprecated. It does have application modal windows, but only Ash requests
+// those.
+#if defined(OS_MACOSX)
+#define MAYBE_SystemModalWindowReleasesCapture \
+ DISABLED_SystemModalWindowReleasesCapture
+#elif defined(OS_CHROMEOS)
+// Investigate enabling for Chrome OS. It probably requires help from the window
+// service.
+#define MAYBE_SystemModalWindowReleasesCapture \
+ DISABLED_SystemModalWindowReleasesCapture
+#else
+#define MAYBE_SystemModalWindowReleasesCapture SystemModalWindowReleasesCapture
+#endif
+
+// Test that when opening a system-modal window, capture is released.
+TEST_F(WidgetCaptureTest, MAYBE_SystemModalWindowReleasesCapture) {
+ TestWidgetFocusChangeListener focus_listener;
+ WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener);
+
+ // Create a top level widget.
+ Widget top_level_widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.show_state = ui::SHOW_STATE_NORMAL;
+ gfx::Rect initial_bounds(0, 0, 500, 500);
+ init_params.bounds = initial_bounds;
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ top_level_widget.Init(std::move(init_params));
+ ShowSync(&top_level_widget);
+
+ ASSERT_FALSE(focus_listener.focus_changes().empty());
+ EXPECT_EQ(top_level_widget.GetNativeView(),
+ focus_listener.focus_changes().back());
+
+ EXPECT_FALSE(top_level_widget.HasCapture());
+ top_level_widget.SetCapture(nullptr);
+ EXPECT_TRUE(top_level_widget.HasCapture());
+
+ // Create a modal dialog.
+ ModalDialogDelegate* dialog_delegate =
+ new ModalDialogDelegate(ui::MODAL_TYPE_SYSTEM);
+
+ Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
+ dialog_delegate, nullptr, top_level_widget.GetNativeView());
+ modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
+ ShowSync(modal_dialog_widget);
+
+ EXPECT_FALSE(top_level_widget.HasCapture());
+
+ modal_dialog_widget->CloseNow();
+ top_level_widget.CloseNow();
+ WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(&focus_listener);
+}
+
// Regression test for http://crbug.com/382421 (Linux-Aura issue).
// TODO(pkotwicz): Make test pass on CrOS and Windows.
// TODO(tapted): Investigate for toolkit-views on Mac http;//crbug.com/441064.
@@ -1952,7 +1900,7 @@ class WidgetInputMethodInteractiveTest : public DesktopWidgetTestInteractive {
// On Windows, Widget::Deactivate() works by activating the next topmost
// window on the z-order stack. This only works if there is at least one
// other window, so make sure that is the case.
- deactivate_widget_ = CreateWidget();
+ deactivate_widget_ = CreateTopLevelNativeWidget();
deactivate_widget_->Show();
#endif
}
@@ -1976,33 +1924,32 @@ class WidgetInputMethodInteractiveTest : public DesktopWidgetTestInteractive {
#endif
// Test input method focus changes affected by top window activaction.
TEST_F(WidgetInputMethodInteractiveTest, MAYBE_Activation) {
- Widget* widget = CreateWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
Textfield* textfield = new Textfield;
widget->GetRootView()->AddChildView(textfield);
textfield->RequestFocus();
- ShowSync(widget);
+ ShowSync(widget.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
widget->GetInputMethod()->GetTextInputType());
- DeactivateSync(widget);
+ DeactivateSync(widget.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
widget->GetInputMethod()->GetTextInputType());
- widget->CloseNow();
}
// Test input method focus changes affected by focus changes within 1 window.
TEST_F(WidgetInputMethodInteractiveTest, OneWindow) {
- Widget* widget = CreateWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
Textfield* textfield1 = new Textfield;
Textfield* textfield2 = new Textfield;
textfield2->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
widget->GetRootView()->AddChildView(textfield1);
widget->GetRootView()->AddChildView(textfield2);
- ShowSync(widget);
+ ShowSync(widget.get());
textfield1->RequestFocus();
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
@@ -2016,31 +1963,30 @@ TEST_F(WidgetInputMethodInteractiveTest, OneWindow) {
// DNWA (which just activates the last active window) and involves the
// AuraTestHelper which sets the input method as DummyInputMethod.
#if BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX)
- DeactivateSync(widget);
+ DeactivateSync(widget.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
widget->GetInputMethod()->GetTextInputType());
- ActivateSync(widget);
+ ActivateSync(widget.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD,
widget->GetInputMethod()->GetTextInputType());
- DeactivateSync(widget);
+ DeactivateSync(widget.get());
textfield1->RequestFocus();
- ActivateSync(widget);
+ ActivateSync(widget.get());
EXPECT_TRUE(widget->IsActive());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
widget->GetInputMethod()->GetTextInputType());
#endif
- widget->CloseNow();
}
// Test input method focus changes affected by focus changes cross 2 windows
// which shares the same top window.
TEST_F(WidgetInputMethodInteractiveTest, TwoWindows) {
- Widget* parent = CreateWidget();
+ WidgetAutoclosePtr parent(CreateTopLevelNativeWidget());
parent->SetBounds(gfx::Rect(100, 100, 100, 100));
- Widget* child = CreateChildNativeWidgetWithParent(parent);
+ Widget* child = CreateChildNativeWidgetWithParent(parent.get());
child->SetBounds(gfx::Rect(0, 0, 50, 50));
child->Show();
@@ -2049,7 +1995,7 @@ TEST_F(WidgetInputMethodInteractiveTest, TwoWindows) {
textfield_parent->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
parent->GetRootView()->AddChildView(textfield_parent);
child->GetRootView()->AddChildView(textfield_child);
- ShowSync(parent);
+ ShowSync(parent.get());
EXPECT_EQ(parent->GetInputMethod(), child->GetInputMethod());
@@ -2065,33 +2011,31 @@ TEST_F(WidgetInputMethodInteractiveTest, TwoWindows) {
// DNWA (which just activates the last active window) and involves the
// AuraTestHelper which sets the input method as DummyInputMethod.
#if BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX)
- DeactivateSync(parent);
+ DeactivateSync(parent.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
parent->GetInputMethod()->GetTextInputType());
- ActivateSync(parent);
+ ActivateSync(parent.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
parent->GetInputMethod()->GetTextInputType());
textfield_parent->RequestFocus();
- DeactivateSync(parent);
+ DeactivateSync(parent.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
parent->GetInputMethod()->GetTextInputType());
- ActivateSync(parent);
+ ActivateSync(parent.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD,
parent->GetInputMethod()->GetTextInputType());
#endif
-
- parent->CloseNow();
}
// Test input method focus changes affected by textfield's state changes.
TEST_F(WidgetInputMethodInteractiveTest, TextField) {
- Widget* widget = CreateWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
Textfield* textfield = new Textfield;
widget->GetRootView()->AddChildView(textfield);
- ShowSync(widget);
+ ShowSync(widget.get());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
widget->GetInputMethod()->GetTextInputType());
@@ -2110,15 +2054,14 @@ TEST_F(WidgetInputMethodInteractiveTest, TextField) {
textfield->SetReadOnly(true);
EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
widget->GetInputMethod()->GetTextInputType());
- widget->CloseNow();
}
// Test input method should not work for accelerator.
TEST_F(WidgetInputMethodInteractiveTest, AcceleratorInTextfield) {
- Widget* widget = CreateWidget();
+ WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
Textfield* textfield = new Textfield;
widget->GetRootView()->AddChildView(textfield);
- ShowSync(widget);
+ ShowSync(widget.get());
textfield->SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
textfield->RequestFocus();
@@ -2135,8 +2078,6 @@ TEST_F(WidgetInputMethodInteractiveTest, AcceleratorInTextfield) {
ui::KeyEvent key_event2(key_event);
widget->OnKeyEvent(&key_event2);
EXPECT_FALSE(key_event2.stopped_propagation());
-
- widget->CloseNow();
}
} // namespace test
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index e932006a39a..469e9150908 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -343,79 +343,6 @@ class OwnershipTestWidget : public Widget {
// TODO(sky): add coverage of ownership for the desktop variants.
-// Widget owns its NativeWidget, part 1: NativeWidget is a platform-native
-// widget.
-TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) {
- OwnershipTestState state;
-
- auto widget = std::make_unique<OwnershipTestWidget>(&state);
- Widget::InitParams params = CreateParamsForTestWidget();
- params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget.get(), kStubCapture, &state.native_widget_deleted);
- widget->Init(std::move(params));
-
- // Now delete the Widget, which should delete the NativeWidget.
- widget.reset();
-
- EXPECT_TRUE(state.widget_deleted);
- EXPECT_TRUE(state.native_widget_deleted);
-
- // TODO(beng): write test for this ownership scenario and the NativeWidget
- // being deleted out from under the Widget.
-}
-
-// Widget owns its NativeWidget, part 2: NativeWidget is a NativeWidget.
-TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) {
- OwnershipTestState state;
-
- auto widget = std::make_unique<OwnershipTestWidget>(&state);
- Widget::InitParams params = CreateParamsForTestWidget();
- params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget.get(), kStubCapture, &state.native_widget_deleted);
- widget->Init(std::move(params));
-
- // Now delete the Widget, which should delete the NativeWidget.
- widget.reset();
-
- EXPECT_TRUE(state.widget_deleted);
- EXPECT_TRUE(state.native_widget_deleted);
-
- // TODO(beng): write test for this ownership scenario and the NativeWidget
- // being deleted out from under the Widget.
-}
-
-// Widget owns its NativeWidget, part 3: NativeWidget is a NativeWidget,
-// destroy the parent view.
-TEST_F(WidgetOwnershipTest,
- Ownership_WidgetOwnsViewsNativeWidget_DestroyParentView) {
- OwnershipTestState state;
-
- Widget* toplevel = CreateTopLevelPlatformWidget();
-
- auto widget = std::make_unique<OwnershipTestWidget>(&state);
- Widget::InitParams params = CreateParamsForTestWidget();
- params.parent = toplevel->GetNativeView();
- params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget.get(), kStubCapture, &state.native_widget_deleted);
- widget->Init(std::move(params));
-
- // Now close the toplevel, which deletes the view hierarchy.
- toplevel->CloseNow();
-
- RunPendingMessages();
-
- // This shouldn't delete the widget because it shouldn't be deleted
- // from the native side.
- EXPECT_FALSE(state.widget_deleted);
- EXPECT_FALSE(state.native_widget_deleted);
-
- // Now delete it explicitly.
- widget.reset();
-
- EXPECT_TRUE(state.widget_deleted);
- EXPECT_TRUE(state.native_widget_deleted);
-}
-
// NativeWidget owns its Widget, part 1: NativeWidget is a platform-native
// widget.
TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
@@ -424,7 +351,7 @@ TEST_F(WidgetOwnershipTest, Ownership_PlatformNativeWidgetOwnsWidget) {
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget, kStubCapture, &state.native_widget_deleted);
+ widget, kStubCapture, &state.native_widget_deleted);
widget->Init(std::move(params));
// Now destroy the native widget.
@@ -444,7 +371,7 @@ TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget) {
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.parent = toplevel->GetNativeView();
params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget, kStubCapture, &state.native_widget_deleted);
+ widget, kStubCapture, &state.native_widget_deleted);
widget->Init(std::move(params));
// Now destroy the native widget. This is achieved by closing the toplevel.
@@ -467,7 +394,7 @@ TEST_F(WidgetOwnershipTest,
Widget* widget = new OwnershipTestWidget(&state);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget, kStubCapture, &state.native_widget_deleted);
+ widget, kStubCapture, &state.native_widget_deleted);
widget->Init(std::move(params));
// Now simulate a destroy of the platform native widget from the OS:
@@ -489,7 +416,7 @@ TEST_F(WidgetOwnershipTest,
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.parent = toplevel->GetNativeView();
params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget, kStubCapture, &state.native_widget_deleted);
+ widget, kStubCapture, &state.native_widget_deleted);
widget->Init(std::move(params));
// Destroy the widget (achieved by closing the toplevel).
@@ -514,7 +441,7 @@ TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget_Close) {
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.parent = toplevel->GetNativeView();
params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget, kStubCapture, &state.native_widget_deleted);
+ widget, kStubCapture, &state.native_widget_deleted);
widget->Init(std::move(params));
// Destroy the widget.
@@ -529,26 +456,72 @@ TEST_F(WidgetOwnershipTest, Ownership_ViewsNativeWidgetOwnsWidget_Close) {
EXPECT_TRUE(state.native_widget_deleted);
}
-// Widget owns its NativeWidget and has a WidgetDelegateView as its contents.
-TEST_F(WidgetOwnershipTest,
- Ownership_WidgetOwnsNativeWidgetWithWithWidgetDelegateView) {
- OwnershipTestState state;
+class WidgetOwnsNativeWidgetTest : public WidgetOwnershipTest {
+ public:
+ WidgetOwnsNativeWidgetTest() = default;
+ ~WidgetOwnsNativeWidgetTest() override = default;
+
+ void TearDown() override {
+ EXPECT_TRUE(state_.widget_deleted);
+ EXPECT_TRUE(state_.native_widget_deleted);
- WidgetDelegateView* delegate_view = new WidgetDelegateView;
+ WidgetOwnershipTest::TearDown();
+ }
+
+ OwnershipTestState* state() { return &state_; }
- auto widget = std::make_unique<OwnershipTestWidget>(&state);
+ private:
+ OwnershipTestState state_;
+};
+
+// Widget owns its NativeWidget, part 1.
+TEST_F(WidgetOwnsNativeWidgetTest, Ownership) {
+ auto widget = std::make_unique<OwnershipTestWidget>(state());
Widget::InitParams params = CreateParamsForTestWidget();
params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget.get(), kStubCapture, &state.native_widget_deleted);
- params.delegate = delegate_view;
+ widget.get(), kStubCapture, &state()->native_widget_deleted);
widget->Init(std::move(params));
- widget->SetContentsView(delegate_view);
- // Now delete the Widget. There should be no crash or use-after-free.
+ // Now delete the Widget, which should delete the NativeWidget.
widget.reset();
- EXPECT_TRUE(state.widget_deleted);
- EXPECT_TRUE(state.native_widget_deleted);
+ // TODO(beng): write test for this ownership scenario and the NativeWidget
+ // being deleted out from under the Widget.
+}
+
+// Widget owns its NativeWidget, part 2: destroy the parent view.
+TEST_F(WidgetOwnsNativeWidgetTest, DestroyParentView) {
+ Widget* toplevel = CreateTopLevelPlatformWidget();
+
+ auto widget = std::make_unique<OwnershipTestWidget>(state());
+ Widget::InitParams params = CreateParamsForTestWidget();
+ params.parent = toplevel->GetNativeView();
+ params.native_widget = CreatePlatformNativeWidgetImpl(
+ widget.get(), kStubCapture, &state()->native_widget_deleted);
+ widget->Init(std::move(params));
+
+ // Now close the toplevel, which deletes the view hierarchy.
+ toplevel->CloseNow();
+
+ RunPendingMessages();
+
+ // This shouldn't delete the widget because it shouldn't be deleted
+ // from the native side.
+ EXPECT_FALSE(state()->widget_deleted);
+ EXPECT_FALSE(state()->native_widget_deleted);
+}
+
+// Widget owns its NativeWidget, part 3: has a WidgetDelegateView as contents.
+TEST_F(WidgetOwnsNativeWidgetTest, WidgetDelegateView) {
+ auto widget = std::make_unique<OwnershipTestWidget>(state());
+ Widget::InitParams params = CreateParamsForTestWidget();
+ params.native_widget = CreatePlatformNativeWidgetImpl(
+ widget.get(), kStubCapture, &state()->native_widget_deleted);
+ params.delegate = new WidgetDelegateView();
+ widget->Init(std::move(params));
+
+ // Allow the Widget to go out of scope. There should be no crash or
+ // use-after-free.
}
////////////////////////////////////////////////////////////////////////////////
@@ -1259,37 +1232,6 @@ TEST_F(WidgetTest, KeyboardInputEvent) {
EXPECT_FALSE(backspace_r.handled());
}
-// Verifies bubbles result in a focus lost when shown.
-// TODO(msw): this tests relies on focus, it needs to be in
-// interactive_ui_tests.
-TEST_F(DesktopWidgetTest, DISABLED_FocusChangesOnBubble) {
- // Create a widget, show and activate it and focus the contents view.
- View* contents_view = new View;
- contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- std::unique_ptr<Widget> widget = CreateTestWidget();
- widget->SetContentsView(contents_view);
- widget->Show();
- widget->Activate();
- contents_view->RequestFocus();
- EXPECT_TRUE(contents_view->HasFocus());
-
- // Show a bubble.
- BubbleDialogDelegateView* bubble_delegate_view =
- new TestBubbleDialogDelegateView(contents_view);
- bubble_delegate_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- BubbleDialogDelegateView::CreateBubble(bubble_delegate_view)->Show();
- bubble_delegate_view->RequestFocus();
-
- // |contents_view_| should no longer have focus.
- EXPECT_FALSE(contents_view->HasFocus());
- EXPECT_TRUE(bubble_delegate_view->HasFocus());
-
- bubble_delegate_view->GetWidget()->CloseNow();
-
- // Closing the bubble should result in focus going back to the contents view.
- EXPECT_TRUE(contents_view->HasFocus());
-}
-
TEST_F(WidgetTest, BubbleControlsResetOnInit) {
WidgetAutoclosePtr anchor(CreateTopLevelPlatformWidget());
anchor->Show();
@@ -1332,8 +1274,10 @@ TEST_F(DesktopWidgetTest, TestViewWidthAfterMinimizingWidget) {
// paints are expected.
class DesktopAuraTestValidPaintWidget : public Widget, public WidgetObserver {
public:
- DesktopAuraTestValidPaintWidget() { observer_.Add(this); }
-
+ explicit DesktopAuraTestValidPaintWidget(Widget::InitParams init_params)
+ : Widget(std::move(init_params)) {
+ observer_.Add(this);
+ }
~DesktopAuraTestValidPaintWidget() override = default;
bool ReadReceivedPaintAndReset() {
@@ -1385,14 +1329,12 @@ class DesktopAuraPaintWidgetTest : public DesktopWidgetTest {
std::unique_ptr<views::Widget> CreateTestWidget(
views::Widget::InitParams::Type type =
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS) override {
- Widget::InitParams params = CreateParamsForTestWidget(type);
- auto widget = std::make_unique<DesktopAuraTestValidPaintWidget>();
+ auto widget = std::make_unique<DesktopAuraTestValidPaintWidget>(
+ CreateParamsForTestWidget(type));
paint_widget_ = widget.get();
- widget->Init(std::move(params));
- View* contents_view = new View;
+ View* contents_view = widget->SetContentsView(std::make_unique<View>());
contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
- widget->SetContentsView(contents_view);
widget->Show();
widget->Activate();
@@ -2019,8 +1961,8 @@ class WidgetWindowTitleTest : public DesktopWidgetTest {
CreateParams(Widget::InitParams::TYPE_WINDOW);
if (!desktop_native_widget) {
- init_params.native_widget = CreatePlatformNativeWidgetImpl(
- init_params, widget.get(), kStubCapture, nullptr);
+ init_params.native_widget =
+ CreatePlatformNativeWidgetImpl(widget.get(), kStubCapture, nullptr);
}
widget->Init(std::move(init_params));
@@ -2066,7 +2008,8 @@ TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
CreateParams(views::Widget::InitParams::TYPE_POPUP);
widget->Init(std::move(params));
- widget->SetContentsView(new CloseWidgetView(ui::ET_MOUSE_PRESSED));
+ widget->SetContentsView(
+ std::make_unique<CloseWidgetView>(ui::ET_MOUSE_PRESSED));
widget->SetSize(gfx::Size(100, 100));
widget->Show();
@@ -2091,7 +2034,8 @@ TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) {
CreateParams(views::Widget::InitParams::TYPE_POPUP);
widget->Init(std::move(params));
- widget->SetContentsView(new CloseWidgetView(ui::ET_GESTURE_TAP_DOWN));
+ widget->SetContentsView(
+ std::make_unique<CloseWidgetView>(ui::ET_GESTURE_TAP_DOWN));
widget->SetSize(gfx::Size(100, 100));
widget->Show();
@@ -2131,8 +2075,8 @@ bool RunGetNativeThemeFromDestructor(Widget::InitParams params,
// Deletes itself when the Widget is destroyed.
params.delegate = new GetNativeThemeFromDestructorView;
if (!is_first_run) {
- params.native_widget = CreatePlatformNativeWidgetImpl(
- params, widget.get(), kStubCapture, nullptr);
+ params.native_widget =
+ CreatePlatformNativeWidgetImpl(widget.get(), kStubCapture, nullptr);
needs_second_run = true;
}
widget->Init(std::move(params));
@@ -3041,8 +2985,8 @@ class WidgetChildDestructionTest : public DesktopWidgetTest {
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
if (!top_level_has_desktop_native_widget_aura) {
- params.native_widget = CreatePlatformNativeWidgetImpl(
- params, top_level, kStubCapture, nullptr);
+ params.native_widget =
+ CreatePlatformNativeWidgetImpl(top_level, kStubCapture, nullptr);
}
top_level->Init(std::move(params));
top_level->GetRootView()->AddChildView(
@@ -3054,8 +2998,8 @@ class WidgetChildDestructionTest : public DesktopWidgetTest {
CreateParams(views::Widget::InitParams::TYPE_POPUP);
child_params.parent = top_level->GetNativeView();
if (!child_has_desktop_native_widget_aura) {
- child_params.native_widget = CreatePlatformNativeWidgetImpl(
- child_params, child, kStubCapture, nullptr);
+ child_params.native_widget =
+ CreatePlatformNativeWidgetImpl(child, kStubCapture, nullptr);
}
child->Init(std::move(child_params));
child->GetRootView()->AddChildView(
@@ -3874,48 +3818,31 @@ class ModalDialogDelegate : public DialogDelegateView {
// remaining top-level windows should be re-enabled.
TEST_F(DesktopWidgetTest, WindowModalOwnerDestroyedEnabledTest) {
// top_level_widget owns owner_dialog_widget which owns owned_dialog_widget.
-
- // Create the top level widget.
std::unique_ptr<Widget> top_level_widget = CreateTestWidget();
top_level_widget->Show();
// Create the owner modal dialog.
- // owner_dialog_delegate instance will be destroyed when the dialog
- // is destroyed.
- ModalDialogDelegate* owner_dialog_delegate =
- new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
-
- Widget owner_dialog_widget;
- Widget::InitParams init_params =
- CreateParamsForTestWidget(Widget::InitParams::TYPE_WINDOW);
- init_params.delegate = owner_dialog_delegate;
- init_params.parent = top_level_widget->GetNativeView();
- init_params.native_widget =
- new test::TestPlatformNativeWidget<DesktopNativeWidgetAura>(
- &owner_dialog_widget, false, nullptr);
- owner_dialog_widget.Init(std::move(init_params));
-
- HWND owner_hwnd = HWNDForWidget(&owner_dialog_widget);
-
+ const auto create_params = [this](Widget* widget, gfx::NativeView parent) {
+ Widget::InitParams init_params =
+ CreateParamsForTestWidget(Widget::InitParams::TYPE_WINDOW);
+ init_params.delegate = new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
+ init_params.parent = parent;
+ init_params.native_widget =
+ new test::TestPlatformNativeWidget<DesktopNativeWidgetAura>(
+ widget, false, nullptr);
+ return init_params;
+ };
+ Widget owner_dialog_widget(
+ create_params(&owner_dialog_widget, top_level_widget->GetNativeView()));
owner_dialog_widget.Show();
+ HWND owner_hwnd = HWNDForWidget(&owner_dialog_widget);
// Create the owned modal dialog.
- // As above, the owned_dialog_instance instance will be destroyed
- // when the dialog is destroyed.
- ModalDialogDelegate* owned_dialog_delegate =
- new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW);
-
- Widget owned_dialog_widget;
- init_params.delegate = owned_dialog_delegate;
- init_params.parent = owner_dialog_widget.GetNativeView();
- init_params.native_widget =
- new test::TestPlatformNativeWidget<DesktopNativeWidgetAura>(
- &owned_dialog_widget, false, nullptr);
- owned_dialog_widget.Init(std::move(init_params));
-
+ Widget owned_dialog_widget(
+ create_params(&owned_dialog_widget, owner_dialog_widget.GetNativeView()));
+ owned_dialog_widget.Show();
HWND owned_hwnd = HWNDForWidget(&owned_dialog_widget);
- owned_dialog_widget.Show();
RunPendingMessages();
HWND top_hwnd = HWNDForWidget(top_level_widget.get());
diff --git a/chromium/ui/views/win/fullscreen_handler.cc b/chromium/ui/views/win/fullscreen_handler.cc
index 2f828618daf..8791362556f 100644
--- a/chromium/ui/views/win/fullscreen_handler.cc
+++ b/chromium/ui/views/win/fullscreen_handler.cc
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/logging.h"
#include "base/win/win_util.h"
#include "ui/base/win/shell.h"
#include "ui/gfx/geometry/rect.h"
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index e18afe3c8c2..c981cfc6b0a 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -403,7 +403,6 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate,
use_system_default_icon_(false),
restored_enabled_(false),
current_cursor_(nullptr),
- previous_cursor_(nullptr),
dpi_(0),
called_enable_non_client_dpi_scaling_(false),
active_mouse_tracking_flags_(0),
@@ -864,13 +863,9 @@ bool HWNDMessageHandler::SetTitle(const base::string16& title) {
}
void HWNDMessageHandler::SetCursor(HCURSOR cursor) {
- if (cursor) {
- previous_cursor_ = ::SetCursor(cursor);
- current_cursor_ = cursor;
- } else if (previous_cursor_) {
- ::SetCursor(previous_cursor_);
- previous_cursor_ = nullptr;
- }
+ TRACE_EVENT1("ui,input", "HWNDMessageHandler::SetCursor", "cursor", cursor);
+ ::SetCursor(cursor);
+ current_cursor_ = cursor;
}
void HWNDMessageHandler::FrameTypeChanged() {
@@ -2386,18 +2381,42 @@ void HWNDMessageHandler::OnPaint(HDC dc) {
}
if (!IsRectEmpty(&ps.rcPaint)) {
+ HBRUSH brush = reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
+
if (HasChildRenderingWindow()) {
// If there's a child window that's being rendered to then clear the
// area outside it (as WS_CLIPCHILDREN is set) with transparent black.
// Otherwise, other portions of the backing store for the window can
// flicker opaque black. http://crbug.com/586454
- FillRect(ps.hdc, &ps.rcPaint,
- reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
+ FillRect(ps.hdc, &ps.rcPaint, brush);
+ } else if (exposed_pixels_.height() > 0 || exposed_pixels_.width() > 0) {
+ // Fill in newly exposed window client area with black to ensure Windows
+ // doesn't put something else there (eg. copying existing pixels). This
+ // isn't needed if we've just cleared the whole client area outside the
+ // child window above.
+ RECT cr;
+ if (GetClientRect(hwnd(), &cr)) {
+ if (exposed_pixels_.height() > 0) {
+ DCHECK_GE(cr.bottom, exposed_pixels_.height());
+ RECT rect = {cr.left, cr.bottom - exposed_pixels_.height(), cr.right,
+ cr.bottom};
+ FillRect(ps.hdc, &rect, brush);
+ }
+ if (exposed_pixels_.width() > 0) {
+ DCHECK_GE(cr.right, exposed_pixels_.width());
+ RECT rect = {cr.right - exposed_pixels_.width(), cr.top, cr.right,
+ cr.bottom - exposed_pixels_.height()};
+ FillRect(ps.hdc, &rect, brush);
+ }
+ }
}
+
delegate_->HandlePaintAccelerated(gfx::Rect(ps.rcPaint));
}
+ exposed_pixels_ = gfx::Size();
+
EndPaint(hwnd(), &ps);
}
@@ -2815,6 +2834,10 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
gfx::Size new_size = gfx::Size(window_pos->cx, window_pos->cy);
if ((old_size != new_size && !(window_pos->flags & SWP_NOSIZE)) ||
window_pos->flags & SWP_FRAMECHANGED) {
+ // If the window is getting larger then fill the exposed area on the next
+ // WM_PAINT.
+ exposed_pixels_ = new_size - old_size;
+
delegate_->HandleWindowSizeChanging();
sent_window_size_changing_ = true;
@@ -2827,6 +2850,9 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
// resizing. See https://crbug.com/739724
if (is_translucent_)
window_pos->flags |= SWP_NOCOPYBITS;
+ } else {
+ // The window size isn't changing so there are no exposed pixels.
+ exposed_pixels_ = gfx::Size();
}
if (ScopedFullscreenVisibility::IsHiddenForFullscreen(hwnd())) {
@@ -2867,10 +2893,13 @@ LRESULT HWNDMessageHandler::OnWindowSizingFinished(UINT message,
// received after this message was posted.
if (current_window_size_message_ != w_param)
return 0;
-
delegate_->HandleWindowSizeUnchanged();
sent_window_size_changing_ = false;
+ // The window size didn't actually change, so nothing was exposed that needs
+ // to be filled black.
+ exposed_pixels_ = gfx::Size();
+
return 0;
}
@@ -3126,9 +3155,8 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message,
ui::TouchEvent event(
event_type, touch_point, event_time,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
- mapped_pointer_id, radius_x, radius_y, pressure,
- rotation_angle),
+ ui::PointerDetails(ui::EventPointerType::kTouch, mapped_pointer_id,
+ radius_x, radius_y, pressure, rotation_angle),
ui::GetModifiersFromKeyState());
event.latency()->AddLatencyNumberWithTimestamp(
@@ -3282,9 +3310,8 @@ void HWNDMessageHandler::GenerateTouchEvent(ui::EventType event_type,
size_t id,
base::TimeTicks time_stamp,
TouchEvents* touch_events) {
- ui::TouchEvent event(
- event_type, point, time_stamp,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, id));
+ ui::TouchEvent event(event_type, point, time_stamp,
+ ui::PointerDetails(ui::EventPointerType::kTouch, id));
event.set_flags(ui::GetModifiersFromKeyState());
diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h
index 7b56d58faff..a84076658b4 100644
--- a/chromium/ui/views/win/hwnd_message_handler.h
+++ b/chromium/ui/views/win/hwnd_message_handler.h
@@ -625,10 +625,6 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// The current cursor.
HCURSOR current_cursor_;
- // The last cursor that was active before the current one was selected. Saved
- // so that we can restore it.
- HCURSOR previous_cursor_;
-
// The icon created from the bitmap image of the window icon.
base::win::ScopedHICON window_icon_;
@@ -798,6 +794,11 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
static base::LazyInstance<FullscreenWindowMonitorMap>::DestructorAtExit
fullscreen_monitor_map_;
+ // How many pixels the window is expected to grow from OnWindowPosChanging().
+ // Used to fill the newly exposed pixels black in OnPaint() before the
+ // browser compositor is able to redraw at the new window size.
+ gfx::Size exposed_pixels_;
+
// Populated if the cursor position is being mocked for testing purposes.
base::Optional<gfx::Point> mock_cursor_position_;
diff --git a/chromium/ui/views/win/pen_event_processor.cc b/chromium/ui/views/win/pen_event_processor.cc
index 3ff82e59065..46ac6b2c8f7 100644
--- a/chromium/ui/views/win/pen_event_processor.cc
+++ b/chromium/ui/views/win/pen_event_processor.cc
@@ -4,6 +4,8 @@
#include "ui/views/win/pen_event_processor.h"
+#include "base/check.h"
+#include "base/notreached.h"
#include "base/time/time.h"
#include "ui/events/event_utils.h"
@@ -40,16 +42,16 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateEvent(
// We are now creating a fake mouse event with pointer type of pen from
// the WM_POINTER message and then setting up an associated pointer
// details in the MouseEvent which contains the pen's information.
- ui::EventPointerType input_type = ui::EventPointerType::POINTER_TYPE_PEN;
+ ui::EventPointerType input_type = ui::EventPointerType::kPen;
// For the pointerup event, the penFlags is not set to PEN_FLAG_ERASER, so we
// have to check if previously the pointer type is an eraser.
if (pointer_pen_info.penFlags & PEN_FLAG_ERASER) {
- input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
+ input_type = ui::EventPointerType::kEraser;
DCHECK(!eraser_pointer_id_ || *eraser_pointer_id_ == mapped_pointer_id);
eraser_pointer_id_ = mapped_pointer_id;
} else if (eraser_pointer_id_ && *eraser_pointer_id_ == mapped_pointer_id &&
(message == WM_POINTERUP || message == WM_NCPOINTERUP)) {
- input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
+ input_type = ui::EventPointerType::kEraser;
eraser_pointer_id_.reset();
}
diff --git a/chromium/ui/views/win/pen_event_processor_unittest.cc b/chromium/ui/views/win/pen_event_processor_unittest.cc
index 211a735e062..652606182df 100644
--- a/chromium/ui/views/win/pen_event_processor_unittest.cc
+++ b/chromium/ui/views/win/pen_event_processor_unittest.cc
@@ -245,7 +245,7 @@ TEST(PenProcessorTest, PenEraserFlagDMEnabled) {
ASSERT_TRUE(event);
ASSERT_TRUE(event->IsTouchEvent());
EXPECT_EQ(ui::ET_TOUCH_PRESSED, event->AsTouchEvent()->type());
- EXPECT_EQ(ui::EventPointerType::POINTER_TYPE_ERASER,
+ EXPECT_EQ(ui::EventPointerType::kEraser,
event->AsTouchEvent()->pointer_details().pointer_type);
pen_info.pointerInfo.pointerFlags = POINTER_FLAG_UP;
@@ -255,7 +255,7 @@ TEST(PenProcessorTest, PenEraserFlagDMEnabled) {
ASSERT_TRUE(event);
ASSERT_TRUE(event->IsTouchEvent());
EXPECT_EQ(ui::ET_TOUCH_RELEASED, event->AsTouchEvent()->type());
- EXPECT_EQ(ui::EventPointerType::POINTER_TYPE_ERASER,
+ EXPECT_EQ(ui::EventPointerType::kEraser,
event->AsTouchEvent()->pointer_details().pointer_type);
}
diff --git a/chromium/ui/views/win/scoped_fullscreen_visibility.cc b/chromium/ui/views/win/scoped_fullscreen_visibility.cc
index e3103243c64..4c77b7e7ee8 100644
--- a/chromium/ui/views/win/scoped_fullscreen_visibility.cc
+++ b/chromium/ui/views/win/scoped_fullscreen_visibility.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/logging.h"
+#include "base/check.h"
namespace views {
diff --git a/chromium/ui/views/window/caption_button_layout_constants.cc b/chromium/ui/views/window/caption_button_layout_constants.cc
index a0738471c3f..3845999821f 100644
--- a/chromium/ui/views/window/caption_button_layout_constants.cc
+++ b/chromium/ui/views/window/caption_button_layout_constants.cc
@@ -4,7 +4,6 @@
#include "ui/views/window/caption_button_layout_constants.h"
-#include "base/logging.h"
#include "ui/base/pointer/touch_ui_controller.h"
#include "ui/gfx/geometry/size.h"
diff --git a/chromium/ui/views/window/client_view.cc b/chromium/ui/views/window/client_view.cc
index c1b7d081893..13562905b1a 100644
--- a/chromium/ui/views/window/client_view.cc
+++ b/chromium/ui/views/window/client_view.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/logging.h"
+#include "base/check.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/hit_test.h"
diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc
index 7c683a51ae9..64e7e523b45 100644
--- a/chromium/ui/views/window/dialog_client_view.cc
+++ b/chromium/ui/views/window/dialog_client_view.cc
@@ -266,10 +266,8 @@ void DialogClientView::UpdateDialogButton(LabelButton** member,
return;
}
- std::unique_ptr<LabelButton> button =
- is_default ? MdTextButton::CreateSecondaryUiBlueButton(this, title)
- : MdTextButton::CreateSecondaryUiButton(this, title);
-
+ auto button = MdTextButton::Create(this, title);
+ button->SetProminent(is_default);
button->SetIsDefault(is_default);
button->SetEnabled(delegate->IsDialogButtonEnabled(type));
@@ -352,13 +350,13 @@ void DialogClientView::SetupLayout() {
// into the layout. This simplifies min/max size calculations.
column_set->AddPaddingColumn(kFixed, button_row_insets_.left());
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(kStretchy, GetExtraViewSpacing());
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(kFixed, button_spacing);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
- GridLayout::USE_PREF, 0, 0);
+ GridLayout::ColumnSize::kUsePreferred, 0, 0);
column_set->AddPaddingColumn(kFixed, button_row_insets_.right());
// Track which columns to link sizes under MD.
diff --git a/chromium/ui/views/window/dialog_client_view_unittest.cc b/chromium/ui/views/window/dialog_client_view_unittest.cc
index 390eac20ccd..921d7e999f8 100644
--- a/chromium/ui/views/window/dialog_client_view_unittest.cc
+++ b/chromium/ui/views/window/dialog_client_view_unittest.cc
@@ -50,6 +50,9 @@ class DialogClientViewTest : public test::WidgetTest,
params.delegate = this;
widget_->Init(std::move(params));
EXPECT_EQ(this, GetContentsView());
+ layout_provider_ = std::make_unique<test::TestLayoutProvider>();
+ layout_provider_->SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH,
+ 200);
}
void TearDown() override {
@@ -90,6 +93,11 @@ class DialogClientViewTest : public test::WidgetTest,
DialogModelChanged();
}
+ void SetDialogButtonLabel(ui::DialogButton button, const std::string& label) {
+ DialogDelegate::SetButtonLabel(button, base::UTF8ToUTF16(label));
+ DialogModelChanged();
+ }
+
// Sets the view to provide to DisownExtraView() and updates the dialog. This
// can only be called a single time because DialogClientView caches the result
// of DisownExtraView() and never calls it again.
@@ -124,14 +132,34 @@ class DialogClientViewTest : public test::WidgetTest,
DialogModelChanged();
}
+ views::Button* GetButtonByAccessibleName(views::View* root,
+ const base::string16& name) {
+ views::Button* button = Button::AsButton(root);
+ if (button && button->GetAccessibleName() == name)
+ return button;
+ for (auto* child : root->children()) {
+ button = GetButtonByAccessibleName(child, name);
+ if (button)
+ return button;
+ }
+ return nullptr;
+ }
+
+ views::Button* GetButtonByAccessibleName(const std::string& label) {
+ return GetButtonByAccessibleName(widget_->GetRootView(),
+ base::UTF8ToUTF16(label));
+ }
+
DialogClientView* client_view() {
return static_cast<DialogClientView*>(widget_->client_view());
}
Widget* widget() { return widget_; }
+ test::TestLayoutProvider* layout_provider() { return layout_provider_.get(); }
private:
// The dialog Widget.
+ std::unique_ptr<test::TestLayoutProvider> layout_provider_;
Widget* widget_ = nullptr;
gfx::Size preferred_size_;
@@ -330,8 +358,6 @@ TEST_F(DialogClientViewTest, MinMaxPreferredSize) {
// Ensure button widths are linked under MD.
TEST_F(DialogClientViewTest, LinkedWidthDoesLink) {
- test::TestLayoutProvider layout_provider;
- layout_provider.SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 200);
SetLongCancelLabel();
// Ensure there is no default button since getting a bold font can throw off
@@ -361,13 +387,13 @@ TEST_F(DialogClientViewTest, LinkedWidthDoesLink) {
EXPECT_EQ(cancel_button_width, client_view()->ok_button()->width());
// But not when the size of the cancel button exceeds the max linkable width.
- layout_provider.SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 100);
+ layout_provider()->SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 100);
EXPECT_GT(cancel_button_width, 100);
DialogModelChanged();
CheckContentsIsSetToPreferredSize();
EXPECT_EQ(ok_button_only_width, client_view()->ok_button()->width());
- layout_provider.SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 200);
+ layout_provider()->SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 200);
// The extra view should also match, if it's a matching button type.
View* extra_button =
@@ -377,8 +403,6 @@ TEST_F(DialogClientViewTest, LinkedWidthDoesLink) {
}
TEST_F(DialogClientViewTest, LinkedWidthDoesntLink) {
- test::TestLayoutProvider layout_provider;
- layout_provider.SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 200);
SetLongCancelLabel();
// Ensure there is no default button since getting a bold font can throw off
@@ -408,13 +432,13 @@ TEST_F(DialogClientViewTest, LinkedWidthDoesntLink) {
EXPECT_EQ(cancel_button_width, client_view()->ok_button()->width());
// But not when the size of the cancel button exceeds the max linkable width.
- layout_provider.SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 100);
+ layout_provider()->SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 100);
EXPECT_GT(cancel_button_width, 100);
DialogModelChanged();
CheckContentsIsSetToPreferredSize();
EXPECT_EQ(ok_button_only_width, client_view()->ok_button()->width());
- layout_provider.SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 200);
+ layout_provider()->SetDistanceMetric(DISTANCE_BUTTON_MAX_LINKABLE_WIDTH, 200);
// Checkbox extends LabelButton, but it should not participate in linking.
View* extra_button =
@@ -542,4 +566,74 @@ TEST_F(DialogClientViewTest, IgnorePossiblyUnintendedClicks_RepeatedClicks) {
EXPECT_TRUE(widget()->IsClosed());
}
+TEST_F(DialogClientViewTest, ButtonLayoutWithExtra) {
+ // The dialog button row's layout should look like:
+ // | <inset> [extra] <flex-margin> [cancel] <margin> [ok] <inset> |
+ // Where:
+ // 1) The two insets are linkable
+ // 2) The ok & cancel buttons have their width linked
+ // 3) The extra button has its width linked to the other two
+ // 4) The margin should be invariant as the dialog changes width
+ // 5) The flex margin should change as the dialog changes width
+ //
+ // Note that cancel & ok may swap order depending on
+ // PlatformStyle::kIsOkButtonLeading; these invariants hold for either order.
+ SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL);
+ SetDialogButtonLabel(ui::DIALOG_BUTTON_OK, "ok");
+ SetDialogButtonLabel(ui::DIALOG_BUTTON_CANCEL, "cancel");
+ SetExtraView(
+ std::make_unique<LabelButton>(nullptr, base::UTF8ToUTF16("extra")));
+
+ widget()->Show();
+
+ Button* ok = GetButtonByAccessibleName("ok");
+ Button* cancel = GetButtonByAccessibleName("cancel");
+ Button* extra = GetButtonByAccessibleName("extra");
+
+ ASSERT_NE(ok, cancel);
+ ASSERT_NE(ok, extra);
+ ASSERT_NE(cancel, extra);
+
+ client_view()->SizeToPreferredSize();
+ client_view()->Layout();
+
+ auto bounds_left = [](View* v) { return v->GetBoundsInScreen().x(); };
+ auto bounds_right = [](View* v) { return v->GetBoundsInScreen().right(); };
+
+ // (1): left inset == right inset (and they shouldn't be 0):
+ int left_inset = bounds_left(extra) - bounds_left(this);
+ int right_inset =
+ bounds_right(this) - std::max(bounds_right(ok), bounds_right(cancel));
+ EXPECT_EQ(left_inset, right_inset);
+ EXPECT_GT(left_inset, 0);
+
+ // (2) & (3): All three buttons have their widths linked:
+ EXPECT_EQ(ok->width(), cancel->width());
+ EXPECT_EQ(ok->width(), extra->width());
+ EXPECT_GT(ok->width(), 0);
+
+ // (4): Margin between ok & cancel should be invariant as dialog width
+ // changes:
+ auto get_margin = [&]() {
+ return std::max(bounds_left(ok), bounds_left(cancel)) -
+ std::min(bounds_right(ok), bounds_right(cancel));
+ };
+
+ // (5): Flex margin between ok/cancel and extra should vary with dialog width
+ // (it should absorb 100% of the change in width)
+ auto get_flex_margin = [&]() {
+ return std::min(bounds_left(ok), bounds_left(cancel)) - bounds_right(extra);
+ };
+
+ int old_margin = get_margin();
+ int old_flex_margin = get_flex_margin();
+
+ SetSizeConstraints(gfx::Size(), gfx::Size(width() + 100, 0), gfx::Size());
+ client_view()->SizeToPreferredSize();
+ client_view()->Layout();
+
+ EXPECT_EQ(old_margin, get_margin());
+ EXPECT_EQ(old_flex_margin + 100, get_flex_margin());
+}
+
} // namespace views
diff --git a/chromium/ui/views/window/dialog_delegate.cc b/chromium/ui/views/window/dialog_delegate.cc
index 16ee3828e40..6afc661f5a2 100644
--- a/chromium/ui/views/window/dialog_delegate.cc
+++ b/chromium/ui/views/window/dialog_delegate.cc
@@ -12,6 +12,7 @@
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_role_properties.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_palette.h"
#include "ui/strings/grit/ui_strings.h"
@@ -42,6 +43,8 @@ DialogDelegate::Params::~Params() = default;
// DialogDelegate:
DialogDelegate::DialogDelegate() {
+ WidgetDelegate::RegisterWindowWillCloseCallback(
+ base::BindOnce(&DialogDelegate::WindowWillClose, base::Unretained(this)));
UMA_HISTOGRAM_BOOLEAN("Dialog.DialogDelegate.Create", true);
creation_time_ = base::TimeTicks::Now();
}
@@ -135,7 +138,7 @@ base::string16 DialogDelegate::GetDialogButtonLabel(
}
bool DialogDelegate::IsDialogButtonEnabled(ui::DialogButton button) const {
- return true;
+ return params_.enabled_buttons & button;
}
bool DialogDelegate::Cancel() {
@@ -324,16 +327,35 @@ void DialogDelegate::DialogModelChanged() {
}
void DialogDelegate::SetDefaultButton(int button) {
+ if (params_.default_button == button)
+ return;
params_.default_button = button;
+ DialogModelChanged();
}
void DialogDelegate::SetButtons(int buttons) {
+ if (params_.buttons == buttons)
+ return;
params_.buttons = buttons;
+ DialogModelChanged();
+}
+
+void DialogDelegate::SetButtonEnabled(ui::DialogButton button, bool enabled) {
+ if (!!(params_.enabled_buttons & button) == enabled)
+ return;
+ if (enabled)
+ params_.enabled_buttons |= button;
+ else
+ params_.enabled_buttons &= ~button;
+ DialogModelChanged();
}
void DialogDelegate::SetButtonLabel(ui::DialogButton button,
base::string16 label) {
+ if (params_.button_labels[button] == label)
+ return;
params_.button_labels[button] = label;
+ DialogModelChanged();
}
void DialogDelegate::SetAcceptCallback(base::OnceClosure callback) {
@@ -430,8 +452,7 @@ View* DialogDelegateView::GetContentsView() {
void DialogDelegateView::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
if (details.is_add && details.child == this && GetWidget() &&
- (GetAccessibleWindowRole() == ax::mojom::Role::kAlert ||
- GetAccessibleWindowRole() == ax::mojom::Role::kAlertDialog)) {
+ ui::IsAlert(GetAccessibleWindowRole())) {
NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
}
}
diff --git a/chromium/ui/views/window/dialog_delegate.h b/chromium/ui/views/window/dialog_delegate.h
index 54ea673bb33..04bc5b4cdce 100644
--- a/chromium/ui/views/window/dialog_delegate.h
+++ b/chromium/ui/views/window/dialog_delegate.h
@@ -59,6 +59,11 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
// Prefer to use this field (via SetButtonLabel) rather than override
// GetDialogButtonLabel - see https://crbug.com/1011446
base::string16 button_labels[ui::DIALOG_BUTTON_LAST + 1];
+
+ // A bitmask of buttons (from ui::DialogButton) that are enabled in this
+ // dialog. It's legal for a button to be marked enabled that isn't present
+ // in |buttons| (see above).
+ int enabled_buttons = ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
};
DialogDelegate();
@@ -130,7 +135,6 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
DialogDelegate* AsDialogDelegate() override;
ClientView* CreateClientView(Widget* widget) override;
NonClientFrameView* CreateNonClientFrameView(Widget* widget) override;
- void WindowWillClose() override;
static NonClientFrameView* CreateDialogFrameView(Widget* widget);
@@ -169,7 +173,11 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
void AddObserver(DialogObserver* observer);
void RemoveObserver(DialogObserver* observer);
- // Notifies observers when the result of the DialogModel overrides changes.
+ // Notifies DialogDelegate that the result of one of the virtual getter
+ // functions above has changed, which causes it to rebuild its layout. It is
+ // not necessary to call this unless you are overriding
+ // IsDialogButtonEnabled() or manually manipulating the dialog buttons.
+ // TODO(https://crbug.com/1011446): Make this private.
void DialogModelChanged();
void set_use_round_corners(bool round) { params_.round_corners = round; }
@@ -178,9 +186,12 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
void set_use_custom_frame(bool use) { params_.custom_frame = use; }
bool use_custom_frame() const { return params_.custom_frame; }
+ // These methods internally call DialogModelChanged() if needed, so it is not
+ // necessary to call DialogModelChanged() yourself after calling them.
void SetDefaultButton(int button);
void SetButtons(int buttons);
void SetButtonLabel(ui::DialogButton button, base::string16 label);
+ void SetButtonEnabled(ui::DialogButton button, bool enabled);
void SetAcceptCallback(base::OnceClosure callback);
void SetCancelCallback(base::OnceClosure callback);
void SetCloseCallback(base::OnceClosure callback);
@@ -243,6 +254,10 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
// dialogs use the same button row insets.
void SetButtonRowInsets(const gfx::Insets& insets);
+ // Callback for WidgetDelegate when the window this dialog is hosted in is
+ // closing. Don't call this yourself.
+ void WindowWillClose();
+
protected:
~DialogDelegate() override;
diff --git a/chromium/ui/views/window/dialog_delegate_unittest.cc b/chromium/ui/views/window/dialog_delegate_unittest.cc
index eeaf5cd23a8..6096431dc6b 100644
--- a/chromium/ui/views/window/dialog_delegate_unittest.cc
+++ b/chromium/ui/views/window/dialog_delegate_unittest.cc
@@ -427,6 +427,17 @@ TEST_F(DialogTest, UnfocusableInitialFocus) {
dialog_widget->CloseNow();
}
+TEST_F(DialogTest, ButtonEnableUpdatesState) {
+ test::WidgetTest::WidgetAutoclosePtr widget(
+ CreateDialogWidget(new DialogDelegateView));
+ auto* dialog = static_cast<DialogDelegateView*>(widget->widget_delegate());
+
+ EXPECT_TRUE(dialog->GetOkButton()->GetEnabled());
+ dialog->SetButtonEnabled(ui::DIALOG_BUTTON_OK, false);
+ dialog->DialogModelChanged();
+ EXPECT_FALSE(dialog->GetOkButton()->GetEnabled());
+}
+
using DialogDelegateCloseTest = ViewsTestBase;
TEST_F(DialogDelegateCloseTest, AnyCallbackInhibitsDefaultClose) {
diff --git a/chromium/ui/views/window/window_resize_utils.cc b/chromium/ui/views/window/window_resize_utils.cc
index 8ec1727320e..5578e3ac267 100644
--- a/chromium/ui/views/window/window_resize_utils.cc
+++ b/chromium/ui/views/window/window_resize_utils.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "base/check_op.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"